diff options
author | Ton Roosendaal <ton@blender.org> | 2006-01-24 01:05:47 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2006-01-24 01:05:47 +0300 |
commit | 042d612df219c8f6a29afa235537380f227b5684 (patch) | |
tree | 310a2c859b99c559115bbcda0aa70f2543bf962c /source/blender/render/intern | |
parent | 5668480c99001a617fd59a2383deb858195ffb26 (diff) |
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
Diffstat (limited to 'source/blender/render/intern')
46 files changed, 7144 insertions, 9880 deletions
diff --git a/source/blender/render/intern/include/RE_callbacks.h b/source/blender/render/intern/include/RE_callbacks.h deleted file mode 100644 index 159eaa84ca4..00000000000 --- a/source/blender/render/intern/include/RE_callbacks.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * $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 ***** - * Callbacks to make the renderer interact with calling modules. - */ - -#ifndef RE_CALLBACKS_H -#define RE_CALLBACKS_H - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * Test whether operation should be prematurely terminated. - * - * @returns 0 to continue, any other value to break. - */ - int RE_local_test_break(void); - - /** - * Set a red square with the argument as text as cursor. - */ - void RE_local_timecursor(int i); - - /** - * Render these lines from the renderbuffer on screen (needs better spec) - */ - void RE_local_render_display(int i, int j, int k, int l, unsigned int *m); - - /** - * Initialise a render display (needs better spec) - */ - void RE_local_init_render_display(void); - - /** - * Clear/close a render display (needs better spec) - */ - void RE_local_clear_render_display(short); - - /** - * Print render statistics. - */ - void RE_local_printrenderinfo(double time, int i); - - /** Get the data for the scene to render. */ - void RE_local_get_renderdata(void); - - /** Release the data for the scene that was rendered. */ - void RE_local_free_renderdata(void); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h index 7a44a139b20..32d72555ca4 100644 --- a/source/blender/render/intern/include/envmap.h +++ b/source/blender/render/intern/include/envmap.h @@ -41,10 +41,11 @@ * (initrender.c) */ +struct Render; struct TexResult; -void make_envmaps(void); -int envmaptex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres); +void make_envmaps(struct Render *re); +int envmaptex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres); #endif /* ENVMAP_EXT_H */ diff --git a/source/blender/render/intern/include/errorHandler.h b/source/blender/render/intern/include/errorHandler.h deleted file mode 100644 index fb980fa255a..00000000000 --- a/source/blender/render/intern/include/errorHandler.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * errorHandler.h - * - * $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 ***** - */ - -#ifndef ERRORHANDLER_H -#define ERRORHANDLER_H - -/* error codes */ -enum RE_RENDER_ERROR { - RE_NO_ERROR, - RE_DEPTH_MISMATCH, /* 1. conflict resolution detects a bad z value */ - RE_BAD_FACE_TYPE, /* 2. a face type switch fails */ - RE_BAD_FACE_INDEX, /* 3. tried to do an operation with a bad index */ - RE_BAD_DATA_POINTER, - RE_TRACE_COUNTER, - RE_TOO_MANY_FACES, /* 6. overflow on z-buffer depth */ - RE_EDGERENDER_WRITE_OUTSIDE_BUFFER, /* 7. write value outside buffer */ - RE_CANNOT_ALLOCATE_MEMORY, /* 8. no memory for malloc */ - RE_WRITE_OUTSIDE_COLOUR_BUFFER, /* 9. write outside colour target buffer */ - RE_MAX_ERROR -}; - -/** - * Reset all counters for the error trace - */ -void RE_errortrace_reset(void); - -/** - * Signals an error to screen. Counts repetitive errors - */ -void RE_error(int errType, char* fname); - -/** - * Signals an error, and prints an integer argument - */ -void RE_error_int(int errType, char* fname, int valye); - -#endif /* ERRORHANDLER_H */ - diff --git a/source/blender/render/intern/include/gammaCorrectionTables.h b/source/blender/render/intern/include/gammaCorrectionTables.h index 6197f769f6f..3d0928f84a3 100644 --- a/source/blender/render/intern/include/gammaCorrectionTables.h +++ b/source/blender/render/intern/include/gammaCorrectionTables.h @@ -35,26 +35,12 @@ #ifndef GAMMACORRECTIONTABLES_H #define GAMMACORRECTIONTABLES_H -/* Default gamma. For most CRTs, gamma ranges from 2.2 to 2.5 (Foley), so */ -/* 2.35 seems appropriate enough. Experience teaches a different number */ -/* though. Old blender: 2.0. It might be nice to make this a slider */ -#define RE_DEFAULT_GAMMA 2.0 -/* This 400 is sort of based on the number of intensity levels needed for */ -/* the typical dynamic range of a medium, in this case CRTs. (Foley) */ -/* (Actually, it says the number should be between 400 and 535.) */ -#define RE_GAMMA_TABLE_SIZE 400 - /** * Initialise the gamma lookup tables */ void makeGammaTables(float gamma); /** - * Returns true if the table is initialised, false otherwise - */ -int gammaTableIsInitialised(void); - -/** * Apply gamma correction on col */ float gammaCorrect(float col); @@ -64,10 +50,5 @@ float gammaCorrect(float col); */ float invGammaCorrect(float col); -/** - * Tell whether or not to do gamma. - */ -extern int do_gamma; - #endif diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h index 15ec3eb69a3..9a94d193990 100644 --- a/source/blender/render/intern/include/initrender.h +++ b/source/blender/render/intern/include/initrender.h @@ -32,19 +32,21 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#ifndef INITRENDER_EXT_H -#define INITRENDER_EXT_H +#ifndef INITRENDER_H +#define INITRENDER_H -/* type includes */ - -#include "DNA_effect_types.h" /* for PartEff type */ -#include "render_types.h" +struct Object; /* Functions */ -void schrijfplaatje(char *name); -void render(void); /* Switch between the old and the unified renderer. */ -/* void write_screendump(char *name); not here !*/ +void free_sample_tables(Render *re); +void make_sample_tables(Render *re); + +void render_scene_set_window(Render *re, struct Object *camera, int blursample); + +void initparts(Render *re); +void freeparts(Render *re); + -#endif /* INITRENDER_EXT_H */ +#endif /* INITRENDER_H */ diff --git a/source/blender/render/intern/include/jitter.h b/source/blender/render/intern/include/jitter.h deleted file mode 100644 index 696ded297b1..00000000000 --- a/source/blender/render/intern/include/jitter.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * jitter.h - * - * $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 ***** - */ - -#ifndef JITTER_H -#define JITTER_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern float jit[64][2]; - -extern void initjit(float *jitarr, int num); -extern void init_render_jit(int nr); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h index b82642a34d0..bc44c916701 100644 --- a/source/blender/render/intern/include/pixelblending.h +++ b/source/blender/render/intern/include/pixelblending.h @@ -1,18 +1,12 @@ /* - * pixelblending_ext.h - * external interface for pixelblending - * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,9 +20,7 @@ * 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. + * Contributor(s): 2004-2006 Blender Foundation, full recode * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -36,41 +28,12 @@ #ifndef PIXELBLENDING_EXT_H #define PIXELBLENDING_EXT_H -/* local includes */ -#include "vanillaRenderPipe_types.h" - -/** - * Halo-add pixel, bring your own R.osa setting, and add factor - */ -void addAddSampColF(float *s, float *d, int m, int osa, char add); - -/** - * Alpha undersamples pixel, bring your own R.osa setting - */ -int addUnderSampColF(float *sampcol, float *dest, int mask, int osaNr); - -/** - * Alpha oversample pixel, bring your own R.osa setting - */ -void addOverSampColF(float *sampcol, float *dest, int mask, int osaNr); /** * add 1 pixel to into filtered three lines * (float vecs to float vec) */ -void add_filt_fmask(unsigned int mask, float *col, float *rb1, float *rb2, float *rb3); - -/** - * Convert a series of oversampled pixels into filtered three lines - * (float vecs to float vec) - */ -void sampleFloatColV2FloatColVFilter(float *sample, float *dest1, float *dest2, float *dest3, int osaNr); - -/** - * Convert a series of oversampled pixels into a single pixel. Uses R.osa to - * count the length! (short vecs to short vec) - */ -void sampleShortColV2ShortColV(unsigned short *sample, unsigned short *dest, int osaNr); +void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w); /** * Alpha-over blending for floats. @@ -82,50 +45,6 @@ void addAlphaOverFloat(float *dest, float *source); */ void addAlphaUnderFloat(float *dest, float *source); -/** - * Write a 16-bit-colour colour vector to a 8-bit-colour colour vector. - */ -void cpShortColV2CharColV(unsigned short *source, char *dest); - -/** - * Write a 8-bit-colour colour vector to a 16-bit-colour colour vector. - */ -void cpCharColV2ShortColV(char *source, unsigned short *dest); - -/** - * Write a 32-bit-colour colour vector to a 8-bit-colour colour vector. - */ -void cpIntColV2CharColV(unsigned int *source, char *dest); - -/** - * Write a floating-point-colour colour vector to a 8-bit-colour colour - * vector. Clip colours to [0, 1]. - */ -void cpFloatColV2CharColV(float *source, char *dest); - -/** - * Cpoy a 8-bit-colour vector to floating point colour vector. - */ -void cpCharColV2FloatColV(char *source, float *dest); -/** - * Cpoy a 16-bit-colour vector to floating point colour vector. - */ -void cpShortColV2FloatColV(unsigned short *source, float *dest); - -/** - * Copy a float-colour colour vector. - */ -void cpFloatColV(float *source, float *dest); - -/** - * Copy a 16-bit-colour colour vector. - */ -void cpShortColV(unsigned short *source, unsigned short *dest); - -/** - * Copy an 8-bit-colour colour vector. - */ -void cpCharColV(char *source, char *dest); /** * Same for floats @@ -137,26 +56,20 @@ void addalphaAddfacFloat(float *dest, float *source, char addfac); */ void addalphaAddFloat(float *dest, float *source); -/** ols functions: side effects? -void addalphaUnderFloat(char *doel, char *bron); think this already exists... -void addalphaUnderGammaFloat(char *doel, char *bron); -*/ /** * Blend bron under doel, while doing gamma correction */ void addalphaUnderGammaFloat(float *doel, float *bron); /** - * Transform an premul-alpha 32-bit colour into a key-alpha 32-bit colour. +* Copy the colour buffer output to R.rectot, to line y. + */ +void transferColourBufferToOutput(float *buf, int y); +/** +* using default transforms for brightness, gamma, hue, saturation etc. */ -void applyKeyAlphaCharCol(char* target); +void std_floatcol_to_charcol(float *buf, char *target); -/* Old blending functions */ -void keyalpha(char *doel); /* maakt premul 255 */ -void addalphaUnder(char *doel, char *bron); -void addalphaUnderGamma(char *doel, char *bron); -void addalphaOver(char *doel, char *bron); -void addalphaAdd(char *doel, char *bron); #endif /* PIXELBLENDING_EXT_H */ diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h index a7a611ed117..67b0e5bcf3c 100644 --- a/source/blender/render/intern/include/pixelshading.h +++ b/source/blender/render/intern/include/pixelshading.h @@ -1,19 +1,12 @@ /* - * pixelshading.h - * - * These functions determine what actual colour a pixel will have. - * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,19 +20,20 @@ * 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. + * Contributor(s): 2004-2006, Blender Foundation, full recode * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ +/* pixelshading.h +* +* These functions determine what actual colour a pixel will have. +*/ + + #ifndef PIXELSHADING_H #define PIXELSHADING_H -#include "render.h" -#include "vanillaRenderPipe_types.h" - /** * Render the pixel at (x,y) for object ap. Apply the jitter mask. * Output is given in float collector[4]. The type vector: @@ -51,30 +45,18 @@ * mask is pixel coverage in bits * @return pointer to the object */ -void *renderPixel(RE_COLBUFTYPE *collector, float x, float y, int *t, int mask); - - -void setSkyBlendingMode(enum RE_SkyAlphaBlendingType mode); - void shadeHaloFloat(HaloRen *har, float *col, int zz, float dist, float xn, float yn, short flarec); /** - * Get the sky blending mode. - */ -enum RE_SkyAlphaBlendingType getSkyBlendingMode(void); -/** * Render the sky at pixel (x, y). */ -void renderSkyPixelFloat(RE_COLBUFTYPE *collector, float x, float y, float *rco); -void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco); +void renderSkyPixelFloat(float *collector, float x, float y, float *rco); +void shadeSkyPixel(float *collector, float fx, float fy, float *rco); void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview); -void renderSpotHaloPixel(float x, float y, float *target); -void fillBackgroundImageChar(char *col, float x, float y); - /* ------------------------------------------------------------------------- */ #endif diff --git a/source/blender/render/intern/include/renderHelp.h b/source/blender/render/intern/include/renderHelp.h deleted file mode 100644 index 318b538d510..00000000000 --- a/source/blender/render/intern/include/renderHelp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * renderhelp_ext.h - * - * $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 ***** - */ - -#ifndef RENDERHELP_EXT_H -#define RENDERHELP_EXT_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* Push-pop, because this sometimes is necessary... */ - void pushTempPanoPhi(float p); - void popTempPanoPhi(void); - - float getPanoPhi(void); - float getPanovCo(void); - float getPanovSi(void); - void setPanoRot(int part); - - /** Set clip flags on all data entries, using the given projection - * function */ - void setzbufvlaggen( void (*projectfunc)(float *, float *) ); - -/* external for the time being, since the converter calls it. */ -/** Recalculate all normals on renderdata. */ -/* void set_normalflags(void); */ - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/source/blender/render/intern/include/renderPreAndPost.h b/source/blender/render/intern/include/renderPreAndPost.h deleted file mode 100644 index 59315868010..00000000000 --- a/source/blender/render/intern/include/renderPreAndPost.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * renderpreandpost.h - * - * $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 ***** - */ - -#ifndef RENDERPREANDPOST_H -#define RENDERPREANDPOST_H - -void prepareScene(void); -void finalizeScene(void); -void doClipping( void (*projectfunc)(float *, float *) ); - -#endif - diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h new file mode 100644 index 00000000000..c73deca6d22 --- /dev/null +++ b/source/blender/render/intern/include/render_types.h @@ -0,0 +1,347 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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. + * + * Contributor(s): (c) 2006 Blender Foundation, full refactor + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef RENDER_TYPES_H +#define RENDER_TYPES_H + +/* ------------------------------------------------------------------------- */ +/* exposed internal in render module only! */ +/* ------------------------------------------------------------------------- */ + +#include "DNA_scene_types.h" +#include "DNA_world_types.h" +#include "DNA_object_types.h" +#include "DNA_vec_types.h" + +#include "RE_pipeline.h" +#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */ + +struct MemArena; +struct VertTableNode; +struct Octree; +struct GHash; + +#define TABLEINITSIZE 1024 +#define LAMPINITSIZE 256 + +typedef struct SampleTables +{ + float centLut[16]; + float *fmask1[9], *fmask2[9]; + char cmask[256], *centmask; + +} SampleTables; + +/* this is handed over to threaded hiding/passes/shading engine */ +typedef struct RenderPart +{ + struct RenderPart *next, *prev; + + /* result of part rendering */ + RenderResult *result; + + unsigned int *rectp; /* polygon index table */ + int *rectz; /* zbuffer */ + long *rectdaps; /* delta acum buffer for pixel structs */ + + rcti disprect; /* part coordinates within total picture */ + int rectx, recty; /* the size */ + short crop, ready; /* crop is amount of pixels we crop, for filter */ + short sample, nr; /* sample can be used by zbuffers, nr is partnr */ + short thread; /* thread id */ + +} RenderPart; + +typedef struct Octree { + struct Branch **adrbranch; + struct Node **adrnode; + float ocsize; /* ocsize: mult factor, max size octree */ + float ocfacx,ocfacy,ocfacz; + float min[3], max[3]; + int ocres; + int branchcount, nodecount; +} Octree; + + +/* controls state of render, everything that's read-only during render stage */ +struct Render +{ + struct Render *next, *prev; + char name[RE_MAXNAME]; + + /* state settings */ + short flag, osa, ok, do_gamma; + + /* result of rendering */ + RenderResult *result; + + /* window size, display rect, viewplane */ + int winx, winy; + rcti disprect; /* part within winx winy */ + rctf viewplane; /* mapped on winx winy */ + float viewdx, viewdy; /* size of 1 pixel */ + + /* final picture width and height (within disprect) */ + int rectx, recty; + + /* correction values for pixels or view */ + float ycor, viewfac; + float bluroffsx, bluroffsy; + float panosi, panoco; + + /* Matrices */ + float grvec[3]; /* for world */ + float imat[3][3]; /* copy of viewinv */ + float viewmat[4][4], viewinv[4][4]; + float winmat[4][4]; + + /* clippping */ + float clipsta; + float clipend; + + /* samples */ + SampleTables *samples; + float jit[32][2]; + + /* scene, and its full copy of renderdata and world */ + Scene *scene; + RenderData r; + World wrld; + + ListBase parts; + + /* octree tables and variables for raytrace */ + Octree oc; + + /* use this instead of R.r.cfra */ + float cfra; + + /* render database */ + int totvlak, totvert, tothalo, totlamp; + ListBase lights; + + int vertnodeslen; + struct VertTableNode *vertnodes; + int blohalen; + struct HaloRen **bloha; + int blovllen; + struct VlakRen **blovl; + + struct GHash *orco_hash; + + /* arena for allocating data for use during render, for + * example dynamic TFaces to go in the VlakRen structure. + */ + struct MemArena *memArena; + + /* callbacks */ + void (*display_init)(RenderResult *rr); + void (*display_clear)(RenderResult *rr); + void (*display_draw)(RenderResult *rr, rcti *rect); + + void (*stats_draw)(RenderStats *ri); + void (*timecursor)(int i); + + int (*test_break)(void); + int (*test_return)(void); + void (*error)(const char *str); + + RenderStats i; +}; + +/* ------------------------------------------------------------------------- */ + + +typedef struct ShadBuf { + short samp, shadhalostep; + float persmat[4][4]; + float viewmat[4][4]; + float winmat[4][4]; + float *jit; + float d,clipend,pixsize,soft; + int co[3]; + int size,bias; + long *zbuf; + char *cbuf; +} ShadBuf; + +/* ------------------------------------------------------------------------- */ + +typedef struct VertRen +{ + float co[3]; + float n[3]; + float ho[4]; + float *orco; + short clip; + unsigned short flag; /* in use for clipping zbuffer parts, temp setting stuff in convertblender.c */ + float accum; /* accum for radio weighting, and for strand texco static particles */ + int index; /* index allows extending vertren with any property */ +} VertRen; + +/* ------------------------------------------------------------------------- */ + +struct halosort { + struct HaloRen *har; + int z; +}; + +/* ------------------------------------------------------------------------- */ +struct Material; +struct TFace; + +typedef struct RadFace { + float unshot[3], totrad[3]; + float norm[3], cent[3], area; + int flag; +} RadFace; + +typedef struct VlakRen +{ + struct VertRen *v1, *v2, *v3, *v4; + unsigned int lay; + float n[3]; + struct Material *mat; + struct TFace *tface; + unsigned int *vcol; + char snproj, puno; + char flag, ec; + RadFace *radface; + Object *ob; +} VlakRen; + +typedef struct HaloRen +{ + short miny, maxy; + float alfa, xs, ys, rad, radsq, sin, cos, co[3], no[3]; + float hard, b, g, r; + int zs, zd; + int zBufDist; /* depth in the z-buffer coordinate system */ + char starpoints, type, add, tex; + char linec, ringc, seed; + short flarec; /* used to be a char. why ?*/ + float hasize; + int pixels; + unsigned int lay; + struct Material *mat; +} HaloRen; + +struct LampRen; +struct MTex; + +/** + * For each lamp in a scene, a LampRen is created. It determines the + * properties of a lightsource. + */ +typedef struct LampRen +{ + float xs, ys, dist; + float co[3]; + short type, mode; + float r, g, b, k; + float energy, haint; + int lay; + float spotsi,spotbl; + float vec[3]; + float xsp, ysp, distkw, inpr; + float halokw, halo; + float ld1,ld2; + + /* copied from Lamp, to decouple more rendering stuff */ + /** Size of the shadowbuffer */ + short bufsize; + /** Number of samples for the shadows */ + short samp; + /** Softness factor for shadow */ + float soft; + /** shadow plus halo: detail level */ + short shadhalostep; + /** Near clip of the lamp */ + float clipsta; + /** Far clip of the lamp */ + float clipend; + /** A small depth offset to prevent self-shadowing. */ + float bias; + + short ray_samp, ray_sampy, ray_sampz, ray_samp_type, area_shape, ray_totsamp; + short xold1, yold1, xold2, yold2; /* last jitter table for area lights */ + float area_size, area_sizey, area_sizez; + + struct ShadBuf *shb; + float *jitter; + + float imat[3][3]; + float spottexfac; + float sh_invcampos[3], sh_zfac; /* sh_= spothalo */ + + float mat[3][3]; /* 3x3 part from lampmat x viewmat */ + float area[8][3], areasize; + + /* yafray: photonlight params */ + int YF_numphotons, YF_numsearch; + short YF_phdepth, YF_useqmc, YF_bufsize; + float YF_causticblur, YF_ltradius; + float YF_glowint, YF_glowofs; + short YF_glowtype; + + /* ray optim */ + VlakRen *vlr_last; + + struct MTex *mtex[MAX_MTEX]; +} LampRen; + +/* **************** defines ********************* */ + +/* mode flag is same as for renderdata */ +/* flag */ +#define R_ZTRA 1 +#define R_HALO 2 +#define R_SEC_FIELD 4 +#define R_LAMPHALO 8 +#define R_RENDERING 16 +#define R_ANIMRENDER 32 +#define R_REDRAW_PRV 64 + +/* vlakren->flag (vlak = face in dutch) char!!! */ +#define R_SMOOTH 1 +#define R_VISIBLE 2 +/* strand flag, means special handling */ +#define R_STRAND 4 +#define R_NOPUNOFLIP 8 +#define R_FULL_OSA 16 +#define R_FACE_SPLIT 32 +/* Tells render to divide face other way. */ +#define R_DIVIDE_24 64 +/* vertex normals are tangent or view-corrected vector, for hair strands */ +#define R_TANGENT 128 + + + + + +#endif /* RENDER_TYPES_H */ + diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 8f236c502f4..cfdf34c205b 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -46,6 +46,8 @@ struct HaloRen; struct ShadeInput; +/* ------------------------------------------------------------------------- */ + typedef struct PixStr { struct PixStr *next; @@ -53,14 +55,15 @@ typedef struct PixStr unsigned short mask, amount; } PixStr; -/* ------------------------------------------------------------------------- */ - typedef struct PixStrMain { + struct PixStrMain *next, *prev; struct PixStr *ps; - struct PixStrMain *next; + int counter; } PixStrMain; +/* ------------------------------------------------------------------------- */ + void calc_view_vector(float *view, float x, float y); float mistfactor(float zcor, float *co); /* dist and height, return alpha */ @@ -74,34 +77,30 @@ void shade_lamp_loop(struct ShadeInput *shi, ShadeResult *shr); float fresnel_fac(float *view, float *vn, float fresnel, float fac); void calc_R_ref(struct ShadeInput *shi); -float spec(float inp, int hard); -/* -------- ray.c ------- */ +/* for nodes */ +void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); -extern void ray_shadow(ShadeInput *, LampRen *, float *); -extern void ray_trace(ShadeInput *, ShadeResult *); -extern void ray_ao(ShadeInput *, World *, float *); - -/** - * Do z buffer and shade - */ void zbufshade(void); - -/** - * zbuffer and shade, anti aliased - */ void zbufshadeDA(void); /* Delta Accum Pixel Struct */ -/** - * Also called in: zbuf.c - */ -void *shadepixel(float x, float y, int z, int facenr, int mask, float *col, float *rco); +void *shadepixel(RenderPart *pa, float x, float y, int z, int facenr, int mask, float *col, float *rco); -/** - * A cryptic but very efficient way of counting the number of bits that - * is set in the unsigned short. - */ int count_mask(unsigned short mask); +void zbufshade_tile(struct RenderPart *pa); +void zbufshadeDA_tile(struct RenderPart *pa); + +/* -------- ray.c ------- */ + +extern void freeoctree(Render *re); +extern void makeoctree(Render *re); + +extern void ray_shadow(ShadeInput *, LampRen *, float *); +extern void ray_trace(ShadeInput *, ShadeResult *); +extern void ray_ao(ShadeInput *, float *); +extern void init_jitter_plane(LampRen *lar); +extern void init_ao_sphere(float *sphere, int tot, int iter); + #endif /* RENDER_EXT_H */ diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h new file mode 100644 index 00000000000..6996bca7a5c --- /dev/null +++ b/source/blender/render/intern/include/renderdatabase.h @@ -0,0 +1,69 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef RENDERDATABASE_H +#define RENDERDATABASE_H + +struct VlakRen; +struct VertRen; +struct HaloRen; +struct Material; +struct Render; + +/* renderdatabase.c */ +void free_renderdata_tables(struct Render *re); +void set_normalflags(Render *re); +void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int part); + +/* functions are not exported... so wrong names */ + +struct VlakRen *RE_findOrAddVlak(struct Render *re, int nr); +struct VertRen *RE_findOrAddVert(struct Render *re, int nr); +struct HaloRen *RE_findOrAddHalo(struct Render *re, int nr); +struct HaloRen *RE_inithalo(struct Render *re, struct Material *ma, float *vec, float *vec1, float *orco, float hasize, + float vectsize, int seed); + +float *RE_vertren_get_sticky(struct Render *re, struct VertRen *ver, int verify); +float *RE_vertren_get_stress(struct Render *re, struct VertRen *ver, int verify); +float *RE_vertren_get_rad(struct Render *re, struct VertRen *ver, int verify); +float *RE_vertren_get_strand(struct Render *re, struct VertRen *ver, int verify); +float *RE_vertren_get_tangent(struct Render *re, struct VertRen *ver, int verify); + +/* haloren->type: flags */ +#define HA_ONLYSKY 1 +#define HA_VECT 2 +#define HA_XALPHA 4 +#define HA_FLARECIRC 8 + + +void init_render_world(Render *re); + + +#endif /* RENDERDATABASE_H */ + diff --git a/source/blender/render/intern/include/outerRenderLoop.h b/source/blender/render/intern/include/renderpipeline.h index 1c0faf666ae..5ccb2f318dc 100644 --- a/source/blender/render/intern/include/outerRenderLoop.h +++ b/source/blender/render/intern/include/renderpipeline.h @@ -1,17 +1,12 @@ -/* - * outerRenderLoop.h - * +/** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,23 +17,25 @@ * 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. + * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef OUTERRENDERLOOP_H -#define OUTERRENDERLOOP_H +#ifndef PIPELINE_H +#define PIPELINE_H + +struct Render; + +void *RE_mallocN(int len, char *name); +void *RE_callocN(int len, char *name); +void RE_freeN(void *poin); -/** - * Outer loop for rendering a single picture. - */ -void unifiedRenderingLoop(void); -#endif +#endif /* PIPELINE_H */ diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h index 279d5319b21..16127537975 100644 --- a/source/blender/render/intern/include/shadbuf.h +++ b/source/blender/render/intern/include/shadbuf.h @@ -41,7 +41,7 @@ * Calculates shadowbuffers for a vector of shadow-giving lamps * @param lar The vector of lamps */ -void makeshadowbuf(LampRen *lar); +void makeshadowbuf(struct Render *re, LampRen *lar); /** * Determines the shadow factor for a face and lamp. There is some diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index 4b7ac102d80..9eb4f16a60d 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -56,6 +56,11 @@ struct Image; void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf); void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend); +void do_material_tex(struct ShadeInput *shi); +void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf); + +void init_render_textures(void); + void render_realtime_texture(struct ShadeInput *shi); /* imagetexture.h */ diff --git a/source/blender/render/intern/include/vanillaRenderPipe.h b/source/blender/render/intern/include/vanillaRenderPipe.h deleted file mode 100644 index f242b8522fc..00000000000 --- a/source/blender/render/intern/include/vanillaRenderPipe.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * vanillaRenderPipe_ext.h - * - * $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 ***** - */ - -#ifndef VANILLARENDERPIPE_EXT_H -#define VANILLARENDERPIPE_EXT_H - -#include "vanillaRenderPipe_types.h" - -/** - * Render pipeline with all kinds of extras. - * status-------------------------\/ - * - integrated z buffering ok - * - integrated halo rendering ok - */ -void zBufShadeAdvanced(void); - -/** - * Copy the colour buffer output to R.rectot, to line y. - */ -void transferColourBufferToOutput(float *buf, int y); -/** - * using default transforms for brightness, gamma, hue, saturation etc. - */ -void std_floatcol_to_charcol(float *buf, char *target); - - -#endif /* VANILLARENDERPIPE_EXT_H */ - diff --git a/source/blender/render/intern/include/vanillaRenderPipe_types.h b/source/blender/render/intern/include/vanillaRenderPipe_types.h deleted file mode 100644 index df24ed01f5e..00000000000 --- a/source/blender/render/intern/include/vanillaRenderPipe_types.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * vanillaRenderPipe_types.h - * - * $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 ***** - */ - -#ifndef VANILLARENDERPIPE_TYPES_H -#define VANILLARENDERPIPE_TYPES_H - -/* Render defines */ -#define RE_MAX_OSA_COUNT 16 /* The max. number of possible oversamples */ -#define RE_MAX_FACES_PER_PIXEL 1000 /* max. nr of faces rendered behind one */ - /* pixel */ - -enum RE_SkyAlphaBlendingType { - RE_ALPHA_NODEF = 0, - RE_ALPHA_PREMUL, - RE_ALPHA_KEY, - RE_ALPHA_SKY, - RE_ALPHA_MAX -}; - - -/* Render typedefs */ -typedef float RE_COLBUFTYPE; /* datatype for the colour buffer */ - - -/** - * Threshold for add-blending for faces - */ -#define RE_FACE_ADD_THRESHOLD 0.001 - -/** - For oversampling - - New stack: the old stack limits our freedom to do all kinds of - manipulation, so we rewrite it. - - A stacked face needs: - - a face type - - a colour - - a conflict count - - a data pointer (void*) - - a mask - - The stack starts at index 0, with the closest face, and stacks up. - -*/ - -struct RE_faceField { - int faceType; - float colour[4]; - int conflictCount; - void *data; - int mask; -}; - -#endif /* VANILLARENDERPIPE_TYPES_H */ - diff --git a/source/blender/render/intern/include/zblur.h b/source/blender/render/intern/include/zblur.h deleted file mode 100644 index a0e1c6a39ce..00000000000 --- a/source/blender/render/intern/include/zblur.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * $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. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** - */ - -#ifndef ZBLUR_H -#define ZBLUR_H - -#ifdef __cplusplus -extern "C" { -#endif - -/*-----------------------------------------------------------*/ -/* Includes */ -/*-----------------------------------------------------------*/ - -/*-----------------------------------------------------------*/ -/* Function */ -/*-----------------------------------------------------------*/ - -void add_zblur(void); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index 394e38be47e..7a6c78d5728 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -1,18 +1,12 @@ /* - * zbuf_ext.h - * external interface for zbuf.h - * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +20,7 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Full recode: 2004-2006 Blender Foundation * * Contributor(s): none yet. * @@ -36,158 +30,66 @@ #ifndef ZBUF_H #define ZBUF_H -#ifdef __cplusplus -extern "C" { -#endif - +struct RenderPart; struct LampRen; struct VlakRen; +struct ListBase; -/*-----------------------------------------------------------*/ -/* Includes */ -/*-----------------------------------------------------------*/ - -#include "zbuf_types.h" -#include "render_types.h" -#include "radio_types.h" /* for RadView */ - -/*-----------------------------------------------------------*/ -/* Function */ -/* (11 so far ) */ -/*-----------------------------------------------------------*/ - -/** - * Fill a 'rectangle' with a fixed value. The rectangle contains x by - * y points. The rows are assumed to be contiguous in memory, and to - * consist of uints. This function is used for initializing the z - * buffer. - * (why is x int and y uint? called in envmap, render, zbuf) - * @param rect Pointer to the data representing the rectangle. - * @param x The width of the rectangle - * @param y The height of the rectangle - * @param val The value used to fill the rectangle. - */ void fillrect(int *rect, int x, int y, int val); /** * Converts a world coordinate into a homogenous coordinate in view - * coordinates. The transformation matrix is only allowed to have a - * scaling and translation component. - * Also called in: shadbuf.c render.c radfactors.c - * initrender.c envmap.c editmesh.c - * @param v1 [3 floats] the world coordinate - * @param adr [4 floats] the homogenous view coordinate - */ -void projectvert(float *v1,float *adr); - - -/** - * Do a z buffer calculation pass for shadow calculations. - * Also called in: shadbuf.c - * Note: Uses globals. - * @param lar lamp definition data - */ -void zbuffershad(struct LampRen *lar); - - /* to the external interface, temp, I hope... */ -/** - * Tests whether the first three coordinates should be clipped - * wrt. the fourth component. Bits 1 and 2 test on x, 3 and 4 test on - * y, 5 and 6 test on z: - * xyz > test => set first bit (01), - * xyz < -test => set second bit (10), - * xyz == test => reset both bits (00). - * Note: functionality is duplicated from an internal function - * Also called in: initrender.c, radfactors.c - * @param v [4 floats] a coordinate - * @return a vector of bitfields - */ -/* int testclip(float *v); */ - - -/* The following are only used in zbuf.c and render.c ---------------*/ -/** - * Fills the entire in the alpha DA buffer. (All of it!) - * Note: Uses globals. - * Also called in: render.c - * @param y the line number to set - */ -void abufsetrow(float *acolrow, int y); - - -/** - * Calculate the z buffer for all faces (or edges when in wireframe - * mode) presently visible. - * Note: Uses globals. - * Also called in: render.c + * coordinates. */ -void zbufferall(void); - - -/** - * Initialize accumulation buffers for alpha z buffering. - * The buffers are global variables. Also resets Accu buffer - * y bounds. - * <LI> - * <IT> Acolrow : colour buffer for one line - * <IT> Arectz : distance buffer for one line, depth ABUFPART - * <IT> APixbuf : pixel data buffer for one line, depth ABUFPART - * </LI> - * Also called in: render.c (should migrate) - * Note: Uses globals. - */ -void bgnaccumbuf(void); - -/** - * Discard accumulation buffers for alpha z buffering. - * The buffers are global variables. The released buffers are Acolrow, - * Arectz, APixBuf. - * Also called in: render.c (should migrate) - * Note: Uses globals. - */ -void endaccumbuf(void); - -/** - * Z face intersect? - */ -int vergzvlak(const void *x1, const void *x2); - -/** - * Clip and fill vertex into the z buffer. zbuffunc needs to be set - * before entering, to assure that there is a buffer fill function - * that can be called. Zvlnr must be set to the current valid face - * index . - * Note: uses globals - * @param f1 [4 floats] vertex 1 - * @param f2 [4 floats] vertex 2 - * @param f3 [4 floats] vertex 3 - * @param c1 clip conditions? - * @param c2 - * @param c3 - */ - -/* span fill in method */ +void projectvert(float *v1, float winmat[][4], float *adr); +void projectverto(float *v1, float winmat[][4], float *adr); +int testclip(float *v); + +void set_part_zbuf_clipflag(struct RenderPart *pa); +void zbuffer_shadow(struct Render *re, struct LampRen *lar, int *rectz, int size); +void zbuffer_solid(struct RenderPart *pa); +void zbuffer_transp_shade(struct RenderPart *pa, float *pass); + +typedef struct APixstr { + unsigned short mask[4]; /* jitter mask */ + int z[4]; /* distance */ + int p[4]; /* index */ + struct APixstr *next; +} APixstr; + +typedef struct APixstrMain +{ + struct APixstrMain *next, *prev; + struct APixstr *ps; +} APixstrMain; + +/* span fill in method, is also used to localize data for zbuffering */ typedef struct ZSpan { - int yres, miny, maxy; /* range for clipping */ + int rectx, recty; /* range for clipping */ + int miny1, maxy1, miny2, maxy2; /* actual filled in range */ float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */ float *span1, *span2; + + float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */ + + int *rectz, *arectz; /* zbuffers, arectz is for transparant */ + int *rectp; /* polygon index buffer */ + APixstr *apixbuf, *curpstr; /* apixbuf for transparent */ + struct ListBase *apsmbase; + + int polygon_offset; /* offset in Z */ + int mask, apsmcounter; /* in use by apixbuf */ + + void (*zbuffunc)(struct ZSpan *, int, float *, float *, float *, float *); + void (*zbuflinefunc)(struct ZSpan *, int, float *, float *); + } ZSpan; -void zbufclip(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3); - -/* These function pointers are used for z buffer filling. */ -extern void (*zbuffunc)(struct ZSpan *zspan, int, float *, float *, float *); -extern void (*zbuflinefunc)(int, float *, float *); - -/** - * same, for edges - */ -void zbufclipwire(int zvlnr, struct VlakRen *vlr); - -#ifdef __cplusplus -} -#endif +/* exported for evil edge render... */ +void zbufclip(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3); +void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty); +void zbufclipwire(ZSpan *zspan, int zvlnr, struct VlakRen *vlr); #endif diff --git a/source/blender/render/intern/include/zbuf_types.h b/source/blender/render/intern/include/zbuf_types.h deleted file mode 100644 index b5ad9c75902..00000000000 --- a/source/blender/render/intern/include/zbuf_types.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * zbuf_types.h - * type definitions used (and maybe exported) by zbuf.c. - * - * $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 ***** - */ - -#ifndef ZBUF_TYPES_H -#define ZBUF_TYPES_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define ABUFPART 64 - -/** - * Primitive data structure for zbuffering. One struct - * stores data for 4 entries. - */ -typedef struct APixstr { - unsigned short mask[4]; /* jitter mask */ - int z[4]; /* distance */ - int p[4]; /* index */ - struct APixstr *next; -} APixstr; - - -typedef struct APixstrMain -{ - struct APixstr *ps; - struct APixstrMain *next; -} APixstrMain; - - -typedef struct { - float *vert; - float hoco[4]; - int clip; -} VertBucket; - -#ifdef __cplusplus -} -#endif - -#endif /* ZBUF_TYPES_H */ - diff --git a/source/blender/render/intern/include/zbufferdatastruct.h b/source/blender/render/intern/include/zbufferdatastruct.h deleted file mode 100644 index 2cef53dc9f6..00000000000 --- a/source/blender/render/intern/include/zbufferdatastruct.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * zbufferdatastruct_ext.h - * - * $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 ***** - */ - -#ifndef ZBUFFERDATASTRUCT_EXT_H -#define ZBUFFERDATASTRUCT_EXT_H - -#include "zbufferdatastruct_types.h" - -/** - * Set memory and counters for a fresh z buffer - */ -void initZbuffer(int linewidth); - -/** - * Release memory for the current z buffer - */ -void freeZbuffer(void); - -/** - * Release previous buffer and initialise new buffer. - */ -void resetZbuffer(void); - -/** - * Make a root for a memory block (internal) - */ -RE_APixstrExt *addpsemainA(void); - -/** - * Release a memory chunk - */ -void freepseA(void); - -/** - * Add a structure - */ -RE_APixstrExt *addpseA(void); - -/** - * Add an object to a zbuffer entry. - */ -void insertObject(int teller, - int obindex, - int obtype, - int dist, - int mask); - -/** - * Add a flat object to a zbuffer entry. - */ -void insertFlatObject(RE_APixstrExt* ap, - int obindex, - int obtype, - int dist, - int mask); - -/** - * Add a flat object to a zbuffer entry, but don't do OSA entry testing. - */ -void insertFlatObjectNoOsa(RE_APixstrExt* ap, - int obindex, - int obtype, - int dist, - int mask); - -#endif - diff --git a/source/blender/render/intern/include/zbufferdatastruct_types.h b/source/blender/render/intern/include/zbufferdatastruct_types.h deleted file mode 100644 index 5048adfa8bc..00000000000 --- a/source/blender/render/intern/include/zbufferdatastruct_types.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * zbufferdatastruct_types.h - * - * $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 ***** - */ - -#ifndef ZBUFFERDATASTRUCT_TYPES_H -#define ZBUFFERDATASTRUCT_TYPES_H - -#define RE_ZBUFLEN 64 /* number of lines in the accumulation buffer */ - -/** - * Primitive data structure for zbuffering. One struct - * stores data for 4 entries. This struct has been extended - * for the render pipeline overhaul. - */ -typedef struct RE_APixstrExt { - unsigned short mask[4]; /* jitter masks */ - int zmin[4]; /* min. distance of all samples */ - int zmax[4]; /* max. distance of all samples */ - int p[4]; /* index */ - int t[4]; /* entry type: ZB_POLY or ZB_HALO */ - struct RE_APixstrExt *next; -} RE_APixstrExt; - -/* For now I'll stick to the Blender convention of hand made defines */ -/* but this should definitely be done in a better way. An enum may */ -/* be some help, but masking is still a nice feature... */ -/* object types to buffer in the z buffer */ -/* RE_SOLID is flag for RE_POLY, as speedup */ -#define RE_NONE 0 -#define RE_POLY 1 -#define RE_HALO 2 -#define RE_SKY 4 -#define RE_SOLID 8 - -/* unique indices for each field */ -#define RE_ZMIN 0 -#define RE_INDEX 1 -#define RE_MASK 2 -#define RE_TYPE 3 -#define RE_ZMAX 4 -#define RE_PIXELFIELDSIZE 5 - -typedef struct RE_APixstrExtMain -{ - struct RE_APixstrExt *ps; - struct RE_APixstrExtMain *next; -} RE_APixstrExtMain; - -#endif - diff --git a/source/blender/render/intern/source/RE_callbacks.c b/source/blender/render/intern/source/RE_callbacks.c deleted file mode 100644 index acc115b2b87..00000000000 --- a/source/blender/render/intern/source/RE_callbacks.c +++ /dev/null @@ -1,168 +0,0 @@ -/** - * $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 ***** - * Callbacks to make the renderer interact with calling modules. - */ - -#include <stdlib.h> /* for NULL??? */ -#include <stdio.h> -#include "render.h" -#include "RE_callbacks.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/* - * The callbacks are done in three parts: - * - * - a local static pointer to the eventual function. NULL if not - * defined, or if the behaviour is not required. - * - * - a hook that can be called locally - * - * - a hook that can be called externally, to set an external function - * to provide said functionality. - * - * These might be generated from a spec such as: - * - * callback { - * local = <local name> - * external = <external name> - * type = <ret_type> (<args>,...) - * } - * - * Should generate: - * - a static var - * - an internal loop, plus decl. - * - an external setter, plus decl. - * - */ - -/* Part 1: ------------------------------------------------------------- */ - -static int (*RE_local_test_break_function)(void) = NULL; - -static void (*RE_local_timecursor_function)(int) = NULL; - -static void (*RE_local_renderdisplay_function)(int i, - int j, - int k, - int l, - unsigned int *m) - = NULL; - -static void (*RE_local_initrenderdisplay_function)(void) = NULL; -static void (*RE_local_clearrenderdisplay_function)(short) = NULL; - -static void (*RE_local_printrenderinfo_function)(double,int) = NULL; - -static void (*RE_local_getrenderdata_function)(void) = NULL; -static void (*RE_local_freerenderdata_function)(void) = NULL; - -/* Part 2: ------------------------------------------------------------- */ - -int RE_local_test_break(void) { - if (RE_local_test_break_function) { - return RE_local_test_break_function(); - } else { - /* transparant behaviour: proceed */ - return 0; - } -} - -void RE_local_timecursor(int i) { - if (RE_local_timecursor_function) RE_local_timecursor_function(i); -} - -void RE_local_render_display(int i, int j, int k, int l, unsigned int* m) { - if (RE_local_renderdisplay_function) RE_local_renderdisplay_function(i, j, k, l, m); - else { - if(j-i >= l-1) printf("\n");// full picture - else printf("\rRender %d%% ", (100*i)/l); - fflush(stdout); - } -} -void RE_local_init_render_display(void) { - if (RE_local_initrenderdisplay_function) RE_local_initrenderdisplay_function(); -} -void RE_local_clear_render_display(short i) { - if (RE_local_clearrenderdisplay_function) RE_local_clearrenderdisplay_function(i); -} - -void RE_local_printrenderinfo(double time, int i) { - if (RE_local_printrenderinfo_function) RE_local_printrenderinfo_function(time, i); -} - -void RE_local_get_renderdata(void) { - if (RE_local_getrenderdata_function) RE_local_getrenderdata_function(); -} -void RE_local_free_renderdata(void) { - if (RE_local_freerenderdata_function) RE_local_freerenderdata_function(); -} - -/* Part 3: ------------------------------------------------------------- */ - -void RE_set_test_break_callback(int (*f)(void)) { - RE_local_test_break_function = f; -} - -void RE_set_timecursor_callback(void (*f)(int)) { - RE_local_timecursor_function = f; -} - -void RE_set_renderdisplay_callback(void (*f)(int i, - int j, - int k, - int l, - unsigned int *)) -{ - RE_local_renderdisplay_function = f; -} - -void RE_set_initrenderdisplay_callback(void (*f)(void)) { - RE_local_initrenderdisplay_function = f; -} - -void RE_set_clearrenderdisplay_callback(void (*f)(short)) { - RE_local_clearrenderdisplay_function = f; -} - -void RE_set_printrenderinfo_callback(void (*f)(double,int)) { - RE_local_printrenderinfo_function = f; -} - -void RE_set_getrenderdata_callback(void (*f)(void)) { - RE_local_getrenderdata_function = f; -} - -void RE_set_freerenderdata_callback(void (*f)(void)) { - RE_local_freerenderdata_function = f; -} diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c new file mode 100644 index 00000000000..76f4b11fe7b --- /dev/null +++ b/source/blender/render/intern/source/convertblender.c @@ -0,0 +1,3108 @@ +/** + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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. + * + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +#include "blendef.h" +#include "MTC_matrixops.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_memarena.h" +#include "BLI_ghash.h" + +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_material_types.h" +#include "DNA_curve_types.h" +#include "DNA_effect_types.h" +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_meta_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_curve.h" +#include "BKE_constraint.h" +#include "BKE_displist.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_key.h" +#include "BKE_ipo.h" +#include "BKE_lattice.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_subsurf.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_world.h" + +#include "envmap.h" +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "renderpipeline.h" +#include "radio.h" +#include "shadbuf.h" +#include "texture.h" +#include "zbuf.h" + +#include "YafRay_Api.h" + +/* yafray: Identity transform 'hack' removed, exporter now transforms vertices back to world. + * Same is true for lamp coords & vec. + * Duplicated data objects & dupliframe/duplivert objects are only stored once, + * only the matrix is stored for all others, in yafray these objects are instances of the original. + * The main changes are in RE_rotateBlenderScene(). + */ + +/* ------------------------------------------------------------------------- */ +/* Local functions */ +/* ------------------------------------------------------------------------- */ +static short test_for_displace(Render *re, Object *ob); +static void do_displacement(Render *re, Object *ob, int startface, int numface, int startvert, int numvert ); + +/* ------------------------------------------------------------------------- */ +/* tool functions/defines for ad hoc simplification and possible future + cleanup */ +/* ------------------------------------------------------------------------- */ + +#define UVTOINDEX(u,v) (startvlak + (u) * sizev + (v)) +/* + +NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !! + +^ ()----p4----p3----() +| | | | | +u | | F1 | F2 | + | | | | + ()----p1----p2----() + v -> +*/ + +/* ------------------------------------------------------------------------- */ + +static VertRen *duplicate_vertren(Render *re, VertRen *ver) +{ + VertRen *v1= RE_findOrAddVert(re, re->totvert++); + int index= v1->index; + *v1= *ver; + v1->index= index; + return v1; +} + +static void split_v_renderfaces(Render *re, int startvlak, int startvert, int usize, int vsize, int uIndex, int cyclu, int cyclv) +{ + int vLen = vsize-1+(!!cyclv); + int v; + + for (v=0; v<vLen; v++) { + VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v); + VertRen *vert = duplicate_vertren(re, vlr->v2); + + if (cyclv) { + vlr->v2 = vert; + + if (v==vLen-1) { + VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + 0); + vlr->v1 = vert; + } else { + VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v+1); + vlr->v1 = vert; + } + } else { + vlr->v2 = vert; + + if (v<vLen-1) { + VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v+1); + vlr->v1 = vert; + } + + if (v==0) { + vlr->v1 = duplicate_vertren(re, vlr->v1); + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +static int contrpuntnormr(float *n, float *puno) +{ + float inp; + + inp=n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2]; + if(inp<0.0) return 1; + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2) +{ + float len= VecLenf(v1->co, v2->co)/VecLenf(v1->orco, v2->orco); + float *acc; + + acc= accum + 2*v1->index; + acc[0]+= len; + acc[1]+= 1.0f; + + acc= accum + 2*v2->index; + acc[0]+= len; + acc[1]+= 1.0f; +} + +static void calc_edge_stress(Render *re, Mesh *me, int startvert, int startvlak) +{ + float loc[3], size[3], *accum, *acc, *accumoffs, *stress; + int a; + + if(startvert==re->totvert) return; + + mesh_get_texspace(me, loc, NULL, size); + + accum= MEM_callocN(2*sizeof(float)*(re->totvert-startvert), "temp accum for stress"); + + /* de-normalize orco */ + for(a=startvert; a<re->totvert; a++, acc+=2) { + VertRen *ver= RE_findOrAddVert(re, a); + if(ver->orco) { + ver->orco[0]= ver->orco[0]*size[0] +loc[0]; + ver->orco[1]= ver->orco[1]*size[1] +loc[1]; + ver->orco[2]= ver->orco[2]*size[2] +loc[2]; + } + } + + /* add stress values */ + accumoffs= accum - 2*startvert; /* so we can use vertex index */ + for(a=startvlak; a<re->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(re, a); + + if(vlr->v1->orco && vlr->v4) { + calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2); + calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3); + calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1); + if(vlr->v4) { + calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4); + calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1); + calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4); + } + } + } + + for(a=startvert; a<re->totvert; a++) { + VertRen *ver= RE_findOrAddVert(re, a); + if(ver->orco) { + /* find stress value */ + acc= accumoffs + 2*ver->index; + if(acc[1]!=0.0f) + acc[0]/= acc[1]; + stress= RE_vertren_get_stress(re, ver, 1); + *stress= *acc; + + /* restore orcos */ + ver->orco[0] = (ver->orco[0]-loc[0])/size[0]; + ver->orco[1] = (ver->orco[1]-loc[1])/size[1]; + ver->orco[2] = (ver->orco[2]-loc[2])/size[2]; + } + } + + MEM_freeN(accum); +} + +static void calc_tangent_vector(Render *re, VlakRen *vlr, float fac1, float fac2, float fac3, float fac4) +{ + TFace *tface= vlr->tface; + + if(tface) { + VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4; + float *uv1= tface->uv[0], *uv2= tface->uv[1], *uv3= tface->uv[2], *uv4= tface->uv[3]; + float tang[3], *tav; + float s1, s2, t1, t2, det; + + /* we calculate quads as two triangles, so weight for diagonal gets halved */ + if(v4) { + fac1*= 0.5f; + fac3*= 0.5f; + } + + /* first tria, we use the V now */ + s1= uv2[0] - uv1[0]; + s2= uv3[0] - uv1[0]; + t1= uv2[1] - uv1[1]; + t2= uv3[1] - uv1[1]; + det= 1.0f / (s1 * t2 - s2 * t1); + + /* normals in render are inversed... */ + tang[0]= (t2 * (v1->co[0]-v2->co[0]) - t1 * (v1->co[0]-v3->co[0])); + tang[1]= (t2 * (v1->co[1]-v2->co[1]) - t1 * (v1->co[1]-v3->co[1])); + tang[2]= (t2 * (v1->co[2]-v2->co[2]) - t1 * (v1->co[2]-v3->co[2])); + + tav= RE_vertren_get_tangent(re, v1, 1); + VECADDFAC(tav, tav, tang, fac1); + tav= RE_vertren_get_tangent(re, v2, 1); + VECADDFAC(tav, tav, tang, fac2); + tav= RE_vertren_get_tangent(re, v3, 1); + VECADDFAC(tav, tav, tang, fac3); + + if(v4) { + /* 2nd tria, we use the V now */ + s1= uv3[0] - uv1[0]; + s2= uv4[0] - uv1[0]; + t1= uv3[1] - uv1[1]; + t2= uv4[1] - uv1[1]; + det= 1.0f / (s1 * t2 - s2 * t1); + + /* normals in render are inversed... */ + tang[0]= (t2 * (v1->co[0]-v3->co[0]) - t1 * (v1->co[0]-v4->co[0])); + tang[1]= (t2 * (v1->co[1]-v3->co[1]) - t1 * (v1->co[1]-v4->co[1])); + tang[2]= (t2 * (v1->co[2]-v3->co[2]) - t1 * (v1->co[2]-v4->co[2])); + + Normalise(tang); + + tav= RE_vertren_get_tangent(re, v1, 1); + VECADDFAC(tav, tav, tang, fac1); + tav= RE_vertren_get_tangent(re, v3, 1); + VECADDFAC(tav, tav, tang, fac3); + tav= RE_vertren_get_tangent(re, v4, 1); + VECADDFAC(tav, tav, tang, fac4); + } + } +} + +static void calc_vertexnormals(Render *re, int startvert, int startvlak, int do_tangent) +{ + int a; + + /* clear all vertex normals */ + for(a=startvert; a<re->totvert; a++) { + VertRen *ver= RE_findOrAddVert(re, a); + ver->n[0]=ver->n[1]=ver->n[2]= 0.0; + } + + /* calculate cos of angles and point-masses, use as weight factor to + add face normal to vertex */ + for(a=startvlak; a<re->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(re, a); + if(vlr->flag & ME_SMOOTH) { + VertRen *adrve1= vlr->v1; + VertRen *adrve2= vlr->v2; + VertRen *adrve3= vlr->v3; + VertRen *adrve4= vlr->v4; + float n1[3], n2[3], n3[3], n4[3]; + float fac1, fac2, fac3, fac4=0.0f; + + VecSubf(n1, adrve2->co, adrve1->co); + Normalise(n1); + VecSubf(n2, adrve3->co, adrve2->co); + Normalise(n2); + if(adrve4==NULL) { + VecSubf(n3, adrve1->co, adrve3->co); + Normalise(n3); + + fac1= saacos(-n1[0]*n3[0]-n1[1]*n3[1]-n1[2]*n3[2]); + fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + } + else { + VecSubf(n3, adrve4->co, adrve3->co); + Normalise(n3); + VecSubf(n4, adrve1->co, adrve4->co); + Normalise(n4); + + fac1= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]); + fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + fac4= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]); + + if(!(vlr->flag & R_NOPUNOFLIP)) { + if( contrpuntnormr(vlr->n, adrve4->n) ) fac4= -fac4; + } + + adrve4->n[0] +=fac4*vlr->n[0]; + adrve4->n[1] +=fac4*vlr->n[1]; + adrve4->n[2] +=fac4*vlr->n[2]; + } + + if(!(vlr->flag & R_NOPUNOFLIP)) { + if( contrpuntnormr(vlr->n, adrve1->n) ) fac1= -fac1; + if( contrpuntnormr(vlr->n, adrve2->n) ) fac2= -fac2; + if( contrpuntnormr(vlr->n, adrve3->n) ) fac3= -fac3; + } + + adrve1->n[0] +=fac1*vlr->n[0]; + adrve1->n[1] +=fac1*vlr->n[1]; + adrve1->n[2] +=fac1*vlr->n[2]; + + adrve2->n[0] +=fac2*vlr->n[0]; + adrve2->n[1] +=fac2*vlr->n[1]; + adrve2->n[2] +=fac2*vlr->n[2]; + + adrve3->n[0] +=fac3*vlr->n[0]; + adrve3->n[1] +=fac3*vlr->n[1]; + adrve3->n[2] +=fac3*vlr->n[2]; + + if(do_tangent) + calc_tangent_vector(re, vlr, fac1, fac2, fac3, fac4); + } + } + + /* do solid faces */ + for(a=startvlak; a<re->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(re, a); + if((vlr->flag & ME_SMOOTH)==0) { + float *f1= vlr->v1->n; + if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n); + f1= vlr->v2->n; + if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n); + f1= vlr->v3->n; + if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n); + if(vlr->v4) { + f1= vlr->v4->n; + if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n); + } + } + } + + /* normalise vertex normals */ + for(a=startvert; a<re->totvert; a++) { + VertRen *ver= RE_findOrAddVert(re, a); + Normalise(ver->n); + if(do_tangent) { + float *tav= RE_vertren_get_tangent(re, ver, 0); + if(tav) Normalise(tav); + } + } + + /* vertex normal (puno) switch flags for during render */ + for(a=startvlak; a<re->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(re, a); + + if((vlr->flag & R_NOPUNOFLIP)==0) { + VertRen *adrve1= vlr->v1; + VertRen *adrve2= vlr->v2; + VertRen *adrve3= vlr->v3; + VertRen *adrve4= vlr->v4; + vlr->puno &= ~15; + if ((vlr->n[0]*adrve1->n[0]+vlr->n[1]*adrve1->n[1]+vlr->n[2]*adrve1->n[2])<0.0) vlr->puno= 1; + if ((vlr->n[0]*adrve2->n[0]+vlr->n[1]*adrve2->n[1]+vlr->n[2]*adrve2->n[2])<0.0) vlr->puno+= 2; + if ((vlr->n[0]*adrve3->n[0]+vlr->n[1]*adrve3->n[1]+vlr->n[2]*adrve3->n[2])<0.0) vlr->puno+= 4; + if(adrve4) { + if((vlr->n[0]*adrve4->n[0]+vlr->n[1]*adrve4->n[1]+vlr->n[2]*adrve4->n[2])<0.0) vlr->puno+= 8; + } + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Autosmoothing: */ +/* ------------------------------------------------------------------------- */ + +typedef struct ASvert { + int totface; + ListBase faces; +} ASvert; + +typedef struct ASface { + struct ASface *next, *prev; + VlakRen *vlr[4]; + VertRen *nver[4]; +} ASface; + +static void as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr) +{ + ASface *asf; + int a; + + if(v1 == NULL) return; + + if(asv->faces.first==NULL) { + asf= MEM_callocN(sizeof(ASface), "asface"); + BLI_addtail(&asv->faces, asf); + } + + asf= asv->faces.last; + for(a=0; a<4; a++) { + if(asf->vlr[a]==NULL) { + asf->vlr[a]= vlr; + asv->totface++; + break; + } + } + + /* new face struct */ + if(a==4) { + asf= MEM_callocN(sizeof(ASface), "asface"); + BLI_addtail(&asv->faces, asf); + asf->vlr[0]= vlr; + asv->totface++; + } +} + +static int as_testvertex(VlakRen *vlr, VertRen *ver, ASvert *asv, float thresh) +{ + /* return 1: vertex needs a copy */ + ASface *asf; + float inp; + int a; + + if(vlr==0) return 0; + + asf= asv->faces.first; + while(asf) { + for(a=0; a<4; a++) { + if(asf->vlr[a] && asf->vlr[a]!=vlr) { + inp= fabs( vlr->n[0]*asf->vlr[a]->n[0] + vlr->n[1]*asf->vlr[a]->n[1] + vlr->n[2]*asf->vlr[a]->n[2] ); + if(inp < thresh) return 1; + } + } + asf= asf->next; + } + + return 0; +} + +static VertRen *as_findvertex(VlakRen *vlr, VertRen *ver, ASvert *asv, float thresh) +{ + /* return when new vertex already was made */ + ASface *asf; + float inp; + int a; + + asf= asv->faces.first; + while(asf) { + for(a=0; a<4; a++) { + if(asf->vlr[a] && asf->vlr[a]!=vlr) { + /* this face already made a copy for this vertex! */ + if(asf->nver[a]) { + inp= fabs( vlr->n[0]*asf->vlr[a]->n[0] + vlr->n[1]*asf->vlr[a]->n[1] + vlr->n[2]*asf->vlr[a]->n[2] ); + if(inp >= thresh) { + return asf->nver[a]; + } + } + } + } + asf= asf->next; + } + + return NULL; +} + +static void autosmooth(Render *re, int startvert, int startvlak, int degr) +{ + ASvert *asv, *asverts, *asvertoffs; + ASface *asf; + VertRen *ver, *v1; + VlakRen *vlr; + float thresh; + int a, b, totvert; + + if(startvert==re->totvert) return; + asverts= MEM_callocN(sizeof(ASvert)*(re->totvert-startvert), "all smooth verts"); + asvertoffs= asverts-startvert; /* se we can use indices */ + + thresh= cos( M_PI*((float)degr)/180.0 ); + + /* step one: construct listbase of all vertices and pointers to faces */ + for(a=startvlak; a<re->totvlak; a++) { + vlr= RE_findOrAddVlak(re, a); + + as_addvert(asvertoffs+vlr->v1->index, vlr->v1, vlr); + as_addvert(asvertoffs+vlr->v2->index, vlr->v2, vlr); + as_addvert(asvertoffs+vlr->v3->index, vlr->v3, vlr); + if(vlr->v4) + as_addvert(asvertoffs+vlr->v4->index, vlr->v4, vlr); + } + + /* we now test all vertices, when faces have a normal too much different: they get a new vertex */ + totvert= re->totvert; + for(a=startvert, asv=asverts; a<totvert; a++, asv++) { + if(asv && asv->totface>1) { + ver= RE_findOrAddVert(re, a); + + asf= asv->faces.first; + while(asf) { + for(b=0; b<4; b++) { + + /* is there a reason to make a new vertex? */ + vlr= asf->vlr[b]; + if( as_testvertex(vlr, ver, asv, thresh) ) { + + /* already made a new vertex within threshold? */ + v1= as_findvertex(vlr, ver, asv, thresh); + if(v1==NULL) { + /* make a new vertex */ + v1= duplicate_vertren(re, ver); + } + asf->nver[b]= v1; + if(vlr->v1==ver) vlr->v1= v1; + if(vlr->v2==ver) vlr->v2= v1; + if(vlr->v3==ver) vlr->v3= v1; + if(vlr->v4==ver) vlr->v4= v1; + } + } + asf= asf->next; + } + } + } + + /* free */ + for(a=0; a<totvert-startvert; a++) { + BLI_freelistN(&asverts[a].faces); + } + MEM_freeN(asverts); +} + +/* ------------------------------------------------------------------------- */ +/* End of autosmoothing: */ +/* ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ +/* Orco hash */ +/* ------------------------------------------------------------------------- */ + + +static float *get_object_orco(Render *re, Object *ob) +{ + float *orco; + + if (!re->orco_hash) + re->orco_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + orco = BLI_ghash_lookup(re->orco_hash, ob); + + if (!orco) { + if (ob->type==OB_MESH) { + orco = mesh_create_orco_render(ob); + } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { + orco = make_orco_curve(ob); + } else if (ob->type==OB_SURF) { + orco = make_orco_surf(ob); + } + + if (orco) + BLI_ghash_insert(re->orco_hash, ob, orco); + } + + return orco; +} + +static void free_mesh_orco_hash(Render *re) +{ + if (re->orco_hash) { + BLI_ghash_free(re->orco_hash, NULL, (GHashValFreeFP)MEM_freeN); + re->orco_hash = NULL; + } +} + +/* ******************** END ORCO HASH ***************** */ + + +static void make_render_halos(Render *re, Object *ob, Mesh *me, int totvert, MVert *mvert, Material *ma, float *orco) +{ + HaloRen *har; + float xn, yn, zn, nor[3], view[3]; + float vec[3], hasize, mat[4][4], imat[3][3]; + int a, ok, seed= ma->seed1; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat3CpyMat4(imat, ob->imat); + + re->flag |= R_HALO; + + for(a=0; a<totvert; a++, mvert++) { + ok= 1; + + if(ok) { + hasize= ma->hasize; + + VECCOPY(vec, mvert->co); + MTC_Mat4MulVecfl(mat, vec); + + if(ma->mode & MA_HALOPUNO) { + xn= mvert->no[0]; + yn= mvert->no[1]; + zn= mvert->no[2]; + + /* transpose ! */ + nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(nor); + + VECCOPY(view, vec); + Normalise(view); + + zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2]; + if(zn>=0.0) hasize= 0.0; + else hasize*= zn*zn*zn*zn; + } + + if(orco) har= RE_inithalo(re, ma, vec, NULL, orco, hasize, 0.0, seed); + else har= RE_inithalo(re, ma, vec, NULL, mvert->co, hasize, 0.0, seed); + if(har) har->lay= ob->lay; + } + if(orco) orco+= 3; + seed++; + } +} + +/* ------------------------------------------------------------------------- */ +static Material *give_render_material(Render *re, Object *ob, int nr) +{ + extern Material defmaterial; /* material.c */ + Material *ma; + + ma= give_current_material(ob, nr); + if(ma==NULL) + ma= &defmaterial; + else + if(ma->mode & MA_ZTRA) + re->flag |= R_ZTRA; + + return ma; +} + + + +static void render_particle_system(Render *re, Object *ob, PartEff *paf) +{ + Particle *pa=0; + HaloRen *har=0; + Material *ma=0; + float xn, yn, zn, imat[3][3], tmat[4][4], mat[4][4], hasize, stime, ptime, ctime, vec[3], vec1[3], view[3], nor[3]; + int a, mat_nr=1, seed; + + pa= paf->keys; + if(pa==NULL || paf->disp!=100) { + build_particle_system(ob); + pa= paf->keys; + if(pa==NULL) return; + } + + ma= give_render_material(re, ob, paf->omat); + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); /* this is correct, for imat texture */ + + /* enable duplicators to work */ + Mat4MulMat4(tmat, paf->imat, ob->obmat); + MTC_Mat4MulMat4(mat, tmat, re->viewmat); + + MTC_Mat4Invert(tmat, mat); + MTC_Mat3CpyMat4(imat, tmat); + + re->flag |= R_HALO; + + if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf; + else ptime= 0.0; + ctime= bsystem_time(ob, 0, (float)re->scene->r.cfra, ptime); + seed= ma->seed1; + + for(a=0; a<paf->totpart; a++, pa+=paf->totkey, seed++) { + + /* offset time for calculating normal */ + stime= ctime; + ptime= ctime+1.0f; + if(ctime < pa->time) { + if(paf->flag & PAF_UNBORN) + ptime= pa->time+1.0f; + else + continue; + } + if(ctime > pa->time+pa->lifetime) { + if(paf->flag & PAF_DIED) + stime= pa->time+pa->lifetime-1.0f; + else + continue; + } + + /* watch it: also calculate the normal of a particle */ + if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) { + where_is_particle(paf, pa, stime, vec); + MTC_Mat4MulVecfl(mat, vec); + where_is_particle(paf, pa, ptime, vec1); + MTC_Mat4MulVecfl(mat, vec1); + } + else { + where_is_particle(paf, pa, ctime, vec); + MTC_Mat4MulVecfl(mat, vec); + } + + if(pa->mat_nr != mat_nr) { + mat_nr= pa->mat_nr; + ma= give_render_material(re, ob, mat_nr); + } + + if(ma->ipo) { + /* correction for lifetime */ + ptime= 100.0*(ctime-pa->time)/pa->lifetime; + calc_ipo(ma->ipo, ptime); + execute_ipo((ID *)ma, ma->ipo); + } + + hasize= ma->hasize; + + if(ma->mode & MA_HALOPUNO) { + xn= pa->no[0]; + yn= pa->no[1]; + zn= pa->no[2]; + + /* transpose ! */ + nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(nor); + + VECCOPY(view, vec); + Normalise(view); + + zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2]; + if(zn>=0.0) hasize= 0.0; + else hasize*= zn*zn*zn*zn; + } + + if(paf->stype==PAF_VECT) har= RE_inithalo(re, ma, vec, vec1, pa->co, hasize, paf->vectsize, seed); + else { + har= RE_inithalo(re, ma, vec, NULL, pa->co, hasize, 0.0, seed); + if(har && ma->mode & MA_HALO_SHADE) { + VecSubf(har->no, vec, vec1); + Normalise(har->no); + } + } + if(har) har->lay= ob->lay; + } + + /* restore material */ + for(a=1; a<=ob->totcol; a++) { + ma= give_render_material(re, ob, a); + if(ma) do_mat_ipo(ma); + } + + if(paf->disp!=100) { + MEM_freeN(paf->keys); + paf->keys= NULL; + } +} + + +/* ------------------------------------------------------------------------- */ + +/* future thread problem... */ +static void static_particle_strand(Render *re, Object *ob, Material *ma, float *orco, float *vec, float *vec1, float ctime, int first) +{ + static VertRen *v1= NULL, *v2= NULL; + VlakRen *vlr; + float nor[3], cross[3], w, dx, dy; + int flag; + + VecSubf(nor, vec, vec1); + Normalise(nor); // nor needed as tangent + Crossf(cross, vec, nor); + + /* turn cross in pixelsize */ + w= vec[2]*re->winmat[2][3] + re->winmat[3][3]; + dx= re->winx*cross[0]*re->winmat[0][0]/w; + dy= re->winy*cross[1]*re->winmat[1][1]/w; + w= sqrt(dx*dx + dy*dy); + if(w!=0.0f) { + float fac; + if(ma->strand_ease!=0.0f) { + if(ma->strand_ease<0.0f) + fac= pow(ctime, 1.0+ma->strand_ease); + else + fac= pow(ctime, 1.0/(1.0f-ma->strand_ease)); + } + else fac= ctime; + + VecMulf(cross, ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end)/w); + } + + if(ma->mode & MA_TANGENT_STR) + flag= R_SMOOTH|R_NOPUNOFLIP|R_STRAND|R_TANGENT; + else + flag= R_SMOOTH|R_STRAND; + + /* first two vertices */ + if(first) { + v1= RE_findOrAddVert(re, re->totvert++); + v2= RE_findOrAddVert(re, re->totvert++); + + VECCOPY(v1->co, vec); + VecAddf(v1->co, v1->co, cross); + VECCOPY(v1->n, nor); + v1->orco= orco; + v1->accum= -1.0f; // accum abuse for strand texco + + VECCOPY(v2->co, vec); + VecSubf(v2->co, v2->co, cross); + VECCOPY(v2->n, nor); + v2->orco= orco; + v2->accum= v1->accum; + } + else { + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->flag= flag; + vlr->ob= ob; + vlr->v1= v1; + vlr->v2= v2; + vlr->v3= RE_findOrAddVert(re, re->totvert++); + vlr->v4= RE_findOrAddVert(re, re->totvert++); + + v1= vlr->v4; // cycle + v2= vlr->v3; // cycle + + VECCOPY(vlr->v4->co, vec); + VecAddf(vlr->v4->co, vlr->v4->co, cross); + VECCOPY(vlr->v4->n, nor); + vlr->v4->orco= orco; + vlr->v4->accum= -1.0f + 2.0f*ctime; // accum abuse for strand texco + + VECCOPY(vlr->v3->co, vec); + VecSubf(vlr->v3->co, vlr->v3->co, cross); + VECCOPY(vlr->v3->n, nor); + vlr->v3->orco= orco; + vlr->v3->accum= vlr->v4->accum; + + CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n); + + vlr->mat= ma; + vlr->ec= ME_V2V3; + vlr->lay= ob->lay; + } +} + +static void render_static_particle_system(Render *re, Object *ob, PartEff *paf) +{ + Particle *pa=0; + HaloRen *har=0; + Material *ma=0; + VertRen *v1= NULL; + VlakRen *vlr; + float xn, yn, zn, imat[3][3], mat[4][4], hasize; + float mtime, ptime, ctime, vec[3], vec1[3], view[3], nor[3]; + float *orco= NULL, loc_tex[3], size_tex[3]; + int a, mat_nr=1, seed, totvlako, totverto, first; + + pa= paf->keys; + if(pa==NULL || (paf->flag & PAF_ANIMATED) || paf->disp!=100) { + build_particle_system(ob); + pa= paf->keys; + if(pa==NULL) return; + } + + totvlako= re->totvlak; + totverto= re->totvert; + + ma= give_render_material(re, ob, paf->omat); + if(ma->mode & MA_HALO) + re->flag |= R_HALO; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); /* need to be that way, for imat texture */ + + MTC_Mat3CpyMat4(imat, ob->imat); + + /* orcos */ + if(!(ma->mode & (MA_HALO|MA_WIRE))) { + orco= MEM_mallocN(3*sizeof(float)*paf->totpart, "static particle orcos"); + if (!re->orco_hash) + re->orco_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + BLI_ghash_insert(re->orco_hash, paf, orco); /* pointer is particles, otherwise object uses it */ + } + + mesh_get_texspace(ob->data, loc_tex, NULL, size_tex); + + if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf; + else ptime= 0.0; + ctime= bsystem_time(ob, 0, (float)re->scene->r.cfra, ptime); + seed= ma->seed1; + + for(a=0; a<paf->totpart; a++, pa+=paf->totkey) { + + where_is_particle(paf, pa, pa->time, vec1); + if(orco) { + orco[0] = (vec1[0]-loc_tex[0])/size_tex[0]; + orco[1] = (vec1[1]-loc_tex[1])/size_tex[1]; + orco[2] = (vec1[2]-loc_tex[2])/size_tex[2]; + } + MTC_Mat4MulVecfl(mat, vec1); + mtime= pa->time+pa->lifetime+paf->staticstep-1; + + first= 1; + for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep) { + + /* make sure hair grows until the end.. */ + if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime; + + /* watch it: also calc the normal of a particle */ + if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) { + where_is_particle(paf, pa, ctime+1.0, vec); + MTC_Mat4MulVecfl(mat, vec); + } + else { + where_is_particle(paf, pa, ctime, vec); + MTC_Mat4MulVecfl(mat, vec); + } + + if(pa->mat_nr != mat_nr) { + mat_nr= pa->mat_nr; + ma= give_render_material(re, ob, mat_nr); + } + + /* wires */ + if(ma->mode & MA_WIRE) { + if(ctime == pa->time) { + v1= RE_findOrAddVert(re, re->totvert++); + VECCOPY(v1->co, vec); + } + else { + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= v1; + vlr->v2= RE_findOrAddVert(re, re->totvert++); + vlr->v3= vlr->v2; + vlr->v4= NULL; + + v1= vlr->v2; // cycle + VECCOPY(v1->co, vec); + + VecSubf(vlr->n, vec, vec1); + Normalise(vlr->n); + VECCOPY(v1->n, vlr->n); + + vlr->mat= ma; + vlr->ec= ME_V1V2; + vlr->lay= ob->lay; + } + } + else { + if(ma->ipo) { + /* correction for lifetime */ + ptime= 100.0*(ctime-pa->time)/pa->lifetime; + calc_ipo(ma->ipo, ptime); + execute_ipo((ID *)ma, ma->ipo); + } + + if(ma->mode & MA_HALO) { + hasize= ma->hasize; + + if(ma->mode & MA_HALOPUNO) { + xn= pa->no[0]; + yn= pa->no[1]; + zn= pa->no[2]; + + /* transpose ! */ + nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(nor); + + VECCOPY(view, vec); + Normalise(view); + + zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2]; + if(zn>=0.0) hasize= 0.0; + else hasize*= zn*zn*zn*zn; + } + + if(paf->stype==PAF_VECT) har= RE_inithalo(re, ma, vec, vec1, pa->co, hasize, paf->vectsize, seed); + else { + har= RE_inithalo(re, ma, vec, NULL, pa->co, hasize, 0.0, seed); + if(har && (ma->mode & MA_HALO_SHADE)) { + VecSubf(har->no, vec, vec1); + Normalise(har->no); + har->lay= ob->lay; + } + } + if(har) har->lay= ob->lay; + } + else { /* generate pixel sized hair strand */ + static_particle_strand(re, ob, ma, orco, vec, vec1, (ctime-pa->time)/(mtime-pa->time), first); + } + } + + VECCOPY(vec1, vec); + first= 0; + } + + seed++; + if(orco) orco+=3; + } + + if(paf->disp!=100) { + MEM_freeN(paf->keys); + paf->keys= NULL; + } + + if((ma->mode & MA_TANGENT_STR)==0) + calc_vertexnormals(re, totverto, totvlako, 0); +} + + +/* ------------------------------------------------------------------------- */ + +static int verghalo(const void *a1, const void *a2) +{ + const struct halosort *x1=a1, *x2=a2; + + if( x1->z < x2->z ) return 1; + else if( x1->z > x2->z) return -1; + return 0; +} + +/* ------------------------------------------------------------------------- */ +static void sort_halos(Render *re) +{ + struct halosort *hablock, *haso; + HaloRen *har = NULL, **bloha; + int a; + + if(re->tothalo==0) return; + + /* make datablock with halo pointers, sort */ + haso= hablock= MEM_mallocN(sizeof(struct halosort)*re->tothalo, "hablock"); + + for(a=0; a<re->tothalo; a++) { + if((a & 255)==0) har= re->bloha[a>>8]; + else har++; + haso->har= har; + haso->z= har->zs; + haso++; + } + + qsort(hablock, re->tothalo, sizeof(struct halosort), verghalo); + + /* re-assamble re->bloha */ + + bloha= re->bloha; + re->bloha= (HaloRen **)MEM_callocN(sizeof(void *)*(re->blohalen),"Bloha"); + + haso= hablock; + for(a=0; a<re->tothalo; a++) { + har= RE_findOrAddHalo(re, a); + *har= *(haso->har); + + haso++; + } + + /* free */ + a= 0; + while(bloha[a]) { + MEM_freeN(bloha[a]); + a++; + } + MEM_freeN(bloha); + MEM_freeN(hablock); + +} + +/* ------------------------------------------------------------------------- */ +static void init_render_mball(Render *re, Object *ob) +{ + DispList *dl, *dlo; + VertRen *ver; + VlakRen *vlr, *vlr1; + Material *ma; + float *data, *nors, mat[4][4], imat[3][3], xn, yn, zn; + int a, need_orco, startvert, *index; + + if (ob!=find_basis_mball(ob)) + return; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + MTC_Mat3CpyMat4(imat, ob->imat); + + ma= give_render_material(re, ob, 1); + + need_orco= 0; + if(ma->texco & TEXCO_ORCO) { + need_orco= 1; + } + + dlo= ob->disp.first; + if(dlo) BLI_remlink(&ob->disp, dlo); + + makeDispListMBall(ob); + dl= ob->disp.first; + if(dl==0) return; + + startvert= re->totvert; + data= dl->verts; + nors= dl->nors; + + for(a=0; a<dl->nr; a++, data+=3, nors+=3) { + + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, data); + MTC_Mat4MulVecfl(mat, ver->co); + + xn= nors[0]; + yn= nors[1]; + zn= nors[2]; + + /* transpose ! */ + ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(ver->n); + //if(ob->transflag & OB_NEG_SCALE) VecMulf(ver->n. -1.0); + + if(need_orco) ver->orco= data; + } + + index= dl->index; + for(a=0; a<dl->parts; a++, index+=4) { + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= RE_findOrAddVert(re, startvert+index[0]); + vlr->v2= RE_findOrAddVert(re, startvert+index[1]); + vlr->v3= RE_findOrAddVert(re, startvert+index[2]); + vlr->v4= 0; + + if(ob->transflag & OB_NEG_SCALE) + CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->n); + else + CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n); + + vlr->mat= ma; + vlr->flag= ME_SMOOTH+R_NOPUNOFLIP; + vlr->ec= 0; + vlr->lay= ob->lay; + + /* mball -too bad- always has triangles, because quads can be non-planar */ + if(index[3]) { + vlr1= RE_findOrAddVlak(re, re->totvlak++); + *vlr1= *vlr; + vlr1->v2= vlr1->v3; + vlr1->v3= RE_findOrAddVert(re, startvert+index[3]); + if(ob->transflag & OB_NEG_SCALE) + CalcNormFloat(vlr1->v1->co, vlr1->v2->co, vlr1->v3->co, vlr1->n); + else + CalcNormFloat(vlr1->v3->co, vlr1->v2->co, vlr1->v1->co, vlr1->n); + } + } + + if(need_orco) { + /* store displist and scale */ + make_orco_mball(ob); + if(dlo) BLI_addhead(&ob->disp, dlo); + + } + else { + freedisplist(&ob->disp); + if(dlo) BLI_addtail(&ob->disp, dlo); + } +} +/* ------------------------------------------------------------------------- */ +/* convert */ + +struct edgesort { + int v1, v2; + int has_mcol; + TFace *tface; + float uv1[2], uv2[2]; + unsigned int mcol1, mcol2; +}; + +/* edges have to be added with lowest index first for sorting */ +static void to_edgesort(struct edgesort *ed, int i1, int i2, int v1, int v2, unsigned int *mcol, TFace *tface) +{ + if(v1<v2) { + ed->v1= v1; ed->v2= v2; + } + else { + ed->v1= v2; ed->v2= v1; + SWAP(int, i1, i2); + } + /* copy color and tface, edges use different ordering */ + ed->tface= tface; + if(tface) { + ed->uv1[0]= tface->uv[i1][0]; + ed->uv1[1]= tface->uv[i1][1]; + ed->uv2[0]= tface->uv[i2][0]; + ed->uv2[1]= tface->uv[i2][1]; + + ed->mcol1= tface->col[i1]; + ed->mcol2= tface->col[i2]; + } + ed->has_mcol= mcol!=NULL; + if(mcol) { + ed->mcol1= mcol[i1]; + ed->mcol2= mcol[i2]; + } +} + +static int vergedgesort(const void *v1, const void *v2) +{ + const struct edgesort *x1=v1, *x2=v2; + + if( x1->v1 > x2->v1) return 1; + else if( x1->v1 < x2->v1) return -1; + else if( x1->v2 > x2->v2) return 1; + else if( x1->v2 < x2->v2) return -1; + + return 0; +} + +static struct edgesort *make_mesh_edge_lookup(Mesh *me, DispListMesh *dlm, int *totedgesort) +{ + MFace *mf, *mface; + TFace *tface=NULL; + struct edgesort *edsort, *ed; + unsigned int *mcol=NULL; + int a, totedge=0, totface; + + if (dlm) { + mface= dlm->mface; + totface= dlm->totface; + if (dlm->tface) + tface= dlm->tface; + else if (dlm->mcol) + mcol= (unsigned int *)dlm->mcol; + } else { + mface= me->mface; + totface= me->totface; + if (me->tface) + tface= me->tface; + else if (me->mcol) + mcol= (unsigned int *)me->mcol; + } + + if(mcol==NULL && tface==NULL) return NULL; + + /* make sorted table with edges and and tface/mcol pointers in it */ + for(a= totface, mf= mface; a>0; a--, mf++) { + if(mf->v4) totedge+=4; + else if(mf->v3) totedge+=3; + } + if(totedge==0) return NULL; + + ed= edsort= MEM_mallocN(totedge*sizeof(struct edgesort), "edgesort"); + + for(a= me->totface, mf= mface; a>0; a--, mf++) { + if(mface->v4 || mface->v3) { + to_edgesort(ed++, 0, 1, mf->v1, mf->v2, mcol, tface); + to_edgesort(ed++, 1, 2, mf->v2, mf->v3, mcol, tface); + if(mf->v4) { + to_edgesort(ed++, 2, 3, mf->v3, mf->v4, mcol, tface); + to_edgesort(ed++, 3, 0, mf->v4, mf->v1, mcol, tface); + } + else if(mf->v3) { + to_edgesort(ed++, 2, 3, mf->v3, mf->v1, mcol, tface); + } + } + if(mcol) mcol+=4; + if(tface) tface++; + } + + qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort); + + *totedgesort= totedge; + return edsort; +} + +static void use_mesh_edge_lookup(Render *re, Mesh *me, DispListMesh *dlm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge) +{ + struct edgesort ed, *edp; + + if(medge->v1 < medge->v2) { + ed.v1= medge->v1; ed.v2= medge->v2; + } + else { + ed.v1= medge->v2; ed.v2= medge->v1; + } + + edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort); + if(edp) { + /* since edges have different index ordering, we have to duplicate mcol and tface */ + if(edp->tface) { + vlr->tface= BLI_memarena_alloc(re->memArena, sizeof(TFace)); + vlr->vcol= vlr->tface->col; + memcpy(vlr->tface, edp->tface, sizeof(TFace)); + + if(edp->v1==medge->v1) { + vlr->vcol[0]= edp->mcol1; + vlr->vcol[1]= edp->mcol2; + } + else { + vlr->vcol[0]= edp->mcol2; + vlr->vcol[1]= edp->mcol1; + } + vlr->vcol[2]= vlr->vcol[1]; + vlr->vcol[3]= vlr->vcol[1]; + + if(edp->v1==medge->v1) { + memcpy(vlr->tface->uv[0], edp->uv1, 2*sizeof(float)); + memcpy(vlr->tface->uv[1], edp->uv2, 2*sizeof(float)); + } + else { + memcpy(vlr->tface->uv[0], edp->uv2, 2*sizeof(float)); + memcpy(vlr->tface->uv[1], edp->uv1, 2*sizeof(float)); + } + memcpy(vlr->tface->uv[2], vlr->tface->uv[1], 2*sizeof(float)); + memcpy(vlr->tface->uv[3], vlr->tface->uv[1], 2*sizeof(float)); + } + else if(edp->has_mcol) { + vlr->vcol= BLI_memarena_alloc(re->memArena, sizeof(MCol)*4); + vlr->vcol[0]= edp->mcol1; + vlr->vcol[1]= edp->mcol2; + vlr->vcol[2]= vlr->vcol[1]; + vlr->vcol[3]= vlr->vcol[1]; + } + } +} + +static void init_render_mesh(Render *re, Object *ob) +{ + Mesh *me; + MVert *mvert = NULL; + MFace *mface; + VlakRen *vlr; //, *vlr1; + VertRen *ver; + Material *ma; + MSticky *ms = NULL; + PartEff *paf; + DispListMesh *dlm = NULL; + DerivedMesh *dm; + unsigned int *vertcol; + float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3], + float *orco=0; + int a, a1, ok, need_orco=0, need_stress=0, need_tangent=0, totvlako, totverto, vertofs; + int end, do_autosmooth=0, totvert = 0, dm_needsfree; + + me= ob->data; + + paf = give_parteff(ob); + if(paf) { + /* warning; build_particle_system does modifier calls itself */ + if(paf->flag & PAF_STATIC) render_static_particle_system(re, ob, paf); + else render_particle_system(re, ob, paf); + if((paf->flag & PAF_SHOWE)==0) return; + } + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + MTC_Mat3CpyMat4(imat, ob->imat); + + if(me->totvert==0) { + return; + } + + totvlako= re->totvlak; + totverto= re->totvert; + + need_orco= 0; + for(a=1; a<=ob->totcol; a++) { + ma= give_render_material(re, ob, a); + if(ma) { + if(ma->texco & (TEXCO_ORCO|TEXCO_STRESS)) + need_orco= 1; + if(ma->texco & TEXCO_STRESS) + need_stress= 1; + if(ma->mode & MA_TANGENT_V) + need_tangent= 1; + } + } + + if(need_orco) orco = get_object_orco(re, ob); + + dm = mesh_create_derived_render(ob); + dm_needsfree= 1; + + if(dm==NULL) return; /* in case duplicated object fails? */ + + dlm = dm->convertToDispListMesh(dm, 1); + + mvert= dlm->mvert; + totvert= dlm->totvert; + + ms = (totvert==me->totvert)?me->msticky:NULL; + + ma= give_render_material(re, ob, 1); + + if(ma->mode & MA_HALO) { + make_render_halos(re, ob, me, totvert, mvert, ma, orco); + } + else { + + for(a=0; a<totvert; a++, mvert++) { + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, mvert->co); + MTC_Mat4MulVecfl(mat, ver->co); + + if(orco) { + ver->orco= orco; + orco+=3; + } + if(ms) { + float *sticky= RE_vertren_get_sticky(re, ver, 1); + sticky[0]= ms->co[0]; + sticky[1]= ms->co[1]; + ms++; + } + } + /* still to do for keys: the correct local texture coordinate */ + + /* faces in order of color blocks */ + vertofs= re->totvert - totvert; + for(a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) { + + ma= give_render_material(re, ob, a1+1); + + /* test for 100% transparant */ + ok= 1; + if(ma->alpha==0.0 && ma->spectra==0.0) { + ok= 0; + /* texture on transparency? */ + for(a=0; a<MAX_MTEX; a++) { + if(ma->mtex[a] && ma->mtex[a]->tex) { + if(ma->mtex[a]->mapto & MAP_ALPHA) ok= 1; + } + } + } + + /* if wire material, and we got edges, don't do the faces */ + if(ma->mode & MA_WIRE) { + end= dlm?dlm->totedge:me->totedge; + if(end) ok= 0; + } + + if(ok) { + TFace *tface= NULL; + + /* radio faces need autosmooth, to separate shared vertices in corners */ + if(re->r.mode & R_RADIO) + if(ma->mode & MA_RADIO) + do_autosmooth= 1; + + end= dlm?dlm->totface:me->totface; + if (dlm) { + mface= dlm->mface; + if (dlm->tface) { + tface= dlm->tface; + vertcol= NULL; + } else if (dlm->mcol) { + vertcol= (unsigned int *)dlm->mcol; + } else { + vertcol= NULL; + } + } else { + mface= me->mface; + if (me->tface) { + tface= me->tface; + vertcol= NULL; + } else if (me->mcol) { + vertcol= (unsigned int *)me->mcol; + } else { + vertcol= NULL; + } + } + + for(a=0; a<end; a++) { + int v1, v2, v3, v4, flag; + + if( mface->mat_nr==a1 ) { + float len; + + v1= mface->v1; + v2= mface->v2; + v3= mface->v3; + v4= mface->v4; + flag= mface->flag & ME_SMOOTH; + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= RE_findOrAddVert(re, vertofs+v1); + vlr->v2= RE_findOrAddVert(re, vertofs+v2); + vlr->v3= RE_findOrAddVert(re, vertofs+v3); + if(v4) vlr->v4= RE_findOrAddVert(re, vertofs+v4); + else vlr->v4= 0; + + /* render normals are inverted in render */ + if(vlr->v4) len= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, + vlr->v1->co, vlr->n); + else len= CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, + vlr->n); + + vlr->mat= ma; + vlr->flag= flag; + if((me->flag & ME_NOPUNOFLIP) ) { + vlr->flag |= R_NOPUNOFLIP; + } + vlr->ec= 0; /* mesh edges rendered separately */ + vlr->lay= ob->lay; + + if(len==0) re->totvlak--; + else { + if(dlm) { + if(tface) { + vlr->tface= BLI_memarena_alloc(re->memArena, sizeof(TFace)); + vlr->vcol= vlr->tface->col; + memcpy(vlr->tface, tface, sizeof(TFace)); + } + else if (vertcol) { + vlr->vcol= BLI_memarena_alloc(re->memArena, sizeof(int)*4); + memcpy(vlr->vcol, vertcol+4*a, sizeof(int)*4); + } + } else { + if(tface) { + vlr->vcol= tface->col; + vlr->tface= tface; + } + else if (vertcol) { + vlr->vcol= vertcol+4*a; + } + } + } + } + + mface++; + if(tface) tface++; + } + } + } + + /* exception... we do edges for wire mode. potential conflict when faces exist... */ + end= dlm?dlm->totedge:me->totedge; + mvert= dlm?dlm->mvert:me->mvert; + ma= give_render_material(re, ob, 1); + if(end && (ma->mode & MA_WIRE)) { + MEdge *medge; + struct edgesort *edgetable; + int totedge; + + medge= dlm?dlm->medge:me->medge; + + /* we want edges to have UV and vcol too... */ + edgetable= make_mesh_edge_lookup(me, dlm, &totedge); + + for(a1=0; a1<end; a1++, medge++) { + if (medge->flag&ME_EDGERENDER) { + MVert *v0 = &mvert[medge->v1]; + MVert *v1 = &mvert[medge->v2]; + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= RE_findOrAddVert(re, vertofs+medge->v1); + vlr->v2= RE_findOrAddVert(re, vertofs+medge->v2); + vlr->v3= vlr->v2; + vlr->v4= NULL; + + if(edgetable) { + use_mesh_edge_lookup(re, me, dlm, medge, vlr, edgetable, totedge); + } + + xn= (v0->no[0]+v1->no[0]); + yn= (v0->no[1]+v1->no[1]); + zn= (v0->no[2]+v1->no[2]); + /* transpose ! */ + vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(vlr->n); + + vlr->mat= ma; + vlr->flag= 0; + vlr->ec= ME_V1V2; + vlr->lay= ob->lay; + } + } + if(edgetable) + MEM_freeN(edgetable); + } + } + + if (test_for_displace(re, ob ) ) { + calc_vertexnormals(re, totverto, totvlako, 0); + do_displacement(re, ob, totvlako, re->totvlak-totvlako, totverto, re->totvert-totverto); + } + + if(do_autosmooth || (me->flag & ME_AUTOSMOOTH)) { + autosmooth(re, totverto, totvlako, me->smoothresh); + } + + calc_vertexnormals(re, totverto, totvlako, need_tangent); + + if(need_stress) + calc_edge_stress(re, me, totverto, totvlako); + + if(dlm) displistmesh_free(dlm); + if(dm_needsfree) dm->release(dm); +} + +/* ------------------------------------------------------------------------- */ + +static void initshadowbuf(Render *re, LampRen *lar, float mat[][4]) +{ + struct ShadBuf *shb; + float hoek, temp, viewinv[4][4]; + + /* if(la->spsi<16) return; */ + + /* memory reservation */ + shb= (struct ShadBuf *)MEM_callocN( sizeof(struct ShadBuf),"initshadbuf"); + lar->shb= shb; + + if(shb==NULL) return; + + VECCOPY(shb->co, lar->co); + + /* percentage render: keep track of min and max */ + shb->size= (lar->bufsize*re->r.size)/100; + if(shb->size<512) shb->size= 512; + else if(shb->size > lar->bufsize) shb->size= lar->bufsize; + + shb->size &= ~15; /* make sure its multiples of 16 */ + + shb->samp= lar->samp; + shb->soft= lar->soft; + shb->shadhalostep= lar->shadhalostep; + + shb->zbuf= (unsigned long *)MEM_mallocN( sizeof(unsigned long)*(shb->size*shb->size)/256, "initshadbuf2"); + shb->cbuf= (char *)MEM_callocN( (shb->size*shb->size)/256, "initshadbuf3"); + + if(shb->zbuf==0 || shb->cbuf==0) { + if(shb->zbuf) MEM_freeN(shb->zbuf); + MEM_freeN(lar->shb); + lar->shb= 0; + return; + } + + MTC_Mat4Ortho(mat); + MTC_Mat4Invert(shb->winmat, mat); /* winmat is temp */ + + /* matrix: combination of inverse view and lampmat */ + /* calculate again: the ortho-render has no correct viewinv */ + MTC_Mat4Invert(viewinv, re->viewmat); + MTC_Mat4MulMat4(shb->viewmat, viewinv, shb->winmat); + + /* projection */ + hoek= saacos(lar->spotsi); + temp= 0.5*shb->size*cos(hoek)/sin(hoek); + shb->d= lar->clipsta; + + shb->pixsize= (shb->d)/temp; + + shb->clipend= lar->clipend; + /* bias is percentage, made 2x karger because of correction for angle of incidence */ + /* when a ray is closer to parallel of a face, bias value is increased during render */ + shb->bias= (0.02*lar->bias)*0x7FFFFFFF; + shb->bias= shb->bias*(100/re->r.size); + +} + + +static void area_lamp_vectors(LampRen *lar) +{ + float xsize= 0.5*lar->area_size, ysize= 0.5*lar->area_sizey; + + /* corner vectors */ + lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; + lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; + lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; + lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; + lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; + lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; + lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; + lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; + lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + /* only for correction button size, matrix size works on energy */ + lar->areasize= lar->dist*lar->dist/(4.0*xsize*ysize); +} + +/* If lar takes more lamp data, the decoupling will be better. */ +static void add_render_lamp(Render *re, Object *ob, int actual_render) +{ + Lamp *la= ob->data; + LampRen *lar; + GroupObject *go; + float mat[4][4], hoek, xn, yn; + int c; + + /* prevent only shadow from rendering light, but only return on render, not preview */ + if(actual_render) { + if(la->mode & LA_ONLYSHADOW) + if((re->r.mode & R_SHADOW)==0) + return; + } + + go= MEM_callocN(sizeof(GroupObject), "groupobject"); + BLI_addtail(&re->lights, go); + re->totlamp++; + lar= (LampRen *)MEM_callocN(sizeof(LampRen),"lampren"); + go->lampren= lar; + go->ob= ob; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + + MTC_Mat3CpyMat4(lar->mat, mat); + MTC_Mat3CpyMat4(lar->imat, ob->imat); + + lar->bufsize = la->bufsize; + lar->samp = la->samp; + lar->soft = la->soft; + lar->shadhalostep = la->shadhalostep; + lar->clipsta = la->clipsta; + lar->clipend = la->clipend; + lar->bias = la->bias; + + lar->type= la->type; + lar->mode= la->mode; + + lar->energy= la->energy; + lar->energy= la->energy; + if(la->mode & LA_NEG) lar->energy= -lar->energy; + + lar->vec[0]= -mat[2][0]; + lar->vec[1]= -mat[2][1]; + lar->vec[2]= -mat[2][2]; + Normalise(lar->vec); + lar->co[0]= mat[3][0]; + lar->co[1]= mat[3][1]; + lar->co[2]= mat[3][2]; + lar->dist= la->dist; + lar->haint= la->haint; + lar->distkw= lar->dist*lar->dist; + lar->r= lar->energy*la->r; + lar->g= lar->energy*la->g; + lar->b= lar->energy*la->b; + lar->k= la->k; + + // area + lar->ray_samp= la->ray_samp; + lar->ray_sampy= la->ray_sampy; + lar->ray_sampz= la->ray_sampz; + + lar->area_size= la->area_size; + lar->area_sizey= la->area_sizey; + lar->area_sizez= la->area_sizez; + + lar->area_shape= la->area_shape; + lar->ray_samp_type= la->ray_samp_type; + + if(lar->type==LA_AREA) { + switch(lar->area_shape) { + case LA_AREA_SQUARE: + lar->ray_totsamp= lar->ray_samp*lar->ray_samp; + lar->ray_sampy= lar->ray_samp; + lar->area_sizey= lar->area_size; + break; + case LA_AREA_RECT: + lar->ray_totsamp= lar->ray_samp*lar->ray_sampy; + break; + case LA_AREA_CUBE: + lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp; + lar->ray_sampy= lar->ray_samp; + lar->ray_sampz= lar->ray_samp; + lar->area_sizey= lar->area_size; + lar->area_sizez= lar->area_size; + break; + case LA_AREA_BOX: + lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz; + break; + } + + area_lamp_vectors(lar); + } + else lar->ray_totsamp= 0; + + /* yafray: photonlight and other params */ + if (re->r.renderer==R_YAFRAY) { + lar->YF_numphotons = la->YF_numphotons; + lar->YF_numsearch = la->YF_numsearch; + lar->YF_phdepth = la->YF_phdepth; + lar->YF_useqmc = la->YF_useqmc; + lar->YF_causticblur = la->YF_causticblur; + lar->YF_ltradius = la->YF_ltradius; + lar->YF_bufsize = la->YF_bufsize; + lar->YF_glowint = la->YF_glowint; + lar->YF_glowofs = la->YF_glowofs; + lar->YF_glowtype = la->YF_glowtype; + } + + lar->spotsi= la->spotsize; + if(lar->mode & LA_HALO) { + if(lar->spotsi>170.0) lar->spotsi= 170.0; + } + lar->spotsi= cos( M_PI*lar->spotsi/360.0 ); + lar->spotbl= (1.0-lar->spotsi)*la->spotblend; + + memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *)); + + lar->lay= ob->lay & 0xFFFFFF; // higher 8 bits are localview layers + + lar->ld1= la->att1; + lar->ld2= la->att2; + + if(lar->type==LA_SPOT) { + + Normalise(lar->imat[0]); + Normalise(lar->imat[1]); + Normalise(lar->imat[2]); + + xn= saacos(lar->spotsi); + xn= sin(xn)/cos(xn); + lar->spottexfac= 1.0/(xn); + + if(lar->mode & LA_ONLYSHADOW) { + if((lar->mode & (LA_SHAD|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW; + } + + } + + /* set flag for spothalo en initvars */ + if(la->type==LA_SPOT && (la->mode & LA_HALO)) { + if(la->haint>0.0) { + re->flag |= R_LAMPHALO; + + /* camera position (0,0,0) rotate around lamp */ + lar->sh_invcampos[0]= -lar->co[0]; + lar->sh_invcampos[1]= -lar->co[1]; + lar->sh_invcampos[2]= -lar->co[2]; + MTC_Mat3MulVecfl(lar->imat, lar->sh_invcampos); + + /* z factor, for a normalized volume */ + hoek= saacos(lar->spotsi); + xn= lar->spotsi; + yn= sin(hoek); + lar->sh_zfac= yn/xn; + /* pre-scale */ + lar->sh_invcampos[2]*= lar->sh_zfac; + + } + } + + for(c=0; c<MAX_MTEX; c++) { + if(la->mtex[c] && la->mtex[c]->tex) { + lar->mode |= LA_TEXTURE; + + if(G.rendering) { + if(re->osa) { + if(la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX; + } + } + } + } + + /* yafray: shadowbuffers and jitter only needed for internal render */ + if (actual_render && re->r.renderer==R_INTERN) { + if(re->r.mode & R_SHADOW) { + if (la->type==LA_SPOT && (lar->mode & LA_SHAD) ) { + /* Per lamp, one shadow buffer is made. */ + Mat4CpyMat4(mat, ob->obmat); + initshadowbuf(re, lar, mat); // mat is altered + } + else if(la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) ) { + init_jitter_plane(lar); + } + } + } + + /* yafray: shadow flag should not be cleared, only used with internal renderer */ + if (re->r.renderer==R_INTERN) { + /* to make sure we can check ray shadow easily in the render code */ + if(lar->mode & LA_SHAD_RAY) { + if( (re->r.mode & R_RAYTRACE)==0) + lar->mode &= ~LA_SHAD_RAY; + } + } +} + +/* ------------------------------------------------------------------------- */ +static void init_render_surf(Render *re, Object *ob) +{ + extern Material defmaterial; // initrender.c + Nurb *nu=0; + Curve *cu; + ListBase displist; + DispList *dl; + VertRen *ver, *v1, *v2, *v3, *v4; + VlakRen *vlr; + Material *matar[32]; + float *data, *orco=NULL, *orcobase=NULL, n1[3], flen, mat[4][4]; + int a, need_orco=0, startvlak, startvert, p1, p2, p3, p4; + int u, v; + int sizeu, sizev; + VlakRen *vlr1, *vlr2, *vlr3; + float vn[3]; // n2[3], + + cu= ob->data; + nu= cu->nurb.first; + if(nu==0) return; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + + /* material array */ + memset(matar, 0, 4*32); + matar[0]= &defmaterial; + for(a=0; a<ob->totcol; a++) { + matar[a]= give_render_material(re, ob, a+1); + if(matar[a] && matar[a]->texco & TEXCO_ORCO) { + need_orco= 1; + } + } + + if(ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1; + + if(need_orco) orcobase= orco= get_object_orco(re, ob); + + displist.first= displist.last= 0; + makeDispListSurf(ob, &displist, 1); + + dl= displist.first; + /* walk along displaylist and create rendervertices/-faces */ + while(dl) { + /* watch out: u ^= y, v ^= x !! */ + if(dl->type==DL_SURF) { + int nsizeu, nsizev; + + startvert= re->totvert; + nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr; + + data= dl->verts; + for (u = 0; u < sizeu; u++) { + v1 = RE_findOrAddVert(re, re->totvert++); /* save this for possible V wrapping */ + VECCOPY(v1->co, data); data += 3; + if(orco) { + v1->orco= orco; orco+= 3; + } + MTC_Mat4MulVecfl(mat, v1->co); + + for (v = 1; v < sizev; v++) { + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, data); data += 3; + if(orco) { + ver->orco= orco; orco+= 3; + } + MTC_Mat4MulVecfl(mat, ver->co); + } + /* if V-cyclic, add extra vertices at end of the row */ + if (dl->flag & DL_CYCL_U) { + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, v1->co); + if(orco) { + ver->orco= orcobase + 3*(u*sizev + 0); + } + } + } + + /* Done before next loop to get corner vert */ + if (dl->flag & DL_CYCL_U) nsizev++; + if (dl->flag & DL_CYCL_V) nsizeu++; + + /* if U cyclic, add extra row at end of column */ + if (dl->flag & DL_CYCL_V) { + for (v = 0; v < nsizev; v++) { + v1= RE_findOrAddVert(re, startvert + v); + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, v1->co); + if(orco) { + ver->orco= orcobase + 3*(0*sizev + v); + } + } + } + + sizeu = nsizeu; + sizev = nsizev; + + startvlak= re->totvlak; + + for(u = 0; u < sizeu - 1; u++) { + p1 = startvert + u * sizev; /* walk through face list */ + p2 = p1 + 1; + p3 = p2 + sizev; + p4 = p3 - 1; + + for(v = 0; v < sizev - 1; v++) { + v1= RE_findOrAddVert(re, p1); + v2= RE_findOrAddVert(re, p2); + v3= RE_findOrAddVert(re, p3); + v4= RE_findOrAddVert(re, p4); + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4; + + flen= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1); + VECCOPY(vlr->n, n1); + + vlr->lay= ob->lay; + vlr->mat= matar[ dl->col]; + vlr->ec= ME_V1V2+ME_V2V3; + vlr->flag= dl->rt; + if( (cu->flag & CU_NOPUNOFLIP) ) { + vlr->flag |= R_NOPUNOFLIP; + } + + VecAddf(v1->n, v1->n, n1); + VecAddf(v2->n, v2->n, n1); + VecAddf(v3->n, v3->n, n1); + VecAddf(v4->n, v4->n, n1); + + p1++; p2++; p3++; p4++; + } + } + /* fix normals for U resp. V cyclic faces */ + sizeu--; sizev--; /* dec size for face array */ + if (dl->flag & DL_CYCL_V) { + + for (v = 0; v < sizev; v++) + { + /* optimize! :*/ + vlr= RE_findOrAddVlak(re, UVTOINDEX(sizeu - 1, v)); + vlr1= RE_findOrAddVlak(re, UVTOINDEX(0, v)); + VecAddf(vlr1->v1->n, vlr1->v1->n, vlr->n); + VecAddf(vlr1->v2->n, vlr1->v2->n, vlr->n); + VecAddf(vlr->v3->n, vlr->v3->n, vlr1->n); + VecAddf(vlr->v4->n, vlr->v4->n, vlr1->n); + } + } + if (dl->flag & DL_CYCL_U) { + + for (u = 0; u < sizeu; u++) + { + /* optimize! :*/ + vlr= RE_findOrAddVlak(re, UVTOINDEX(u, 0)); + vlr1= RE_findOrAddVlak(re, UVTOINDEX(u, sizev-1)); + VecAddf(vlr1->v2->n, vlr1->v2->n, vlr->n); + VecAddf(vlr1->v3->n, vlr1->v3->n, vlr->n); + VecAddf(vlr->v1->n, vlr->v1->n, vlr1->n); + VecAddf(vlr->v4->n, vlr->v4->n, vlr1->n); + } + } + /* last vertex is an extra case: + + ^ ()----()----()----() + | | | || | + u | |(0,n)||(0,0)| + | | || | + ()====()====[]====() + | | || | + | |(m,n)||(m,0)| + | | || | + ()----()----()----() + v -> + + vertex [] is no longer shared, therefore distribute + normals of the surrounding faces to all of the duplicates of [] + */ + + if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)) + { + vlr= RE_findOrAddVlak(re, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m,n) */ + vlr1= RE_findOrAddVlak(re, UVTOINDEX(0,0)); /* (0,0) */ + VecAddf(vn, vlr->n, vlr1->n); + vlr2= RE_findOrAddVlak(re, UVTOINDEX(0, sizev-1)); /* (0,n) */ + VecAddf(vn, vn, vlr2->n); + vlr3= RE_findOrAddVlak(re, UVTOINDEX(sizeu-1, 0)); /* (m,0) */ + VecAddf(vn, vn, vlr3->n); + VECCOPY(vlr->v3->n, vn); + VECCOPY(vlr1->v1->n, vn); + VECCOPY(vlr2->v2->n, vn); + VECCOPY(vlr3->v4->n, vn); + } + for(a = startvert; a < re->totvert; a++) { + ver= RE_findOrAddVert(re, a); + Normalise(ver->n); + } + + + } + + dl= dl->next; + } + freedisplist(&displist); +} + +static void init_render_curve(Render *re, Object *ob) +{ + extern Material defmaterial; // initrender.c + Curve *cu; + VertRen *ver; + VlakRen *vlr; + DispList *dl; + Material *matar[32]; + float len, *data, *fp, *orco=NULL; + float n[3], mat[4][4]; + int nr, startvert, startvlak, a, b; + int frontside, need_orco=0; + + cu= ob->data; + if(cu->nurb.first==NULL) return; + + /* no modifier call here, is in makedisp */ + + /* test displist */ + if(cu->disp.first==0) makeDispListCurveTypes(ob, 0); + dl= cu->disp.first; + if(cu->disp.first==0) return; + + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + + /* material array */ + memset(matar, 0, 4*32); + matar[0]= &defmaterial; + for(a=0; a<ob->totcol; a++) { + matar[a]= give_render_material(re, ob, a+1); + if(matar[a]->texco & TEXCO_ORCO) { + need_orco= 1; + } + } + + if(need_orco) orco= get_object_orco(re, ob); + + dl= cu->disp.first; + while(dl) { + if(dl->type==DL_INDEX3) { + int *index; + + startvert= re->totvert; + data= dl->verts; + + n[0]= ob->imat[0][2]; + n[1]= ob->imat[1][2]; + n[2]= ob->imat[2][2]; + Normalise(n); + + /* copy first, rotate later for comparision trick */ + for(a=0; a<dl->nr; a++, data+=3) { + ver= RE_findOrAddVert(re, re->totvert++); + VECCOPY(ver->co, data); + MTC_Mat4MulVecfl(mat, ver->co); + + if(ver->co[2] < 0.0) { + VECCOPY(ver->n, n); + ver->flag = 1; + } + else { + ver->n[0]= -n[0]; ver->n[1]= -n[1]; ver->n[2]= -n[2]; + ver->flag = 0; + } + + if (orco) { + ver->orco = orco; + orco += 3; + } + } + + startvlak= re->totvlak; + index= dl->index; + for(a=0; a<dl->parts; a++, index+=3) { + + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob = ob; + vlr->v1= RE_findOrAddVert(re, startvert+index[0]); + vlr->v2= RE_findOrAddVert(re, startvert+index[1]); + vlr->v3= RE_findOrAddVert(re, startvert+index[2]); + vlr->v4= NULL; + + if(vlr->v1->flag) { + VECCOPY(vlr->n, n); + } + else { + vlr->n[0]= -n[0]; vlr->n[1]= -n[1]; vlr->n[2]= -n[2]; + } + + vlr->mat= matar[ dl->col ]; + vlr->flag= 0; + if( (cu->flag & CU_NOPUNOFLIP) ) { + vlr->flag |= R_NOPUNOFLIP; + } + vlr->ec= 0; + vlr->lay= ob->lay; + } + } + else if (dl->type==DL_SURF) { + int p1,p2,p3,p4; + + fp= dl->verts; + startvert= re->totvert; + nr= dl->nr*dl->parts; + + while(nr--) { + ver= RE_findOrAddVert(re, re->totvert++); + + VECCOPY(ver->co, fp); + MTC_Mat4MulVecfl(mat, ver->co); + fp+= 3; + + if (orco) { + ver->orco = orco; + orco += 3; + } + } + + startvlak= re->totvlak; + + for(a=0; a<dl->parts; a++) { + + frontside= (a >= dl->nr/2); + + DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts); + p1+= startvert; + p2+= startvert; + p3+= startvert; + p4+= startvert; + + for(; b<dl->nr; b++) { + vlr= RE_findOrAddVlak(re, re->totvlak++); + vlr->ob= ob; + vlr->v1= RE_findOrAddVert(re, p2); + vlr->v2= RE_findOrAddVert(re, p1); + vlr->v3= RE_findOrAddVert(re, p3); + vlr->v4= RE_findOrAddVert(re, p4); + vlr->ec= ME_V2V3+ME_V3V4; + if(a==0) vlr->ec+= ME_V1V2; + + vlr->flag= dl->rt; + vlr->lay= ob->lay; + + /* this is not really scientific: the vertices + * 2, 3 en 4 seem to give better vertexnormals than 1 2 3: + * front and backside treated different!! + */ + + if(frontside) + CalcNormFloat(vlr->v2->co, vlr->v3->co, vlr->v4->co, vlr->n); + else + CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->n); + + vlr->mat= matar[ dl->col ]; + + p4= p3; + p3++; + p2= p1; + p1++; + } + } + + if (dl->bevelSplitFlag) { + for(a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++) + if(dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F))) + split_v_renderfaces(re, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U); + } + + /* vertex normals */ + for(a= startvlak; a<re->totvlak; a++) { + vlr= RE_findOrAddVlak(re, a); + + VecAddf(vlr->v1->n, vlr->v1->n, vlr->n); + VecAddf(vlr->v3->n, vlr->v3->n, vlr->n); + VecAddf(vlr->v2->n, vlr->v2->n, vlr->n); + VecAddf(vlr->v4->n, vlr->v4->n, vlr->n); + } + for(a=startvert; a<re->totvert; a++) { + ver= RE_findOrAddVert(re, a); + len= Normalise(ver->n); + if(len==0.0) ver->flag= 1; /* flag use, its only used in zbuf now */ + else ver->flag= 0; + } + for(a= startvlak; a<re->totvlak; a++) { + vlr= RE_findOrAddVlak(re, a); + if(vlr->v1->flag) VECCOPY(vlr->v1->n, vlr->n); + if(vlr->v2->flag) VECCOPY(vlr->v2->n, vlr->n); + if(vlr->v3->flag) VECCOPY(vlr->v3->n, vlr->n); + if(vlr->v4->flag) VECCOPY(vlr->v4->n, vlr->n); + } + } + + dl= dl->next; + } +} + +/* prevent phong interpolation for giving ray shadow errors (terminator problem) */ +static void set_phong_threshold(Render *re, Object *ob, int startface, int numface, int startvert, int numvert ) +{ +// VertRen *ver; + VlakRen *vlr; + float thresh= 0.0, dot; + int tot=0, i; + + /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger + are taken into account. This threshold is meant to work on smooth geometry, not + for extreme cases (ton) */ + + for(i=startface; i<startface+numface; i++) { + vlr= RE_findOrAddVlak(re, i); + if(vlr->flag & R_SMOOTH) { + dot= INPR(vlr->n, vlr->v1->n); + dot= ABS(dot); + if(dot>0.9) { + thresh+= dot; tot++; + } + dot= INPR(vlr->n, vlr->v2->n); + dot= ABS(dot); + if(dot>0.9) { + thresh+= dot; tot++; + } + + dot= INPR(vlr->n, vlr->v3->n); + dot= ABS(dot); + if(dot>0.9) { + thresh+= dot; tot++; + } + + if(vlr->v4) { + dot= INPR(vlr->n, vlr->v4->n); + dot= ABS(dot); + if(dot>0.9) { + thresh+= dot; tot++; + } + } + } + } + + if(tot) { + thresh/= (float)tot; + ob->smoothresh= cos(0.5*M_PI-acos(thresh)); + } +} + +static void init_render_object(Render *re, Object *ob) +{ + float mat[4][4]; + int startface, startvert; + + startface=re->totvlak; + startvert=re->totvert; + + ob->flag |= OB_DONE; + + if(ob->type==OB_LAMP) + add_render_lamp(re, ob, 1); + else if ELEM(ob->type, OB_FONT, OB_CURVE) + init_render_curve(re, ob); + else if(ob->type==OB_SURF) + init_render_surf(re, ob); + else if(ob->type==OB_MESH) + init_render_mesh(re, ob); + else if(ob->type==OB_MBALL) + init_render_mball(re, ob); + else { + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + } + + /* generic post process here */ + if(startvert!=re->totvert) { + + /* the exception below is because displace code now is in init_render_mesh call, + I will look at means to have autosmooth enabled for all object types + and have it as general postprocess, like displace */ + if (ob->type!=OB_MESH && test_for_displace(re, ob ) ) + do_displacement(re, ob, startface, re->totvlak-startface, startvert, re->totvert-startvert); + + /* phong normal interpolation can cause error in tracing (terminator prob) */ + ob->smoothresh= 0.0; + if( (re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW) ) + set_phong_threshold(re, ob, startface, re->totvlak-startface, startvert, re->totvert-startvert); + } +} + +void RE_Database_Free(Render *re) +{ + ShadBuf *shb; + Object *ob = NULL; + GroupObject *go; + unsigned long *ztile; + int b, v; + char *ctile; + + /* FREE */ + + if(re->memArena) { + BLI_memarena_free(re->memArena); + re->memArena = NULL; + } + + for(go= re->lights.first; go; go= go->next) { + struct LampRen *lar= go->lampren; + if(lar->shb) { + shb= lar->shb; + v= (shb->size*shb->size)/256; + ztile= shb->zbuf; + ctile= shb->cbuf; + for(b=0; b<v; b++, ztile++, ctile++) { + if(*ctile) MEM_freeN((void *) *ztile); + } + + MEM_freeN(shb->zbuf); + MEM_freeN(shb->cbuf); + MEM_freeN(lar->shb); + } + if(lar->jitter) MEM_freeN(lar->jitter); + MEM_freeN(lar); + } + + BLI_freelistN(&re->lights); + + free_renderdata_tables(re); + + /* free orco. check all objects because of duplis and sets */ + ob= G.main->object.first; + while(ob) { + if(ob->type==OB_MBALL) { + if(ob->disp.first && ob->disp.first!=ob->disp.last) { + DispList *dl= ob->disp.first; + BLI_remlink(&ob->disp, dl); + freedisplist(&ob->disp); + BLI_addtail(&ob->disp, dl); + } + } + ob= ob->id.next; + } + + free_mesh_orco_hash(re); + + end_radio_render(); + end_render_materials(); + + if(re->wrld.aosphere) { + MEM_freeN(re->wrld.aosphere); + re->wrld.aosphere= NULL; + re->scene->world->aosphere= NULL; + } + + if(re->r.mode & R_RAYTRACE) freeoctree(re); + + re->totvlak=re->totvert=re->totlamp=re->tothalo= 0; + re->i.convertdone= 0; + +} + +/* per face check if all samples should be taken. + if raytrace, do always for raytraced material, or when material full_osa set */ +static void set_fullsample_flag(Render *re) +{ + VlakRen *vlr; + int a, trace; + + trace= re->r.mode & R_RAYTRACE; + + for(a=re->totvlak-1; a>=0; a--) { + vlr= RE_findOrAddVlak(re, a); + + if(vlr->mat->mode & MA_FULL_OSA) vlr->flag |= R_FULL_OSA; + else if(trace) { + if(vlr->mat->mode & MA_SHLESS); + else if(vlr->mat->mode & (MA_RAYTRANSP|MA_RAYMIRROR|MA_SHADOW)) + vlr->flag |= R_FULL_OSA; + } + } +} + +/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp */ +#ifdef FLT_EPSILON +#undef FLT_EPSILON +#endif +#define FLT_EPSILON 1.19209290e-06F + + +static void check_non_flat_quads(Render *re) +{ + VlakRen *vlr, *vlr1; + VertRen *v1, *v2, *v3, *v4; + float nor[3], xn, flen; + int a; + + for(a=re->totvlak-1; a>=0; a--) { + vlr= RE_findOrAddVlak(re, a); + + /* test if rendering as a quad or triangle, skip wire */ + if(vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->mode & MA_WIRE)==0) { + + /* check if quad is actually triangle */ + v1= vlr->v1; + v2= vlr->v2; + v3= vlr->v3; + v4= vlr->v4; + VECSUB(nor, v1->co, v2->co); + if( ABS(nor[0])<FLT_EPSILON && ABS(nor[1])<FLT_EPSILON && ABS(nor[2])<FLT_EPSILON ) { + vlr->v1= v2; + vlr->v2= v3; + vlr->v3= v4; + vlr->v4= NULL; + } + else { + VECSUB(nor, v2->co, v3->co); + if( ABS(nor[0])<FLT_EPSILON && ABS(nor[1])<FLT_EPSILON && ABS(nor[2])<FLT_EPSILON ) { + vlr->v2= v3; + vlr->v3= v4; + vlr->v4= NULL; + } + else { + VECSUB(nor, v3->co, v4->co); + if( ABS(nor[0])<FLT_EPSILON && ABS(nor[1])<FLT_EPSILON && ABS(nor[2])<FLT_EPSILON ) { + vlr->v4= NULL; + } + else { + VECSUB(nor, v4->co, v1->co); + if( ABS(nor[0])<FLT_EPSILON && ABS(nor[1])<FLT_EPSILON && ABS(nor[2])<FLT_EPSILON ) { + vlr->v4= NULL; + } + } + } + } + + if(vlr->v4) { + + /* Face is divided along edge with the least gradient */ + /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */ + /* 4---3 4---3 */ + /* |\ 1| or |1 /| */ + /* |0\ | |/ 0| */ + /* 1---2 1---2 0 = orig face, 1 = new face */ + + /* render normals are inverted in render! we calculate normal of single tria here */ + flen= CalcNormFloat(vlr->v4->co, vlr->v3->co, vlr->v1->co, nor); + if(flen==0.0) CalcNormFloat(vlr->v4->co, vlr->v2->co, vlr->v1->co, nor); + + xn= nor[0]*vlr->n[0] + nor[1]*vlr->n[1] + nor[2]*vlr->n[2]; + if(ABS(xn) < 0.99995 ) { // checked on noisy fractal grid + float d1, d2; + + vlr1= RE_findOrAddVlak(re, re->totvlak++); + *vlr1= *vlr; + vlr1->flag |= R_FACE_SPLIT; + + /* split direction based on vnorms */ + CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, nor); + d1= nor[0]*vlr->v1->n[0] + nor[1]*vlr->v1->n[1] + nor[2]*vlr->v1->n[2]; + + CalcNormFloat(vlr->v2->co, vlr->v3->co, vlr->v4->co, nor); + d2= nor[0]*vlr->v2->n[0] + nor[1]*vlr->v2->n[1] + nor[2]*vlr->v2->n[2]; + + if( fabs(d1) < fabs(d2) ) vlr->flag |= R_DIVIDE_24; + else vlr->flag &= ~R_DIVIDE_24; + + /* new vertex pointers */ + if (vlr->flag & R_DIVIDE_24) { + vlr1->v1= vlr->v2; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr->v3 = vlr->v4; + + vlr1->flag |= R_DIVIDE_24; + } + else { + vlr1->v1= vlr->v1; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr1->flag &= ~R_DIVIDE_24; + } + vlr->v4 = vlr1->v4 = NULL; + + /* new normals */ + CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n); + CalcNormFloat(vlr1->v3->co, vlr1->v2->co, vlr1->v1->co, vlr1->n); + + /* so later UV can be pulled from original tface, look for R_DIVIDE_24 for direction */ + vlr1->tface=vlr->tface; + + } + /* clear the flag when not divided */ + else vlr->flag &= ~R_DIVIDE_24; + } + } + } +} + +static void set_material_lightgroups(Render *re) +{ + GroupObject *go, *gol; + Material *ma; + + /* it's a bit too many loops in loops... but will survive */ + for(ma= G.main->mat.first; ma; ma=ma->id.next) { + if(ma->group) { + for(go= ma->group->gobject.first; go; go= go->next) { + for(gol= re->lights.first; gol; gol= gol->next) { + if(gol->ob==go->ob) { + go->lampren= gol->lampren; + break; + } + } + } + } + } +} + +void init_render_world(Render *re) +{ + int a; + char *cp; + + if(re->scene && re->scene->world) { + re->wrld= *(re->scene->world); + + cp= (char *)&re->wrld.fastcol; + + cp[0]= 255.0*re->wrld.horr; + cp[1]= 255.0*re->wrld.horg; + cp[2]= 255.0*re->wrld.horb; + cp[3]= 1; + + VECCOPY(re->grvec, re->viewmat[2]); + Normalise(re->grvec); + Mat3CpyMat4(re->imat, re->viewinv); + + for(a=0; a<MAX_MTEX; a++) + if(re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX; + + while(re->wrld.aosamp*re->wrld.aosamp < re->osa) re->wrld.aosamp++; + } + else { + memset(&re->wrld, 0, sizeof(World)); + re->wrld.exp= 0.0; + re->wrld.range= 1.0; + } + + re->wrld.linfac= 1.0 + pow((2.0*re->wrld.exp + 0.5), -10); + re->wrld.logfac= log( (re->wrld.linfac-1.0)/re->wrld.linfac )/re->wrld.range; +} + +/* used to be 'rotate scene' */ +void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) +{ + extern int slurph_opt; /* key.c */ + GroupObject *go; + Base *base; + Object *ob; + Scene *sce; + unsigned int lay; + float mat[4][4]; + + re->scene= scene; + + /* XXX add test if dbase was filled already? */ + + re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + re->totvlak=re->totvert=re->totlamp=re->tothalo= 0; + re->lights.first= re->lights.last= NULL; + + slurph_opt= 0; + + /* in localview, lamps are using normal layers, objects only local bits */ + if(re->scene->lay & 0xFF000000) lay= re->scene->lay & 0xFF000000; + else lay= re->scene->lay; + + /* applies changes fully */ + scene_update_for_newframe(re->scene, lay); + + /* if no camera, viewmat should have been set! */ + if(use_camera_view && re->scene->camera) { + Mat4Ortho(re->scene->camera->obmat); + Mat4Invert(mat, re->scene->camera->obmat); + RE_SetView(re, mat); + } + + init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */ + if( (re->wrld.mode & WO_AMB_OCC) && (re->r.mode & R_RAYTRACE) ) { + re->wrld.aosphere= MEM_mallocN(2*3*re->wrld.aosamp*re->wrld.aosamp*sizeof(float), "AO sphere"); + /* we make twice the amount of samples, because only a hemisphere is used */ + init_ao_sphere(re->wrld.aosphere, 2*re->wrld.aosamp*re->wrld.aosamp, 16); + } + + /* still bad... doing all */ + init_render_textures(); + init_render_materials(re->osa, &re->wrld.ambr); + set_node_shader_lamp_loop(shade_material_loop); + + for(SETLOOPER(re->scene, base)) { + ob= base->object; + /* imat objects has to be done here, since displace can have texture using Object map-input */ + MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat); + MTC_Mat4Invert(ob->imat, mat); + /* each object should only be rendered once */ + ob->flag &= ~OB_DONE; + } + + /* MAKE RENDER DATA */ + + for(SETLOOPER(re->scene, base)) { + ob= base->object; + + if( (base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->scene->lay)) ) { + if(ob->transflag & OB_DUPLI) { + + /* exception: mballs! */ + /* yafray: Include at least one copy of a dupliframe object for yafray in the renderlist. + mballs comment above true as well for yafray, they are not included, only all other object types */ + if (re->r.renderer==R_YAFRAY) { + if ((ob->type!=OB_MBALL) && ((ob->transflag & OB_DUPLIFRAMES)!=0)) { + printf("Object %s has OB_DUPLIFRAMES set, adding to renderlist\n", ob->id.name); + init_render_object(re, ob); + } + } + /* before make duplis, update particle for current frame */ + if(ob->transflag & OB_DUPLIVERTS) { + PartEff *paf= give_parteff(ob); + if(paf) { + if(paf->flag & PAF_ANIMATED) build_particle_system(ob); + } + } + + if(ob->type==OB_MBALL) { + init_render_object(re, ob); + } + else { + DupliObject *dob; + ListBase *lb= object_duplilist(sce, ob); + + for(dob= lb->first; dob; dob= dob->next) { + Object *obd= dob->ob; + Mat4CpyMat4(obd->obmat, dob->mat); + + if(obd->type!=OB_MBALL) { + /* yafray: special handling of duplivert objects for yafray: + only the matrix is stored, together with the source object name. + Since the original object is needed as well, it is included in the renderlist (see above) + NOT done for lamps, these need to be included as normal lamps separately + correction: also ignore lattices, armatures and cameras (....) */ + if ((obd->type!=OB_LATTICE) && (obd->type!=OB_ARMATURE) && + (obd->type!=OB_LAMP) && (obd->type!=OB_CAMERA) && (re->r.renderer==R_YAFRAY)) + { + printf("Adding dupli matrix for object %s\n", obd->id.name); + YAF_addDupliMtx(obd); + } + else init_render_object(re, obd); + } + Mat4CpyMat4(obd->obmat, dob->omat); + } + BLI_freelistN(lb); + } + } + else { + /* yafray: if there are linked data objects (except lamps, empties or armatures), + yafray only needs to know about one, the rest can be instanciated. + The dupliMtx list is used for this purpose. + Exception: objects which have object linked materials, these cannot be instanciated. */ + if ((re->r.renderer==R_YAFRAY) && (ob->colbits==0)) + { + /* Special case, parent object dupli's: ignore if object itself is lamp or parent is lattice or empty */ + if (ob->parent) { + if ((ob->type!=OB_LAMP) && (ob->parent->type!=OB_EMPTY) && + (ob->parent->type!=OB_LATTICE) && YAF_objectKnownData(ob)) + printf("From parent: Added dupli matrix for linked data object %s\n", ob->id.name); + else + init_render_object(re, ob); + } + else if ((ob->type!=OB_EMPTY) && (ob->type!=OB_LAMP) && (ob->type!=OB_ARMATURE) && YAF_objectKnownData(ob)) + printf("Added dupli matrix for linked data object %s\n", ob->id.name); + else + init_render_object(re, ob); + } + else init_render_object(re, ob); + } + + } + + if(re->test_break()) break; + } + + + if(!re->test_break()) { + sort_halos(re); + + set_material_lightgroups(re); + + slurph_opt= 1; + + /* for now some clumsy copying still */ + re->i.totvert= re->totvert; + re->i.totface= re->totvlak; + re->i.tothalo= re->tothalo; + re->i.totlamp= re->totlamp; + re->stats_draw(&re->i); + + set_fullsample_flag(re); + check_non_flat_quads(re); + set_normalflags(re); + + /* SHADOW BUFFER */ + for(go=re->lights.first; go; go= go->next) { + LampRen *lar= go->lampren; + + if(re->test_break()) break; + if(lar->shb) { + makeshadowbuf(re, lar); + } + } + + /* yafray: 'direct' radiosity, environment maps and octree init not needed for yafray render */ + /* although radio mode could be useful at some point, later */ + if (re->r.renderer==R_INTERN) { + /* RADIO (uses no R anymore) */ + if(!re->test_break()) + if(re->r.mode & R_RADIO) do_radio_render(re); + + /* octree */ + if(!re->test_break()) + if(re->r.mode & R_RAYTRACE) makeoctree(re); + + /* ENVIRONMENT MAPS */ + if(!re->test_break()) + make_envmaps(re); + } + + if(!re->test_break()) + project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0); + } + + if(re->test_break()) + RE_Database_Free(re); + else + re->i.convertdone= 1; + +} + +/* exported call to recalculate hoco for vertices, when winmat changed */ +void RE_DataBase_ApplyWindow(Render *re) +{ + project_renderdata(re, projectverto, 0, 0); +} + +/* **************************************************************** */ +/* Displacement mapping */ +/* **************************************************************** */ +static short test_for_displace(Render *re, Object *ob) +{ + /* return 1 when this object uses displacement textures. */ + Material *ma; + int i; + + for (i=1; i<=ob->totcol; i++) { + ma=give_render_material(re, ob, i); + /* ma->mapto is ORed total of all mapto channels */ + if(ma && (ma->mapto & MAP_DISPLACE)) return 1; + } + return 0; +} + +static void displace_render_vert(Render *re, ShadeInput *shi, VertRen *vr, float *scale) +{ + short texco= shi->mat->texco; + float sample=0; + /* shi->co is current render coord, just make sure at least some vector is here */ + VECCOPY(shi->co, vr->co); + /* vertex normal is used for textures type 'col' and 'var' */ + VECCOPY(shi->vn, vr->n); + + /* set all rendercoords, 'texco' is an ORed value for all textures needed */ + if ((texco & TEXCO_ORCO) && (vr->orco)) { + VECCOPY(shi->lo, vr->orco); + } + if (texco & TEXCO_STICKY) { + float *sticky= RE_vertren_get_sticky(re, vr, 0); + if(sticky) { + shi->sticky[0]= sticky[0]; + shi->sticky[1]= sticky[1]; + shi->sticky[2]= 0.0f; + } + } + if (texco & TEXCO_GLOB) { + VECCOPY(shi->gl, shi->co); + MTC_Mat4MulVecfl(re->viewinv, shi->gl); + } + if (texco & TEXCO_NORM) { + VECCOPY(shi->orn, shi->vn); + } + if(texco & TEXCO_REFL) { + /* not (yet?) */ + } + + shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0; + + do_material_tex(shi); + + //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2], + //vr->co[0], vr->co[1], vr->co[2]); + + /* 0.5 could become button once? */ + vr->co[0] += shi->displace[0] * scale[0] ; + vr->co[1] += shi->displace[1] * scale[1] ; + vr->co[2] += shi->displace[2] * scale[2] ; + + //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]); + + /* we just don't do this vertex again, bad luck for other face using same vertex with + different material... */ + vr->flag |= 1; + + /* Pass sample back so displace_face can decide which way to split the quad */ + sample = shi->displace[0]*shi->displace[0]; + sample += shi->displace[1]*shi->displace[1]; + sample += shi->displace[2]*shi->displace[2]; + + vr->accum=sample; + /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */ + return; +} + +static void displace_render_face(Render *re, VlakRen *vlr, float *scale) +{ + ShadeInput shi; + // VertRen vr; + // float samp1,samp2, samp3, samp4, xn; + short hasuv=0; + /* set up shadeinput struct for multitex() */ + + shi.osatex= 0; /* signal not to use dx[] and dy[] texture AA vectors */ + shi.vlr= vlr; /* current render face */ + shi.mat= vlr->mat; /* current input material */ + + + /* UV coords must come from face */ + hasuv = vlr->tface && (shi.mat->texco & TEXCO_UV); + if (hasuv) shi.uv[2]=0.0f; + /* I don't think this is used, but seting it just in case */ + + /* Displace the verts, flag is set when done */ + if (! (vlr->v1->flag)){ + if (hasuv) { + shi.uv[0] = 2*vlr->tface->uv[0][0]-1.0f; /* shi.uv and tface->uv are */ + shi.uv[1]= 2*vlr->tface->uv[0][1]-1.0f; /* scalled differently */ + } + displace_render_vert(re, &shi, vlr->v1, scale); + } + + if (! (vlr->v2->flag)) { + if (hasuv) { + shi.uv[0] = 2*vlr->tface->uv[1][0]-1.0f; + shi.uv[1]= 2*vlr->tface->uv[1][1]-1.0f; + } + displace_render_vert(re, &shi, vlr->v2, scale); + } + + if (! (vlr->v3->flag)) { + if (hasuv) { + shi.uv[0] = 2*vlr->tface->uv[2][0]-1.0f; + shi.uv[1]= 2*vlr->tface->uv[2][1]-1.0f; + } + displace_render_vert(re, &shi, vlr->v3, scale); + } + + if (vlr->v4) { + if (! (vlr->v4->flag)) { + if (hasuv) { + shi.uv[0] = 2*vlr->tface->uv[3][0]-1.0f; + shi.uv[1]= 2*vlr->tface->uv[3][1]-1.0f; + } + displace_render_vert(re, &shi, vlr->v4, scale); + } + /* We want to split the quad along the opposite verts that are */ + /* closest in displace value. This will help smooth edges. */ + if ( fabs(vlr->v1->accum - vlr->v3->accum) > fabs(vlr->v2->accum - vlr->v4->accum)) + vlr->flag |= R_DIVIDE_24; + else vlr->flag &= ~R_DIVIDE_24; // E: typo?, was missing '=' + } + + /* Recalculate the face normal - if flipped before, flip now */ + if(vlr->v4) { + CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n); + } + else { + CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n); + } + +} + + +static void do_displacement(Render *re, Object *ob, int startface, int numface, int startvert, int numvert ) +{ + VertRen *vr; + VlakRen *vlr; +// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30}; + float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn + int i; //, texflag=0; + Object *obt; + + /* Object Size with parenting */ + obt=ob; + while(obt){ + VecAddf(temp, obt->size, obt->dsize); + scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2]; + obt=obt->parent; + } + + /* Clear all flags */ + for(i=startvert; i<startvert+numvert; i++){ + vr= RE_findOrAddVert(re, i); + vr->flag= 0; + } + + for(i=startface; i<startface+numface; i++){ + vlr=RE_findOrAddVlak(re, i); + displace_render_face(re, vlr, scale); + } + + /* Recalc vertex normals */ + calc_vertexnormals(re, startvert, startface, 0); +} + diff --git a/source/blender/render/intern/source/edgeRender.c b/source/blender/render/intern/source/edgeRender.c index 7bf3b7f3e09..7d15e3f8145 100644 --- a/source/blender/render/intern/source/edgeRender.c +++ b/source/blender/render/intern/source/edgeRender.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,12 +20,12 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: 2004/2005/2006 Blender Foundation, full recode * - * Contributor(s): none yet. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** - * Add enhanced edges on a rendered image (toon shading, edge shading). + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Add enhanced edges on a rendered image (toon shading, edge shading). */ /* @@ -58,29 +55,25 @@ #include <limits.h> /* INT_MIN,MAX are used here */ #include <stdio.h> +#include "DNA_material_types.h" + #include "MEM_guardedalloc.h" #include "MTC_vectorops.h" #include "BKE_utildefines.h" +#include "BLI_jitter.h" -#include "RE_callbacks.h" +#include "render_types.h" +#include "renderpipeline.h" #include "edgeRender.h" -#include "render.h" #include "zbuf.h" /* for zbufclipwire and zbufclip */ -#include "jitter.h" - -#ifdef RE_EDGERENDERSAFE -char edgeRender_h[] = EDGERENDER_H; -char edgeRender_c[] = "$Id$"; -#include "errorHandler.h" -#endif -/* ------------------------------------------------------------------------- */ - /* These function pointers are used for z buffer filling. */ -extern float Zmulx, Zmuly; /* Some kind of scale? */ -extern float Zjitx,Zjity; /* The x,y values for jitter offset */ +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* ------------------------------------------------------------------------- */ /* exp: */ static Material** matBuffer; /* buffer with material indices */ @@ -111,64 +104,59 @@ static char edgeB; /** * Initialise the edge render buffer memory. */ -void initEdgeRenderBuffer(void); +static void initEdgeRenderBuffer(void); /** * Release buffer memory. */ -void freeEdgeRenderBuffer(void); +static void freeEdgeRenderBuffer(void); /** * Set all distances in the distance buffer to the maximum distance. */ -void resetDistanceBuffer(void); +static void resetDistanceBuffer(void); /** * Insert this distance at these pixel coordinates. */ -void insertInEdgeBuffer(int x, int y, int dist); +static void insertInEdgeBuffer(int x, int y, int dist); /** * Renders enhanced edges. Distances from distRect are used to * determine a correction on colourRect */ -void renderEdges(char * colourRect); +static void renderEdges(char * colourRect); /** * Buffer an edge between these two vertices in the e.r. distance buffer. */ -static void fillEdgeRenderEdge(int, float *vec1, float *vec2); +static void fillEdgeRenderEdge(ZSpan *zspan, int, float *vec1, float *vec2); /** * Buffer a face between these two vertices in the e.r. distance buffer. */ -static void fillEdgeRenderFace(struct ZSpan *zspan, int, float *v1, float *v2, float *v3); +static void fillEdgeRenderFace(struct ZSpan *zspan, int, float *v1, float *v2, float *v3, float *v4); /** * Compose the edge render colour buffer. */ -void calcEdgeRenderColBuf(char * tarbuf); +static void calcEdgeRenderColBuf(char * tarbuf); /** * Loop over all objects that need to be edge rendered. This loop determines * which objects get to be elected for edge rendering. */ -int zBufferEdgeRenderObjects(void); +static int zBufferEdgeRenderObjects(void); /** * Add edge pixels to the original image. It blends <bron> over <doel>. */ -void addEdgeOver(unsigned char *dst, unsigned char *src); +static void addEdgeOver(unsigned char *dst, unsigned char *src); /* ------------------------------------------------------------------------- */ -void addEdges( - char * targetbuf, - int iw, int ih, - int osanr, - short int intens, short int intens_redux, - int compat, int mode, - float r, float g, float b - ) +/* this is main call! */ +void addEdges(char * targetbuf, int iw, int ih, int osanr, + short int intens, short int intens_redux, int compat, int mode, float r, float g, float b) { float rf, gf ,bf; /* render parameters */ @@ -178,6 +166,10 @@ void addEdges( compatible_mode = compat; osaCount = osanr; intensity = intens; + + printf("Unsuported code!\n"); + return; + /* Reduction doesn't exceed intensity. */ same_mat_redux = ((intens_redux < intensity)? intens_redux : intensity); @@ -197,7 +189,7 @@ void addEdges( /* ------------------------------------------------------------------------- */ -void initEdgeRenderBuffer() +static void initEdgeRenderBuffer() { char *ptr; int i; @@ -230,16 +222,10 @@ void initEdgeRenderBuffer() } } -#ifdef RE_EDGERENDERSAFE - if (!edgeBuffer || !colBuffer) { - char *fname = "initEdgeRenderBuffer"; - RE_error(RE_CANNOT_ALLOCATE_MEMORY, fname); - } -#endif } /* end of void initEdgeRenderBuffer(void) */ /* ------------------------------------------------------------------------- */ -void freeEdgeRenderBuffer(void) +static void freeEdgeRenderBuffer(void) { if(edgeBuffer) MEM_freeN(edgeBuffer); edgeBuffer= NULL; @@ -251,7 +237,7 @@ void freeEdgeRenderBuffer(void) /* ------------------------------------------------------------------------- */ -void resetDistanceBuffer(void) +static void resetDistanceBuffer(void) { int i; for(i = 0; i < bufWidth * bufHeight; i++) edgeBuffer[i] = 0x7FFFFFFF; @@ -259,17 +245,9 @@ void resetDistanceBuffer(void) /* ------------------------------------------------------------------------- */ -void insertInEdgeBuffer(int x, int y, int dist) +static void insertInEdgeBuffer(int x, int y, int dist) { int index; -#ifdef RE_EDGERENDERSAFE - char *fname = "insertInEdgeBuffer"; - if ((x < 0) || (x > imWidth ) || - (y < 0) || (y > (imHeight-1) ) ) { - RE_error(RE_EDGERENDER_WRITE_OUTSIDE_BUFFER, fname); - return; - } -#endif /* +1? */ index = (y * bufWidth) + x + maskBorder; @@ -286,7 +264,7 @@ void insertInEdgeBuffer(int x, int y, int dist) /* ------------------------------------------------------------------------- */ /* Modelled after rendercore.c/edge_enhance() */ -void renderEdges(char *colourRect) +static void renderEdges(char *colourRect) { /* use zbuffer to define edges, add it to the image */ int val, y, x, col, *rz, *rz1, *rz2, *rz3; @@ -496,7 +474,7 @@ void renderEdges(char *colourRect) /* ------------------------------------------------------------------------- */ /* adds src to dst */ -void addEdgeOver(unsigned char *dst, unsigned char *src) +static void addEdgeOver(unsigned char *dst, unsigned char *src) { unsigned char inverse; unsigned char alpha; @@ -534,20 +512,15 @@ void addEdgeOver(unsigned char *dst, unsigned char *src) dst[2] = c; } -void calcEdgeRenderColBuf(char* colTargetBuffer) +static void calcEdgeRenderColBuf(char* colTargetBuffer) { - int keepLooping = 1; int sample; /* zbuffer fix: here? */ - Zmulx= ((float) imWidth)/2.0; - Zmuly= ((float) imHeight)/2.0; +// Zmulx= ((float) imWidth)/2.0; +// Zmuly= ((float) imHeight)/2.0; - /* use these buffer fill functions */ - zbuffunc = fillEdgeRenderFace; - zbuflinefunc = fillEdgeRenderEdge; - /* always buffer the max. extent */ Aminy = 0; Amaxy = imHeight; @@ -555,8 +528,8 @@ void calcEdgeRenderColBuf(char* colTargetBuffer) sample = 0; /* Zsample is used internally ! */ while ( (sample < osaCount) && keepLooping ) { /* jitter */ - Zjitx= -jit[sample][0]; - Zjity= -jit[sample][1]; +// Zjitx= -R.jit[sample][0]; +// Zjity= -R.jit[sample][1]; /* should reset dis buffer here */ resetDistanceBuffer(); @@ -567,7 +540,7 @@ void calcEdgeRenderColBuf(char* colTargetBuffer) /* do filtering */ renderEdges(colTargetBuffer); - if(RE_local_test_break()) keepLooping = 0; + if(R.test_break()) keepLooping = 0; sample++; } @@ -589,13 +562,28 @@ void calcEdgeRenderColBuf(char* colTargetBuffer) /* ------------------------------------------------------------------------- */ /* Clip flags etc. should still be set. When called in the span of 'normal' */ /* rendering, this should be ok. */ -int zBufferEdgeRenderObjects(void) +static int zBufferEdgeRenderObjects(void) { + ZSpan zspan; VlakRen *vlr= NULL; + Material *ma; unsigned int zvlnr; int keepLooping; int faceCounter; /* counter for face number */ - Material *ma; + + zbuf_alloc_span(&zspan, imWidth, imHeight); + + /* needed for transform from hoco to zbuffer co */ + zspan.zmulx= ((float)imWidth)/2.0; + zspan.zmuly= ((float)imHeight)/2.0; + zspan.zofsx= -0.5f; + zspan.zofsy= -0.5f; + + /* the buffers ??? */ + + /* filling methods */ + zspan.zbuffunc = fillEdgeRenderFace; + zspan.zbuflinefunc = fillEdgeRenderEdge; keepLooping = 1; ma = NULL; @@ -618,19 +606,19 @@ int zBufferEdgeRenderObjects(void) /* here we cull all transparent faces if mode == 0 */ if (selectmode || !(ma->mode & MA_ZTRA)) { /* here we can add all kinds of extra selection criteria */ - if(ma->mode & (MA_WIRE)) zbufclipwire(zvlnr, vlr); + if(ma->mode & (MA_WIRE)) zbufclipwire(&zspan, zvlnr, vlr); else { - zbufclip(NULL, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, + zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); if(vlr->v4) { zvlnr+= 0x800000; /* in a sense, the 'adjoint' face */ - zbufclip(NULL, zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, + zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v3->clip, vlr->v4->clip); } } } }; - if(RE_local_test_break()) keepLooping = 0; + if(R.test_break()) keepLooping = 0; faceCounter++; } return keepLooping; @@ -638,7 +626,7 @@ int zBufferEdgeRenderObjects(void) /* ------------------------------------------------------------------------- */ -static void fillEdgeRenderFace(struct ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) +static void fillEdgeRenderFace(struct ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) { /* Coordinates of the vertices are specified in ZCS */ double z0; /* used as temp var*/ @@ -846,7 +834,7 @@ static void fillEdgeRenderFace(struct ZSpan *zspan, int zvlnr, float *v1, float /* ------------------------------------------------------------------------- */ -static void fillEdgeRenderEdge(int zvlnr, float *vec1, float *vec2) +static void fillEdgeRenderEdge(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) { int start, end, x, y, oldx, oldy, ofs; int dz, vergz/* , mask */; diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 7c962ff1328..d38ff7d2d38 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -1,15 +1,12 @@ - -/* envmap.c RENDER +/* + * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,15 +20,9 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: 2004/2005/2006 Blender Foundation, full recode * - * Contributor(s): none yet. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** - * - * may 1999 - * - * $Id$ + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -55,8 +46,8 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_global.h" -#include "BKE_world.h" // init_render_world #include "BKE_image.h" // BKE_write_ibuf +#include "BKE_texture.h" #include "MTC_matrixops.h" @@ -65,81 +56,18 @@ #define main main /* stupid SDL_main redefines main as SDL_main */ /* this module */ -#include "RE_callbacks.h" -#include "render.h" +#include "render_types.h" +#include "renderpipeline.h" #include "envmap.h" -#include "mydevice.h" #include "rendercore.h" -#include "renderHelp.h" +#include "renderdatabase.h" #include "texture.h" #include "zbuf.h" +#include "initrender.h" /* ------------------------------------------------------------------------- */ -EnvMap *RE_add_envmap(void) -{ - EnvMap *env; - - env= MEM_callocN(sizeof(EnvMap), "envmap"); - env->type= ENV_CUBE; - env->stype= ENV_STATIC; - env->clipsta= 0.1; - env->clipend= 100.0; - env->cuberes= 100; - - return env; -} /* end of EnvMap *RE_add_envmap() */ - -/* ------------------------------------------------------------------------- */ - -EnvMap *RE_copy_envmap(EnvMap *env) -{ - EnvMap *envn; - int a; - - envn= MEM_dupallocN(env); - envn->ok= 0; - for(a=0; a<6; a++) envn->cube[a]= 0; - if(envn->ima) id_us_plus((ID *)envn->ima); - - return envn; -} - -/* ------------------------------------------------------------------------- */ - -void RE_free_envmapdata(EnvMap *env) -{ - Image *ima; - unsigned int a, part; - - for(part=0; part<6; part++) { - ima= env->cube[part]; - if(ima) { - if(ima->ibuf) IMB_freeImBuf(ima->ibuf); - - for(a=0; a<BLI_ARRAY_NELEMS(ima->mipmap); a++) { - if(ima->mipmap[a]) IMB_freeImBuf(ima->mipmap[a]); - } - MEM_freeN(ima); - env->cube[part]= 0; - } - } - env->ok= 0; -} - -/* ------------------------------------------------------------------------- */ - -void RE_free_envmap(EnvMap *env) -{ - - RE_free_envmapdata(env); - MEM_freeN(env); - -} - -/* ------------------------------------------------------------------------- */ - static void envmap_split_ima(EnvMap *env) { ImBuf *ibuf; @@ -147,7 +75,7 @@ static void envmap_split_ima(EnvMap *env) /* extern rectcpy(); */ int dx, part; - RE_free_envmapdata(env); + BKE_free_envmapdata(env); dx= env->ima->ibuf->y; dx/= 2; @@ -183,52 +111,76 @@ static void envmap_split_ima(EnvMap *env) /* ------------------------------------------------------------------------- */ /* ****************** RENDER ********************** */ -static void envmap_renderdata(EnvMap *env) +/* copy current render */ +static Render *envmap_render_copy(Render *re, EnvMap *env) { - extern void init_filt_mask(void); - static RE_Render envR; - static Object *camera; + Render *envre; int cuberes; - if(env) { - envR= R; - camera= G.scene->camera; - - cuberes = (env->cuberes * R.r.size) / 100; - cuberes &= 0xFFFC; - env->lastsize= R.r.size; - R.rectx= R.r.xsch= R.recty= R.r.ysch= cuberes; - R.afmx= R.afmy= R.r.xsch/2; - R.xstart= R.ystart= -R.afmx; - R.xend= R.yend= R.xstart+R.rectx-1; - - R.r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR); - R.r.filtertype= 0; - R.r.xparts= R.r.yparts= 1; - R.r.bufflag= 0; - R.r.size= 100; - R.ycor= 1.0; - R.r.yasp= R.r.xasp= 1; - - R.near= env->clipsta; - R.far= env->clipend; - - G.scene->camera= env->object; - - } - else { - /* this to make sure init_renderdisplay works */ - envR.winx= R.winx; - envR.winy= R.winy; - envR.winxof= R.winxof; - envR.winyof= R.winyof; - - R= envR; - G.scene->camera= camera; - } - - /* gauss, gamma, etc */ - init_filt_mask(); + envre= RE_NewRender("Envmap"); + + env->lastsize= re->r.size; + cuberes = (env->cuberes * re->r.size) / 100; + cuberes &= 0xFFFC; + + /* set up renderdata */ + envre->r= re->r; + envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR); + envre->r.filtertype= 0; + envre->r.xparts= envre->r.yparts= 1; + envre->r.bufflag= 0; + envre->r.size= 100; + envre->r.yasp= envre->r.xasp= 1; + + RE_InitState(envre, &re->r, cuberes, cuberes, NULL); + envre->scene= re->scene; /* unsure about this... */ + + /* view stuff in env render */ + envre->ycor= 1.0; + envre->clipsta= env->clipsta; /* render_scene_set_window() respects this for now */ + envre->clipend= env->clipend; + + RE_SetCamera(envre, env->object); + + /* callbacks */ + envre->display_draw= re->display_draw; + envre->test_break= re->test_break; + + /* and for the evil stuff; copy the database... */ + envre->totvlak= re->totvlak; + envre->totvert= re->totvert; + envre->tothalo= re->tothalo; + envre->totlamp= re->totlamp; + envre->lights= re->lights; + envre->vertnodeslen= re->vertnodeslen; + envre->vertnodes= re->vertnodes; + envre->blohalen= re->blohalen; + envre->bloha= re->bloha; + envre->blovllen= re->blovllen; + envre->blovl= re->blovl; + envre->oc= re->oc; + + return envre; +} + +static void envmap_free_render_copy(Render *envre) +{ + + envre->totvlak= 0; + envre->totvert= 0; + envre->tothalo= 0; + envre->totlamp= 0; + envre->lights.first= envre->lights.last= NULL; + envre->vertnodeslen= 0; + envre->vertnodes= NULL; + envre->blohalen= 0; + envre->bloha= NULL; + envre->blovllen= 0; + envre->blovl= NULL; + envre->oc.adrbranch= NULL; + envre->oc.adrnode= NULL; + + RE_FreeRender(envre); } /* ------------------------------------------------------------------------- */ @@ -265,7 +217,7 @@ static void envmap_transmatrix(float mat[][4], int part) /* ------------------------------------------------------------------------- */ -static void env_rotate_scene(float mat[][4], int mode) +static void env_rotate_scene(Render *re, float mat[][4], int mode) { GroupObject *go; VlakRen *vlr = NULL; @@ -284,8 +236,8 @@ static void env_rotate_scene(float mat[][4], int mode) MTC_Mat3CpyMat4(imat, mat); } - for(a=0; a<R.totvert; a++) { - if((a & 255)==0) ver= RE_findOrAddVert(a); + for(a=0; a<re->totvert; a++) { + if((a & 255)==0) ver= RE_findOrAddVert(re, a); else ver++; MTC_Mat4MulVecfl(tmat, ver->co); @@ -300,15 +252,15 @@ static void env_rotate_scene(float mat[][4], int mode) Normalise(ver->n); } - for(a=0; a<R.tothalo; a++) { - if((a & 255)==0) har= R.bloha[a>>8]; + for(a=0; a<re->tothalo; a++) { + if((a & 255)==0) har= re->bloha[a>>8]; else har++; MTC_Mat4MulVecfl(tmat, har->co); } - for(a=0; a<R.totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; + for(a=0; a<re->totvlak; a++) { + if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++; xn= vlr->n[0]; @@ -321,9 +273,9 @@ static void env_rotate_scene(float mat[][4], int mode) Normalise(vlr->n); } - set_normalflags(); + set_normalflags(re); - for(go=R.lights.first; go; go= go->next) { + for(go=re->lights.first; go; go= go->next) { lar= go->lampren; /* removed here some horrible code of someone in NaN who tried to fix @@ -355,25 +307,25 @@ static void env_rotate_scene(float mat[][4], int mode) /* ------------------------------------------------------------------------- */ -static void env_layerflags(unsigned int notlay) +static void env_layerflags(Render *re, unsigned int notlay) { VlakRen *vlr = NULL; int a; - for(a=0; a<R.totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; + for(a=0; a<re->totvlak; a++) { + if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++; if(vlr->lay & notlay) vlr->flag &= ~R_VISIBLE; } } -static void env_hideobject(Object *ob) +static void env_hideobject(Render *re, Object *ob) { VlakRen *vlr = NULL; int a; - for(a=0; a<R.totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; + for(a=0; a<re->totvlak; a++) { + if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++; if(vlr->ob == ob) vlr->flag &= ~R_VISIBLE; } @@ -381,14 +333,14 @@ static void env_hideobject(Object *ob) /* ------------------------------------------------------------------------- */ -static void env_set_imats() +static void env_set_imats(Render *re) { Base *base; float mat[4][4]; base= G.scene->base.first; while(base) { - MTC_Mat4MulMat4(mat, base->object->obmat, R.viewmat); + MTC_Mat4MulMat4(mat, base->object->obmat, re->viewmat); MTC_Mat4Invert(base->object->imat, mat); base= base->next; @@ -398,118 +350,97 @@ static void env_set_imats() /* ------------------------------------------------------------------------- */ -static void render_envmap(EnvMap *env) +static void render_envmap(Render *re, EnvMap *env) { /* only the cubemap is implemented */ + Render *envre; ImBuf *ibuf; Image *ima; float oldviewinv[4][4], mat[4][4], tmat[4][4]; short part; /* need a recalc: ortho-render has no correct viewinv */ - MTC_Mat4Invert(oldviewinv, R.viewmat); + MTC_Mat4Invert(oldviewinv, re->viewmat); - /* do first, envmap_renderdata copies entire R struct */ - if(R.rectz) MEM_freeN(R.rectz); - if(R.rectot) MEM_freeN(R.rectot); - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot= NULL; - R.rectz= NULL; - R.rectot= NULL; - - /* setup necessary globals */ - envmap_renderdata(env); + envre= envmap_render_copy(re, env); - RE_local_init_render_display(); - - R.rectot= MEM_mallocN(sizeof(int)*R.rectx*R.recty, "rectot"); - R.rectz= MEM_mallocN(sizeof(int)*R.rectx*R.recty, "rectz"); +// re->display_init(envre->result); for(part=0; part<6; part++) { - RE_local_clear_render_display(R.win); - fillrect(R.rectot, R.rectx, R.recty, 0); - - RE_setwindowclip(1,-1); /* no jit:(-1) */ + re->display_clear(envre->result); - MTC_Mat4CpyMat4(tmat, G.scene->camera->obmat); + MTC_Mat4CpyMat4(tmat, env->object->obmat); MTC_Mat4Ortho(tmat); envmap_transmatrix(tmat, part); MTC_Mat4Invert(mat, tmat); /* mat now is the camera 'viewmat' */ - MTC_Mat4CpyMat4(R.viewmat, mat); - MTC_Mat4CpyMat4(R.viewinv, tmat); + MTC_Mat4CpyMat4(envre->viewmat, mat); + MTC_Mat4CpyMat4(envre->viewinv, tmat); /* we have to correct for the already rotated vertexcoords */ - MTC_Mat4MulMat4(tmat, oldviewinv, R.viewmat); + MTC_Mat4MulMat4(tmat, oldviewinv, envre->viewmat); MTC_Mat4Invert(env->imat, tmat); - env_rotate_scene(tmat, 1); - init_render_world(); - setzbufvlaggen(RE_projectverto); - env_layerflags(env->notlay); - env_hideobject(env->object); - env_set_imats(); + env_rotate_scene(envre, tmat, 1); + init_render_world(envre); + project_renderdata(envre, projectverto, 0, 0); + env_layerflags(envre, env->notlay); + env_hideobject(envre, env->object); + env_set_imats(envre); - if(RE_local_test_break()==0) { - - RE_local_printrenderinfo(0.0, part); - - if(R.r.mode & R_OSA) zbufshadeDA(); - else zbufshade(); - + if(re->test_break()==0) { + RE_TileProcessor(envre); } /* rotate back */ - env_rotate_scene(tmat, 0); + env_rotate_scene(envre, tmat, 0); - if(RE_local_test_break()==0) { - ibuf= IMB_allocImBuf(R.rectx, R.recty, 24, IB_rect, 0); + if(re->test_break()==0) { + RenderLayer *rl= envre->result->layers.first; + + ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0); + ibuf->rect_float= rl->rectf; + IMB_rect_from_float(ibuf); + ibuf->rect_float= NULL; + ima= MEM_callocN(sizeof(Image), "image"); - memcpy(ibuf->rect, R.rectot, 4*ibuf->x*ibuf->y); + ima->ibuf= ibuf; ima->ok= 1; env->cube[part]= ima; } - if(RE_local_test_break()) break; + if(re->test_break()) break; } - if(R.rectz) MEM_freeN(R.rectz); - if(R.rectot) MEM_freeN(R.rectot); - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectz= NULL; - R.rectot= NULL; - R.rectftot= NULL; - - if(RE_local_test_break()) RE_free_envmapdata(env); + if(re->test_break()) BKE_free_envmapdata(env); else { - if(R.r.mode & R_OSA) env->ok= ENV_OSA; + if(envre->r.mode & R_OSA) env->ok= ENV_OSA; else env->ok= ENV_NORMAL; - env->lastframe= G.scene->r.cfra; + env->lastframe= G.scene->r.cfra; /* hurmf */ } /* restore */ - envmap_renderdata(0); - env_set_imats(); - init_render_world(); + envmap_free_render_copy(envre); + env_set_imats(re); } /* ------------------------------------------------------------------------- */ -void make_envmaps() +void make_envmaps(Render *re) { Tex *tex; int do_init= 0, depth= 0, trace; - if (!(R.r.mode & R_ENVMAP)) return; + if (!(re->r.mode & R_ENVMAP)) return; /* we dont raytrace, disabling the flag will cause ray_transp render solid */ - trace= (R.r.mode & R_RAYTRACE); - R.r.mode &= ~R_RAYTRACE; + trace= (re->r.mode & R_RAYTRACE); + re->r.mode &= ~R_RAYTRACE; /* 5 = hardcoded max recursion level */ while(depth<5) { @@ -527,21 +458,21 @@ void make_envmaps() if(tex->env->ok) { /* free when OSA, and old one isn't OSA */ - if((R.r.mode & R_OSA) && tex->env->ok==ENV_NORMAL) - RE_free_envmapdata(tex->env); + if((re->r.mode & R_OSA) && tex->env->ok==ENV_NORMAL) + BKE_free_envmapdata(tex->env); /* free when size larger */ - else if(tex->env->lastsize < R.r.size) - RE_free_envmapdata(tex->env); + else if(tex->env->lastsize < re->r.size) + BKE_free_envmapdata(tex->env); /* free when env is in recalcmode */ else if(tex->env->recalc) - RE_free_envmapdata(tex->env); + BKE_free_envmapdata(tex->env); } if(tex->env->ok==0 && depth==0) tex->env->recalc= 1; if(tex->env->ok==0) { do_init= 1; - render_envmap(tex->env); + render_envmap(re, tex->env); if(depth==tex->env->depth) tex->env->recalc= 0; } @@ -556,12 +487,12 @@ void make_envmaps() } if(do_init) { - RE_local_init_render_display(); - RE_local_clear_render_display(R.win); - R.flag |= R_REDRAW_PRV; + re->display_init(re->result); + re->display_clear(re->result); + re->flag |= R_REDRAW_PRV; } // restore - R.r.mode |= trace; + re->r.mode |= trace; } @@ -643,6 +574,7 @@ static void set_dxtdyt(float *dxts, float *dyts, float *dxt, float *dyt, int fac int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres) { extern SDL_mutex *load_ibuf_lock; // initrender.c + extern Render R; /* only in this call */ /* texvec should be the already reflected normal */ EnvMap *env; Image *ima; diff --git a/source/blender/render/intern/source/errorHandler.c b/source/blender/render/intern/source/errorHandler.c deleted file mode 100644 index 0ab927a9cd9..00000000000 --- a/source/blender/render/intern/source/errorHandler.c +++ /dev/null @@ -1,102 +0,0 @@ -/** - * $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 ***** - * Error handler for the rendering code. Maybe also useful elsewhere? - */ - -#include "GEN_messaging.h" -#include "stdio.h" - -#include "errorHandler.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/* ------------------------------------------------------------------------- */ - -/* counters for error handling */ -static int lastError; /* code of last encountered error */ -static int errorCount; /* count how many time it occured */ -/* ------------------------------------------------------------------------- */ - -char errorStrings[RE_MAX_ERROR][100] = { - "0: No error", - "1: recalculated depth falls outside original range", - "2: invalid face/halo type", - "3: invalid face index", - "4: invalid data pointer", - "5: generic trace counter", - "6: overflow on z buffer depth", - "7: write outside edgerender buffer", - "8: cannot allocate memory", - "9: write outside colour target buffer", -}; - -/* ------------------------------------------------------------------------- */ - -void RE_errortrace_reset(void) -{ - lastError = RE_NO_ERROR; - errorCount = 0; -} - -void RE_error(int errType, char* fname) -{ - /* - * This memory behaviour should move to the generic stream... - */ - - if (lastError == errType) { - int teller; - errorCount++; - for (teller = 0; teller < 12; teller++) - fprintf(GEN_errorstream, "%c", 0x08); /* backspaces */ - fprintf(GEN_errorstream, "( %8u )", errorCount); - } else { - fprintf(GEN_errorstream, "\n*** %s: %s ", - fname, errorStrings[errType]); - lastError = errType; - errorCount = 1; - } -} /* end of void RE_error(int errType, char* errText) */ - -/* ------------------------------------------------------------------------- */ -/* note: non-repeating */ -void RE_error_int(int errType, char* fname, int value) -{ - fprintf(GEN_errorstream, "\n*** %s: %s : %d", - fname, errorStrings[errType], value); - lastError = RE_NO_ERROR; -} /* end of void RE_error_int(int errType, char* errText, int value) */ - -/* ------------------------------------------------------------------------- */ - -/* eof */ diff --git a/source/blender/render/intern/source/gammaCorrectionTables.c b/source/blender/render/intern/source/gammaCorrectionTables.c index 9273aa899ee..812feabede7 100644 --- a/source/blender/render/intern/source/gammaCorrectionTables.c +++ b/source/blender/render/intern/source/gammaCorrectionTables.c @@ -43,10 +43,9 @@ /* WARNING; optimized, cannot be used to do gamma(invgamma()) and expect */ /* result remain identical (ton) */ -/* Default gamma. For most CRTs, gamma ranges from 2.2 to 2.5 (Foley), so */ -/* 2.35 seems appropriate enough. Experience teaches a different number */ -/* though. Old blender: 2.0. It might be nice to make this a slider */ +/* gamma is only used here for correcting adding colors or alpha */ #define RE_DEFAULT_GAMMA 2.0 + /* This 400 is sort of based on the number of intensity levels needed for */ /* the typical dynamic range of a medium, in this case CRTs. (Foley) */ /* (Actually, it says the number should be between 400 and 535.) */ @@ -63,8 +62,7 @@ static float colour_step; static float inv_colour_step; static float valid_gamma; static float valid_inv_gamma; -static int gamma_table_initialised = 0; -int do_gamma=0; + /* ------------------------------------------------------------------------- */ float gammaCorrect(float c) @@ -141,15 +139,9 @@ void makeGammaTables(float gamma) * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]) ; } - gamma_table_initialised = 1; } /* end of void makeGammaTables(float gamma) */ -/* ------------------------------------------------------------------------- */ -int gammaTableIsInitialised(void) -{ - return gamma_table_initialised; -} /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 479bf7190f7..6a59250b448 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -2,15 +2,12 @@ * * $Id: * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,9 +21,7 @@ * 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. + * Contributors: 2004/2005/2006 Blender Foundation, full recode * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -63,9 +58,15 @@ #include "SDL_thread.h" -#include "render.h" +#include "renderpipeline.h" +#include "render_types.h" #include "texture.h" +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int imaprepeat, imapextend; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index baa908cc9b2..c37b30a9bcb 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,11 +20,9 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: 2004/2005/2006 Blender Foundation, full recode * - * Contributor(s): none yet. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ @@ -38,22 +33,23 @@ #include <string.h> #include <stdio.h> -#include "blendef.h" #include "MEM_guardedalloc.h" #include "PIL_time.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" +#include "BLI_jitter.h" #include "BLI_rand.h" #include "MTC_matrixops.h" -#include "DNA_image_types.h" #include "DNA_camera_types.h" +#include "DNA_group_types.h" +#include "DNA_image_types.h" #include "DNA_lamp_types.h" -#include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_utildefines.h" #include "BKE_global.h" @@ -66,13 +62,6 @@ #include "BKE_writeavi.h" #include "BKE_scene.h" -#include "BIF_toolbox.h" -#include "BIF_writeavicodec.h" -#include "BIF_writemovie.h" /* start_movie(), append_movie(), end_movie() */ - -#include "BSE_drawview.h" -#include "BSE_sequence.h" - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -83,34 +72,33 @@ #include "SDL_thread.h" /* this module */ -#include "render.h" +#include "renderpipeline.h" +#include "render_types.h" -#include "RE_callbacks.h" -#include "zbuf.h" -#include "rendercore.h" /* part handler for the old renderer, shading functions */ +#include "rendercore.h" #include "pixelshading.h" -#include "renderPreAndPost.h" -#include "vanillaRenderPipe.h" -#include "renderHelp.h" -#include "jitter.h" #include "gammaCorrectionTables.h" -#include "zblur.h" +#include "zbuf.h" /* Own includes */ #include "initrender.h" -/* yafray: include for yafray export/render */ -#include "YafRay_Api.h" - -float centLut[16], *fmask1[9], *fmask2[9]; -unsigned short *gamtab, *igamtab2, *igamtab1; -char cmask[256], *centmask; +/* ********************** */ -Material defmaterial; - -/* ------- prototypes ----------- */ -void init_filt_mask(void); +static void init_render_jit(Render *re) +{ + static float jit[32][2]; /* simple caching */ + static int lastjit= 0; + + if(lastjit!=re->osa) { + memset(jit, 0, sizeof(jit)); + BLI_initjit(jit[0], re->osa); + } + + lastjit= re->osa; + memcpy(re->jit, jit, sizeof(jit)); +} /* ****************** GAMMA, MASKS and LUTS **************** */ @@ -165,48 +153,48 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */ return 0.0; } -static float calc_weight(float *weight, int i, int j) +static float calc_weight(Render *re, float *weight, int i, int j) { float x, y, dist, totw= 0.0; int a; - for(a=0; a<R.osa; a++) { - x= jit[a][0] + i; - y= jit[a][1] + j; + for(a=0; a<re->osa; a++) { + x= re->jit[a][0] + i; + y= re->jit[a][1] + j; dist= sqrt(x*x+y*y); weight[a]= 0.0; /* Weighting choices */ - switch(R.r.filtertype) { + switch(re->r.filtertype) { case R_FILTER_BOX: if(i==0 && j==0) weight[a]= 1.0; break; case R_FILTER_TENT: - if(dist < R.r.gauss) - weight[a]= R.r.gauss - dist; + if(dist < re->r.gauss) + weight[a]= re->r.gauss - dist; break; case R_FILTER_GAUSS: - x = dist*R.r.gauss; - weight[a]= (1.0/exp(x*x) - 1.0/exp(R.r.gauss*R.r.gauss*2.25)); + x = dist*re->r.gauss; + weight[a]= (1.0/exp(x*x) - 1.0/exp(re->r.gauss*re->r.gauss*2.25)); break; case R_FILTER_MITCH: - weight[a]= filt_mitchell(dist*R.r.gauss); + weight[a]= filt_mitchell(dist*re->r.gauss); break; case R_FILTER_QUAD: - weight[a]= filt_quadratic(dist*R.r.gauss); + weight[a]= filt_quadratic(dist*re->r.gauss); break; case R_FILTER_CUBIC: - weight[a]= filt_cubic(dist*R.r.gauss); + weight[a]= filt_cubic(dist*re->r.gauss); break; case R_FILTER_CATROM: - weight[a]= filt_catrom(dist*R.r.gauss); + weight[a]= filt_catrom(dist*re->r.gauss); break; } @@ -217,1416 +205,440 @@ static float calc_weight(float *weight, int i, int j) return totw; } -// extern called in render_envmap, to disable gauss... -// extern called in sequence.c, it needs the gamtab -void init_filt_mask(void) +void free_sample_tables(Render *re) { - static int firsttime=1; - static int lastosa=0; - static int lastfilter= -1; - static float lastgamma= 0.0f, lastgaussdist=0.0f; - float gamma, igamma, flweight[32], fmask[256]; + int a; + + if(re->samples) { + for(a=0; a<9; a++) { + MEM_freeN(re->samples->fmask1[a]); + MEM_freeN(re->samples->fmask2[a]); + } + + MEM_freeN(re->samples->centmask); + MEM_freeN(re->samples); + re->samples= NULL; + } +} + +/* based on settings in render, it makes the lookup tables */ +void make_sample_tables(Render *re) +{ + static int firsttime= 1; + SampleTables *st; + float flweight[32], fmask[256]; float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4; int i, j, a; + /* optimization tables, only once */ if(firsttime) { + makeGammaTables(2.0); /* tables only used for adding colors */ firsttime= 0; - - for(a=0; a<9;a++) { - fmask1[a]= MEM_mallocN(256*sizeof(float), "initfilt"); - fmask2[a]= MEM_mallocN(256*sizeof(float), "initfilt"); - } - for(a=0; a<256; a++) { - cmask[a]= 0; - if(a & 1) cmask[a]++; - if(a & 2) cmask[a]++; - if(a & 4) cmask[a]++; - if(a & 8) cmask[a]++; - if(a & 16) cmask[a]++; - if(a & 32) cmask[a]++; - if(a & 64) cmask[a]++; - if(a & 128) cmask[a]++; - } - centmask= MEM_mallocN(65536, "Initfilt3"); - for(a=0; a<16; a++) { - centLut[a]= -0.45+((float)a)/16.0; - } - - gamtab= MEM_mallocN(65536*sizeof(short), "initGaus2"); - igamtab1= MEM_mallocN(256*sizeof(short), "initGaus2"); - igamtab2= MEM_mallocN(65536*sizeof(short), "initGaus2"); - - return; // this case is called on startup } - - if(R.r.alphamode==R_ALPHAKEY) gamma= 1.0; /* gamma correction of alpha is nasty */ - else if(R.r.mode & R_GAMMA) gamma= 2.0; - else gamma= 1.0; - igamma= 1.0/gamma; - - if(gamma!= lastgamma) { - lastgamma= gamma; - - /* gamtab: in short, out short */ - for(a=0; a<65536; a++) { - val= a; - val/= 65535.0; - - if(gamma==2.0) val= sqrt(val); - else if(gamma!=1.0) val= pow(val, igamma); + free_sample_tables(re); + + if(re->osa==0) { + /* just prevents cpu cycles for larger render and copying */ + re->r.filtertype= 0; + return; + } + + re->do_gamma= 0; + if(re->r.mode & R_GAMMA) { + if(re->r.alphamode!=R_ALPHAKEY) /* alpha corrected gamma doesnt work for key alpha */ + re->do_gamma= 1; + } + + init_render_jit(re); - gamtab[a]= (65535.99*val); - } - /* inverse gamtab1 : in byte, out short */ - for(a=1; a<=256; a++) { - if(gamma==2.0) igamtab1[a-1]= a*a-1; - else if(gamma==1.0) igamtab1[a-1]= 256*a-1; - else { - val= a/256.0; - igamtab1[a-1]= (65535.0*pow(val, gamma)) -1 ; - } - } + st= re->samples= MEM_callocN(sizeof(SampleTables), "sample tables"); + + for(a=0; a<9;a++) { + st->fmask1[a]= MEM_callocN(256*sizeof(float), "initfilt"); + st->fmask2[a]= MEM_callocN(256*sizeof(float), "initfilt"); + } + for(a=0; a<256; a++) { + st->cmask[a]= 0; + if(a & 1) st->cmask[a]++; + if(a & 2) st->cmask[a]++; + if(a & 4) st->cmask[a]++; + if(a & 8) st->cmask[a]++; + if(a & 16) st->cmask[a]++; + if(a & 32) st->cmask[a]++; + if(a & 64) st->cmask[a]++; + if(a & 128) st->cmask[a]++; + } + + st->centmask= MEM_mallocN((1<<re->osa), "Initfilt3"); + + for(a=0; a<16; a++) { + st->centLut[a]= -0.45+((float)a)/16.0; + } - /* inverse gamtab2 : in short, out short */ - for(a=0; a<65536; a++) { - val= a; - val/= 65535.0; - if(gamma==2.0) val= val*val; - else val= pow(val, gamma); + val= 1.0/((float)re->osa); + for(a=0; a<256; a++) { + fmask[a]= ((float)st->cmask[a])*val; + } - igamtab2[a]= 65535.0*val; + /* calculate totw */ + totw= 0.0; + for(j= -1; j<2; j++) { + for(i= -1; i<2; i++) { + totw+= calc_weight(re, weight, i, j); } } - if(R.osa && (lastosa!=R.osa || lastfilter != (R.r.filtertype) || lastgaussdist!=R.r.gauss)) { - lastosa= R.osa; - lastfilter= R.r.filtertype; - lastgaussdist= R.r.gauss; - - val= 1.0/((float)R.osa); - for(a=0; a<256; a++) { - fmask[a]= ((float)cmask[a])*val; - } + for(j= -1; j<2; j++) { + for(i= -1; i<2; i++) { + /* calculate using jit, with offset the weights */ - for(a=0; a<9;a++) { - memset(fmask1[a], 0, 256*sizeof(float)); - memset(fmask2[a], 0, 256*sizeof(float)); - } + memset(weight, 0, sizeof(weight)); + calc_weight(re, weight, i, j); - /* calculate totw */ - totw= 0.0; - for(j= -1; j<2; j++) { - for(i= -1; i<2; i++) { - totw+= calc_weight(weight, i, j); - } - } + for(a=0; a<16; a++) flweight[a]= weight[a]*(1.0/totw); - for(j= -1; j<2; j++) { - for(i= -1; i<2; i++) { - /* calculate using jit, with offset the weights */ - - memset(weight, 0, sizeof(weight)); - calc_weight(weight, i, j); - - for(a=0; a<16; a++) flweight[a]= weight[a]*(1.0/totw); - - m3= fmask1[ 3*(j+1)+i+1 ]; - m4= fmask2[ 3*(j+1)+i+1 ]; - - for(a=0; a<256; a++) { - if(a & 1) { - m3[a]+= flweight[0]; - m4[a]+= flweight[8]; - } - if(a & 2) { - m3[a]+= flweight[1]; - m4[a]+= flweight[9]; - } - if(a & 4) { - m3[a]+= flweight[2]; - m4[a]+= flweight[10]; - } - if(a & 8) { - m3[a]+= flweight[3]; - m4[a]+= flweight[11]; - } - if(a & 16) { - m3[a]+= flweight[4]; - m4[a]+= flweight[12]; - } - if(a & 32) { - m3[a]+= flweight[5]; - m4[a]+= flweight[13]; - } - if(a & 64) { - m3[a]+= flweight[6]; - m4[a]+= flweight[14]; - } - if(a & 128) { - m3[a]+= flweight[7]; - m4[a]+= flweight[15]; - } - } - } - } + m3= st->fmask1[ 3*(j+1)+i+1 ]; + m4= st->fmask2[ 3*(j+1)+i+1 ]; - /* centmask: the correct subpixel offset per mask */ - - fpx1= MEM_mallocN(256*sizeof(float), "initgauss4"); - fpx2= MEM_mallocN(256*sizeof(float), "initgauss4"); - fpy1= MEM_mallocN(256*sizeof(float), "initgauss4"); - fpy2= MEM_mallocN(256*sizeof(float), "initgauss4"); - for(a=0; a<256; a++) { - fpx1[a]= fpx2[a]= 0.0; - fpy1[a]= fpy2[a]= 0.0; - if(a & 1) { - fpx1[a]+= jit[0][0]; - fpy1[a]+= jit[0][1]; - fpx2[a]+= jit[8][0]; - fpy2[a]+= jit[8][1]; - } - if(a & 2) { - fpx1[a]+= jit[1][0]; - fpy1[a]+= jit[1][1]; - fpx2[a]+= jit[9][0]; - fpy2[a]+= jit[9][1]; - } - if(a & 4) { - fpx1[a]+= jit[2][0]; - fpy1[a]+= jit[2][1]; - fpx2[a]+= jit[10][0]; - fpy2[a]+= jit[10][1]; - } - if(a & 8) { - fpx1[a]+= jit[3][0]; - fpy1[a]+= jit[3][1]; - fpx2[a]+= jit[11][0]; - fpy2[a]+= jit[11][1]; - } - if(a & 16) { - fpx1[a]+= jit[4][0]; - fpy1[a]+= jit[4][1]; - fpx2[a]+= jit[12][0]; - fpy2[a]+= jit[12][1]; - } - if(a & 32) { - fpx1[a]+= jit[5][0]; - fpy1[a]+= jit[5][1]; - fpx2[a]+= jit[13][0]; - fpy2[a]+= jit[13][1]; - } - if(a & 64) { - fpx1[a]+= jit[6][0]; - fpy1[a]+= jit[6][1]; - fpx2[a]+= jit[14][0]; - fpy2[a]+= jit[14][1]; - } - if(a & 128) { - fpx1[a]+= jit[7][0]; - fpy1[a]+= jit[7][1]; - fpx2[a]+= jit[15][0]; - fpy2[a]+= jit[15][1]; + for(a=0; a<256; a++) { + if(a & 1) { + m3[a]+= flweight[0]; + m4[a]+= flweight[8]; + } + if(a & 2) { + m3[a]+= flweight[1]; + m4[a]+= flweight[9]; + } + if(a & 4) { + m3[a]+= flweight[2]; + m4[a]+= flweight[10]; + } + if(a & 8) { + m3[a]+= flweight[3]; + m4[a]+= flweight[11]; + } + if(a & 16) { + m3[a]+= flweight[4]; + m4[a]+= flweight[12]; + } + if(a & 32) { + m3[a]+= flweight[5]; + m4[a]+= flweight[13]; + } + if(a & 64) { + m3[a]+= flweight[6]; + m4[a]+= flweight[14]; + } + if(a & 128) { + m3[a]+= flweight[7]; + m4[a]+= flweight[15]; + } } } - - for(a= (1<<R.osa)-1; a>0; a--) { - val= count_mask(a); - i= 8+(15.9*(fpy1[a & 255]+fpy2[a>>8])/val); - CLAMP(i, 0, 15); - j= 8+(15.9*(fpx1[a & 255]+fpx2[a>>8])/val); - CLAMP(j, 0, 15); - i= j + (i<<4); - centmask[a]= i; - } - - MEM_freeN(fpx1); - MEM_freeN(fpx2); - MEM_freeN(fpy1); - MEM_freeN(fpy2); } -} -static void free_filt_mask() -{ - int a; - - for(a=0; a<9; a++) { - MEM_freeN(fmask1[a]); - MEM_freeN(fmask2[a]); - } - MEM_freeN(gamtab); - MEM_freeN(igamtab1); - MEM_freeN(igamtab2); - - MEM_freeN(centmask); + /* centmask: the correct subpixel offset per mask */ + + fpx1= MEM_mallocN(256*sizeof(float), "initgauss4"); + fpx2= MEM_mallocN(256*sizeof(float), "initgauss4"); + fpy1= MEM_mallocN(256*sizeof(float), "initgauss4"); + fpy2= MEM_mallocN(256*sizeof(float), "initgauss4"); + for(a=0; a<256; a++) { + fpx1[a]= fpx2[a]= 0.0; + fpy1[a]= fpy2[a]= 0.0; + if(a & 1) { + fpx1[a]+= re->jit[0][0]; + fpy1[a]+= re->jit[0][1]; + fpx2[a]+= re->jit[8][0]; + fpy2[a]+= re->jit[8][1]; + } + if(a & 2) { + fpx1[a]+= re->jit[1][0]; + fpy1[a]+= re->jit[1][1]; + fpx2[a]+= re->jit[9][0]; + fpy2[a]+= re->jit[9][1]; + } + if(a & 4) { + fpx1[a]+= re->jit[2][0]; + fpy1[a]+= re->jit[2][1]; + fpx2[a]+= re->jit[10][0]; + fpy2[a]+= re->jit[10][1]; + } + if(a & 8) { + fpx1[a]+= re->jit[3][0]; + fpy1[a]+= re->jit[3][1]; + fpx2[a]+= re->jit[11][0]; + fpy2[a]+= re->jit[11][1]; + } + if(a & 16) { + fpx1[a]+= re->jit[4][0]; + fpy1[a]+= re->jit[4][1]; + fpx2[a]+= re->jit[12][0]; + fpy2[a]+= re->jit[12][1]; + } + if(a & 32) { + fpx1[a]+= re->jit[5][0]; + fpy1[a]+= re->jit[5][1]; + fpx2[a]+= re->jit[13][0]; + fpy2[a]+= re->jit[13][1]; + } + if(a & 64) { + fpx1[a]+= re->jit[6][0]; + fpy1[a]+= re->jit[6][1]; + fpx2[a]+= re->jit[14][0]; + fpy2[a]+= re->jit[14][1]; + } + if(a & 128) { + fpx1[a]+= re->jit[7][0]; + fpy1[a]+= re->jit[7][1]; + fpx2[a]+= re->jit[15][0]; + fpy2[a]+= re->jit[15][1]; + } + } + + for(a= (1<<re->osa)-1; a>0; a--) { + val= st->cmask[a & 255] + st->cmask[a>>8]; + i= 8+(15.9*(fpy1[a & 255]+fpy2[a>>8])/val); + CLAMP(i, 0, 15); + j= 8+(15.9*(fpx1[a & 255]+fpx2[a>>8])/val); + CLAMP(j, 0, 15); + i= j + (i<<4); + st->centmask[a]= i; + } + + MEM_freeN(fpx1); + MEM_freeN(fpx2); + MEM_freeN(fpy1); + MEM_freeN(fpy2); } -/* ********************* init calls *********************** */ -static void init_def_material(void) -{ - Material *ma; - - ma= &defmaterial; - - init_material(&defmaterial); - - init_render_material(ma); -} +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* this is called in creator.c, on startup */ -void RE_init_render_data(void) +/* call this after InitState() */ +/* per render, there's one persistant viewplane. Parts will set their own viewplanes */ +void RE_SetCamera(Render *re, Object *camera) { - memset(&R, 0, sizeof(RE_Render)); + Camera *cam=NULL; + rctf viewplane; + float pixsize, clipsta, clipend; + float lens; + float xd, yd; + int blursample= 0; /* make new call for that */ - RE_init_vertex_tables(); - R.blovl= (VlakRen **)MEM_callocN(sizeof(void *)*(TABLEINITSIZE),"Blovl"); - R.bloha= (HaloRen **)MEM_callocN(sizeof(void *)*(TABLEINITSIZE),"Bloha"); + /* question mark */ + re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp); - init_def_material(); - init_filt_mask(); -} - -/* called in usiblender.c on exit, also for blender -b render */ -void RE_free_render_data() -{ - MEM_freeN(R.vertnodes); - R.vertnodes= NULL; - MEM_freeN(R.blovl); - R.blovl= NULL; - MEM_freeN(R.bloha); - R.bloha= NULL; - - if(R.rectot) MEM_freeN(R.rectot); - if(R.rectftot) MEM_freeN(R.rectftot); - if(R.rectz) MEM_freeN(R.rectz); - if(R.rectzf) MEM_freeN(R.rectzf); - if(R.rectspare) MEM_freeN(R.rectspare); - R.rectot= NULL; - R.rectftot= NULL; - R.rectz= NULL; - R.rectzf= NULL; - R.rectspare= NULL; - - free_filt_mask(); -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -void RE_make_existing_file(char *name) -{ - char di[FILE_MAXDIR], fi[FILE_MAXFILE]; - - strcpy(di, name); - BLI_splitdirstring(di, fi); - - /* test exist */ - if (BLI_exists(di) == 0) { - BLI_recurdir_fileops(di); + if(camera->type==OB_CAMERA) { + cam= camera->data; + + if(cam->type==CAM_ORTHO) re->r.mode |= R_ORTHO; + + lens= cam->lens; + clipsta= cam->clipsta; + clipend= cam->clipend; } -} + else if(camera->type==OB_LAMP) { + /* fac= cos( PI*((float)(256- la->spsi))/512.0 ); */ - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -void RE_setwindowclip(int mode, int jmode) -{ - extern float bluroffsx, bluroffsy; // rendercore.c... hackish (ton) - Camera *cam=NULL; - float lens, minx, miny, maxx, maxy; - float xd, yd, afmx, afmy; - - if(G.scene->camera==NULL) return; - - afmx= R.afmx; - afmy= R.afmy; - - if(mode) { - - if(G.scene->camera->type==OB_LAMP) { - /* fac= cos( PI*((float)(256- la->spsi))/512.0 ); */ - - /* phi= acos(fac); */ - /* lens= 16.0*fac/sin(phi); */ - lens= 35.0; - R.near= 0.1; - R.far= 1000.0; + /* phi= acos(fac); */ + /* lens= 16.0*fac/sin(phi); */ + lens= 35.0; + clipsta= 0.1; + clipend= 1000.0; + } + else { /* envmap exception, can be done better... */ + lens= 16.0; + clipsta= re->clipsta; + clipend= re->clipend; + if(clipsta==0.0f || clipend==0.0f) { + clipsta= 0.1; + clipend= 1000.0; } - else if(G.scene->camera->type==OB_CAMERA) { - cam= G.scene->camera->data; + } - lens= cam->lens; - R.near= cam->clipsta; - R.far= cam->clipend; + /* ortho only with camera available */ + if(re->r.mode & R_ORTHO) { + if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) { + re->viewfac= re->winx; } else { - lens= 16.0; + re->viewfac= re->ycor*re->winy; } - - if(R.r.mode & R_ORTHO) { - if( (R.r.xasp*afmx) >= (R.r.yasp*afmy) ) { - R.viewfac= 2.0*afmx; - } - else { - R.viewfac= 2.0*R.ycor*afmy; - } - /* ortho_scale == 1.0 means exact 1 to 1 mapping */ - R.pixsize= cam->ortho_scale/R.viewfac; + /* ortho_scale == 1.0 means exact 1 to 1 mapping */ + pixsize= cam->ortho_scale/re->viewfac; + } + else { + if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) { + re->viewfac= (re->winx*lens)/32.0; } else { - if( (R.r.xasp*afmx) >= (R.r.yasp*afmy) ) { - R.viewfac= (afmx*lens)/16.0; - } - else { - R.viewfac= R.ycor*(afmy*lens)/16.0; - } - - R.pixsize= R.near/R.viewfac; + re->viewfac= re->ycor*(re->winy*lens)/32.0; } - /* pixsize is not a real global... get rid of it! (ton) */ + pixsize= clipsta/re->viewfac; } - + /* revision / simplification of subpixel offsets: - the matrix will go without offset from start (e.g. -100) to end (e.g. +99). - filling in with zbuffer will set offset of 0.5. to make sure clipped faces fill in too - in shadepixel() again that 0.5 offset is corrected */ - minx= R.xstart; - miny= R.ycor*(R.ystart); - maxx= R.xend; - maxy= R.ycor*(R.yend); - - if(R.flag & R_SEC_FIELD) { - if(R.r.mode & R_ODDFIELD) { - miny-= .5*R.ycor; - maxy-= .5*R.ycor; + viewplane.xmin= -0.5f*(float)re->winx; + viewplane.ymin= -0.5f*re->ycor*(float)re->winy; + viewplane.xmax= 0.5f*(float)re->winx; + viewplane.ymax= 0.5f*re->ycor*(float)re->winy; + + if(re->flag & R_SEC_FIELD) { + if(re->r.mode & R_ODDFIELD) { + viewplane.ymin-= .5*re->ycor; + viewplane.ymax-= .5*re->ycor; } else { - miny+= .5*R.ycor; - maxy+= .5*R.ycor; + viewplane.ymin+= .5*re->ycor; + viewplane.ymax+= .5*re->ycor; } } xd= yd= 0.0; - if(jmode!= -1) { - bluroffsx= xd= jit[jmode % R.osa][0]; - bluroffsy= yd= R.ycor*jit[jmode % R.osa][1]; + if(blursample!= -1) { + re->bluroffsx= xd= re->jit[blursample % re->osa][0]; + re->bluroffsy= yd= re->ycor*re->jit[blursample % re->osa][1]; } - else bluroffsx=bluroffsy= 0.0; + else re->bluroffsx=re->bluroffsy= 0.0f; - minx= R.pixsize*(minx+xd); - maxx= R.pixsize*(maxx+xd); - miny= R.pixsize*(miny+yd); - maxy= R.pixsize*(maxy+yd); - - if(R.r.mode & R_ORTHO) - i_ortho(minx, maxx, miny, maxy, R.near, R.far, R.winmat); + viewplane.xmin= pixsize*(viewplane.xmin+xd); + viewplane.xmax= pixsize*(viewplane.xmax+xd); + viewplane.ymin= pixsize*(viewplane.ymin+yd); + viewplane.ymax= pixsize*(viewplane.ymax+yd); + + re->viewdx= pixsize; + re->viewdy= re->ycor*pixsize; + + if(re->r.mode & R_ORTHO) + RE_SetOrtho(re, &viewplane, clipsta, clipend); else - i_window(minx, maxx, miny, maxy, R.near, R.far, R.winmat); + RE_SetWindow(re, &viewplane, clipsta, clipend); - //printmatrix4("win", R.winmat); + //printmatrix4("win", re->winmat); } -/* ~~~~~~~~~~~~~~~~ PARTS ~~~~~~~~~~~~~~~~~~~~~~ */ +/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */ -/** -* Part as in part-rendering. An image rendered in parts is rendered -* to a list of parts, with x,y size, and a pointer to the render -* output stored per part. Internal! -*/ -typedef struct Part -{ - struct Part *next, *prev; - unsigned int *rect; // color 4x8 bits - float *rectf; // color 4x32 bits - unsigned int *rectz; // zbuffer - - short minx, miny, maxx, maxy, x, y; -} Part; -static void freeparts(void) +void freeparts(Render *re) { - Part *part= R.parts.first; + RenderPart *part= re->parts.first; + while(part) { - if(part->rect) MEM_freeN(part->rect); + if(part->rectp) MEM_freeN(part->rectp); if(part->rectz) MEM_freeN(part->rectz); - if(part->rectf) MEM_freeN(part->rectf); part= part->next; } - BLI_freelistN(&R.parts); -} - -static void initparts(void) -{ - Part *pa; - short nr, xd, yd, xpart, ypart, xparts, yparts; - short a, xminb, xmaxb, yminb, ymaxb; - - freeparts(); - - if(R.r.mode & R_BORDER) { - xminb= R.r.border.xmin*R.rectx; - xmaxb= R.r.border.xmax*R.rectx; - - yminb= R.r.border.ymin*R.recty; - ymaxb= R.r.border.ymax*R.recty; - - if(xminb<0) xminb= 0; - if(xmaxb>R.rectx) xmaxb= R.rectx; - if(yminb<0) yminb= 0; - if(ymaxb>R.recty) ymaxb= R.recty; - } - else { - xminb=yminb= 0; - xmaxb= R.rectx; - ymaxb= R.recty; - } - - xparts= R.r.xparts; /* for border */ - yparts= R.r.yparts; - - xpart= R.rectx/xparts; - ypart= R.recty/yparts; - - /* if border: test if amount of parts can be fewer */ - if(R.r.mode & R_BORDER) { - a= (xmaxb-xminb-1)/xpart+1; /* amount of parts in border */ - if(a<xparts) xparts= a; - a= (ymaxb-yminb-1)/ypart+1; /* amount of parts in border */ - if(a<yparts) yparts= a; - - xpart= (xmaxb-xminb)/xparts; - ypart= (ymaxb-yminb)/yparts; - } - - for(nr=0; nr<xparts*yparts; nr++) { - pa= MEM_callocN(sizeof(Part), "new part"); - - if(R.r.mode & R_PANORAMA) { - pa->minx= pa->miny= 0; - pa->maxx= pa->x= R.rectx; - pa->maxy= pa->y= R.recty; - } - else { - xd= (nr % xparts); - yd= (nr-xd)/xparts; - - pa->minx= xminb+ xd*xpart; - pa->miny= yminb+ yd*ypart; - if(xd<R.r.xparts-1) pa->maxx= pa->minx+xpart; - else pa->maxx= xmaxb; - if(yd<R.r.yparts-1) pa->maxy= pa->miny+ypart; - else pa->maxy= ymaxb; - - pa->x= pa->maxx-pa->minx; - pa->y= pa->maxy-pa->miny; - } - - if(pa->x>0 && pa->y>0) { - /* Non-box filters might need 1 pixel extra to work */ - if((R.r.filtertype)) { - pa->minx-= 1; - pa->miny-= 1; - pa->maxx+= 1; - pa->maxy+= 1; - pa->x+= 2; - pa->y+= 2; - } - BLI_addtail(&R.parts, pa); - } - else MEM_freeN(pa); - } - + BLI_freelistN(&re->parts); } -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -static void setpart(Part *pa) +void initparts(Render *re) { - - R.xstart= pa->minx-R.afmx; - R.ystart= pa->miny-R.afmy; - R.xend= pa->maxx-R.afmx; - R.yend= pa->maxy-R.afmy; - R.rectx= pa->x; - R.recty= pa->y; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -static void addparttorect(Part *pa) -{ - float *rf, *rfp; - unsigned int *rt, *rtp, *rz, *rzp; - int y, height, len, copylen; - - /* calc the right offset in rects, zbuffer cannot exist... */ - if(pa->rect==NULL) return; + int nr, xd, yd, xpart, ypart, xparts, yparts; + int xminb, xmaxb, yminb, ymaxb; - rtp= pa->rect; - rzp= pa->rectz; - rfp= pa->rectf; + freeparts(re); - copylen=len= pa->x; - height= pa->y; + /* this is render info for caller, is not reset when parts are freed! */ + re->i.totpart= 0; + re->i.curpart= 0; + re->i.partsdone= 0; - if(R.r.filtertype) { /* filters added 1 pixel extra */ - - rtp+= 1+len; - if(rzp) rzp+= 1+len; - if(rfp) rfp+= 4*(1+len); - - copylen= len-2; - height -= 2; - rt= R.rectot+ (pa->miny + 1)*R.rectx+ (pa->minx+1); - rz= R.rectz+ (pa->miny + 1)*R.rectx+ (pa->minx+1); - rf= R.rectftot+ 4*( (pa->miny + 1)*R.rectx + (pa->minx+1) ); - } - else { - rt= R.rectot+ pa->miny*R.rectx+ pa->minx; - rz= R.rectz+ pa->miny*R.rectx+ pa->minx; - rf= R.rectftot+ 4*(pa->miny*R.rectx+ pa->minx); - } - - for(y=0; y<height; y++) { - memcpy(rt, rtp, 4*copylen); - rt+= R.rectx; - rtp+= len; - - if(rzp) { - memcpy(rz, rzp, 4*copylen); - rz+= R.rectx; - rzp+= len; - } - if(rfp) { - memcpy(rf, rfp, 16*copylen); - rf+= 4*R.rectx; - rfp+= 4*len; - } - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -static void convert_zbuf_to_distbuf(void) -{ - float *rectzf, zco; - int a, *rectz, ortho= R.r.mode & R_ORTHO; + /* just for readable code.. */ + xminb= re->disprect.xmin; + yminb= re->disprect.ymin; + xmaxb= re->disprect.xmax; + ymaxb= re->disprect.ymax; - if(R.rectz==NULL) return; - if(R.rectzf) { - printf("called convert zbuf wrong...\n"); - MEM_freeN(R.rectzf); - } + xparts= re->r.xparts; + yparts= re->r.yparts; - /* need to make sure winmat is OK */ - R.xstart= -R.afmx; - R.ystart= -R.afmy; - R.xend= R.xstart+R.rectx-1; - R.yend= R.ystart+R.recty-1; + /* mininum part size */ + if(re->rectx/xparts < 64) + xparts= 1 + re->rectx/64; + if(re->recty/yparts < 64) + yparts= 1 + re->recty/64; - RE_setwindowclip(0, -1); - - rectzf= R.rectzf= MEM_mallocN(R.rectx*R.recty*sizeof(float), "rectzf"); - rectz= R.rectz; + /* part size */ + xpart= re->rectx/xparts; + ypart= re->recty/yparts; - for(a=R.rectx*R.recty; a>0; a--, rectz++, rectzf++) { - if(*rectz==0x7FFFFFFF) - *rectzf= 10e10; - else { - /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ - /* or: (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2] - R.winmat[2][3]*zco); */ - /* if ortho [2][3] is zero, else [3][3] is zero */ - - zco= ((float)*rectz)/2147483647.0f; - if(ortho) - *rectzf= (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]); - else - *rectzf= (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco); - } - } - - MEM_freeN(R.rectz); - R.rectz= NULL; -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - -static void add_to_blurbuf(int blur) -{ - static unsigned int *blurrect= 0; - int tot, gamval; - short facr, facb; - char *rtr, *rtb; - - if(blur<0) { - if(blurrect) { - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= blurrect; - blurrect= 0; - } - } - else if(blur==R.osa-1) { - /* first time */ - blurrect= MEM_mallocN(R.rectx*R.recty*sizeof(int), "rectblur"); - if(R.rectot) memcpy(blurrect, R.rectot, R.rectx*R.recty*4); - } - else if(blurrect) { - /* accumulate */ - - facr= 256/(R.osa-blur); - facb= 256-facr; - - if(R.rectot) { - rtr= (char *)R.rectot; - rtb= (char *)blurrect; - tot= R.rectx*R.recty; - while(tot--) { - if( *((unsigned int *)rtb) != *((unsigned int *)rtr) ) { - - if(R.r.mode & R_GAMMA) { - gamval= (facr* igamtab2[ rtr[0]<<8 ] + facb* igamtab2[ rtb[0]<<8 ])>>8; - rtb[0]= gamtab[ gamval ]>>8; - gamval= (facr* igamtab2[ rtr[1]<<8 ] + facb* igamtab2[ rtb[1]<<8 ])>>8; - rtb[1]= gamtab[ gamval ]>>8; - gamval= (facr* igamtab2[ rtr[2]<<8 ] + facb* igamtab2[ rtb[2]<<8 ])>>8; - rtb[2]= gamtab[ gamval ]>>8; - gamval= (facr* igamtab2[ rtr[3]<<8 ] + facb* igamtab2[ rtb[3]<<8 ])>>8; - rtb[3]= gamtab[ gamval ]>>8; - } - else { - rtb[0]= (facr*rtr[0] + facb*rtb[0])>>8; - rtb[1]= (facr*rtr[1] + facb*rtb[1])>>8; - rtb[2]= (facr*rtr[2] + facb*rtb[2])>>8; - rtb[3]= (facr*rtr[3] + facb*rtb[3])>>8; - } - } - rtr+= 4; - rtb+= 4; - } - } - if(blur==0) { - /* last time */ - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= blurrect; - blurrect= 0; - } - } -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - -/* yafray: main yafray render/export call */ -static void yafrayRender(void) -{ - R.flag |= R_RENDERING; /* !!! */ - - /* bug #3193: these params were not initialized, needed later for winmat calc. */ - R.xstart = -R.afmx; - R.ystart = -R.afmy; - R.xend = R.xstart + R.rectx - 1; - R.yend = R.ystart + R.recty - 1; - - /* all allocs moved here, out of export code */ - /* display rgba buf */ - if (R.rectot) MEM_freeN(R.rectot); - R.rectot = MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); - /* zbuf */ - if (R.rectz) MEM_freeN(R.rectz); - if (R.rectzf) MEM_freeN(R.rectzf); - R.rectzf= NULL; - R.rectz = (unsigned int *)MEM_mallocN(sizeof(int)*R.rectx*R.recty, "rectz"); - /* float rgba buf */ - if (R.rectftot) MEM_freeN(R.rectftot); - if (R.r.mode & R_FBUF) R.rectftot= MEM_callocN(4*sizeof(float)*R.rectx*R.recty, "rectftot"); - else R.rectftot = NULL; - - // switch must be done before prepareScene() - if (!R.r.YFexportxml) - YAF_switchFile(); - else - YAF_switchPlugin(); - - RE_local_init_render_display(); - RE_local_clear_render_display(R.win); - RE_local_timecursor((G.scene->r.cfra)); - - printf("Starting scene conversion.\n"); - prepareScene(); - printf("Scene conversion done.\n"); - - YAF_exportScene(); - finalizeScene(); - - // show postpro effects if floatbuffer used (plugin only) - if (R.r.YFexportxml) { - if ((R.r.mode & R_FBUF) && R.rectftot) - RE_floatbuffer_to_output(); - } -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -// exported to other files, belongs in include... later -SDL_mutex *render_abuf_lock=NULL, *load_ibuf_lock=NULL; - - -static void renderloop_setblending(void) -{ - - /* this value should only be set here. do_gamma is for gammablended adding of subpixels */ - do_gamma= 0; - if(R.r.mode & R_GAMMA) { - if(R.r.alphamode==R_ALPHAKEY); // alpha corrected gamma doesnt work for key alpha - else if((R.r.mode & R_OSA)) do_gamma= 1; - } - - /* always call, it does gamma tables used by alphaunder, but call after R.osa and jit was set */ - init_filt_mask(); - - switch (R.r.alphamode) { - case R_ALPHAKEY: - setSkyBlendingMode(RE_ALPHA_KEY); - break; - case R_ALPHAPREMUL: - setSkyBlendingMode(RE_ALPHA_PREMUL); - break; - default: - setSkyBlendingMode(RE_ALPHA_SKY); - } - - /* SHould use slider when the gamma button is pressed. */ - if (do_gamma) { - makeGammaTables(2.0); - } else { - makeGammaTables(1.0); - } - -} - -static void mainRenderLoop(void) /* here the PART and FIELD loops */ -{ - Part *pa; - int blur, fields, fi, totparts, nr; - - /* create mutexes for threaded render */ - render_abuf_lock = SDL_CreateMutex(); - load_ibuf_lock = SDL_CreateMutex(); - - if(R.rectz) MEM_freeN(R.rectz); - R.rectz = NULL; - if(R.rectzf) MEM_freeN(R.rectzf); - R.rectzf = NULL; - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot = NULL; - - /* FIELD LOOP */ - totparts= R.r.xparts*R.r.yparts; - fields= 1; - - if(R.r.mode & R_FIELDS) { - fields= 2; - R.rectf1= R.rectf2= NULL; /* field rects */ - R.r.ysch/= 2; - R.afmy/= 2; - R.r.yasp*= 2; - R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp); - - } - - for(fi=0; fi<fields; fi++) { - - /* INIT */ - BLI_srandom( 2*(G.scene->r.cfra)+fi); - - R.flag|= R_RENDERING; - if(fi==1) R.flag |= R_SEC_FIELD; - - /* MOTIONBLUR loop */ - if(R.r.mode & R_MBLUR) blur= R.osa; - else blur= 1; - while(blur--) { - - /* WINDOW */ - R.rectx= R.r.xsch; - R.recty= R.r.ysch; - R.xstart= -R.afmx; - R.ystart= -R.afmy; - R.xend= R.xstart+R.rectx-1; - R.yend= R.ystart+R.recty-1; - - if(R.r.mode & R_MBLUR) set_mblur_offs(R.osa-blur); - - initparts(); /* always do, because of border and gauss */ - if(R.parts.first==NULL) { - G.afbreek=1; - error("Image too small"); - break; - } - - setpart(R.parts.first); - - RE_local_init_render_display(); - RE_local_clear_render_display(R.win); - RE_local_timecursor((G.scene->r.cfra)); - - prepareScene(); - - /* PARTS LOOP */ - nr= 0; - for(pa= R.parts.first; pa; pa= pa->next, nr++) { - - if(RE_local_test_break()) break; - - setpart(pa); - - if(R.r.mode & R_MBLUR) RE_setwindowclip(0, blur); - else RE_setwindowclip(0,-1); - - if(R.r.mode & R_PANORAMA) setPanoRot(nr); - - /* HOMOGENIC COORDINATES AND ZBUF AND CLIP OPTIMISATION (per part) */ - /* There may be some interference with z-coordinate */ - /* calculation here? */ - - doClipping(RE_projectverto); - if(RE_local_test_break()) break; - - /* rectot is for result and integer face indices */ - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); - - if(R.rectftot) MEM_freeN(R.rectftot); - if(R.r.mode & R_FBUF) R.rectftot= MEM_callocN(4*sizeof(float)*R.rectx*R.recty, "rectftot"); - else R.rectftot = NULL; - - if(R.r.mode & R_MBLUR) { - RE_local_printrenderinfo(0.0, R.osa - blur); - if(G.background && blur<R.osa) printf("\n"); // newline for percentage print - } - else RE_local_printrenderinfo(0.0, -1); - - if(R.r.mode & R_UNIFIED) { - zBufShadeAdvanced(); - } - else { - if(R.rectz) MEM_freeN(R.rectz); - R.rectz = (unsigned int *)MEM_mallocN(sizeof(int)*R.rectx*R.recty, "rectz"); - - if(R.r.mode & R_OSA) zbufshadeDA(); - else zbufshade(); - } - - /* exception */ - if( (R.r.mode & R_BORDER) && (R.r.mode & R_MOVIECROP)); - else { - /* HANDLE PART OR BORDER */ - if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.filtertype)) { - - pa->rect= R.rectot; - R.rectot= NULL; - pa->rectf= R.rectftot; - R.rectftot= NULL; - pa->rectz= R.rectz; - R.rectz= NULL; - } - } - - if(RE_local_test_break()) break; - } - - /* JOIN PARTS OR INSERT BORDER */ - - /* exception: crop */ - if( (R.r.mode & R_BORDER) && (R.r.mode & R_MOVIECROP)) ; - else { - R.rectx= R.r.xsch; - R.recty= R.r.ysch; - - if(R.r.mode & R_PANORAMA) R.rectx*= R.r.xparts; - - if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.filtertype)) { - int a; - - if(R.rectot) MEM_freeN(R.rectot); - if(R.rectftot) MEM_freeN(R.rectftot); - if(R.rectz) MEM_freeN(R.rectz); - - R.rectot= MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); - - if(R.r.mode & R_UNIFIED) R.rectz= NULL; - else R.rectz= MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectz"); - - if(R.r.mode & R_FBUF) R.rectftot= MEM_callocN(4*sizeof(float)*R.rectx*R.recty, "rectftot"); - else R.rectftot= NULL; - - for(a=0, pa= R.parts.first; pa; pa= pa->next, a++) { - - if(R.r.mode & R_PANORAMA) { // pano is fake parts... - pa->minx += a*R.r.xsch; - pa->maxx += a*R.r.xsch; - } - addparttorect(pa); - } - } - } - - freeparts(); - - if( (R.flag & R_HALO)) { - if(RE_local_test_break()==0) add_halo_flare(); - } - - if( (R.r.mode & R_ZBLUR)) { - if(RE_local_test_break()==0) add_zblur(); - } - - if(R.r.mode & R_MBLUR) { - add_to_blurbuf(blur); - } - - /* END (blur loop) */ - finalizeScene(); - - if(RE_local_test_break()) break; - } - - /* definite free */ - add_to_blurbuf(-1); - - /* HANDLE FIELD */ - if(R.r.mode & R_FIELDS) { - if(R.flag & R_SEC_FIELD) R.rectf2= R.rectot; - else R.rectf1= R.rectot; - R.rectot= NULL; - } - - if(RE_local_test_break()) break; - } - - /* JOIN FIELDS */ - if(R.r.mode & R_FIELDS) { - R.r.ysch*= 2; - R.afmy*= 2; - R.recty*= 2; - R.r.yasp/=2; - - if(R.rectot) MEM_freeN(R.rectot); /* happens when a render has been stopped */ - R.rectot=(unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); + for(nr=0; nr<xparts*yparts; nr++) { + rcti disprect; + int rectx, recty; - if(RE_local_test_break()==0) { - unsigned int *rt, *rt1, *rt2; - int len, a; - - rt= R.rectot; - - if(R.r.mode & R_ODDFIELD) { - rt2= R.rectf1; - rt1= R.rectf2; - } - else { - rt1= R.rectf1; - rt2= R.rectf2; - } - - len= 4*R.rectx; - - for(a=0; a<R.recty; a+=2) { - memcpy(rt, rt1, len); - rt+= R.rectx; - rt1+= R.rectx; - memcpy(rt, rt2, len); - rt+= R.rectx; - rt2+= R.rectx; - } - } + xd= (nr % xparts); + yd= (nr-xd)/xparts; - if(R.rectf1) MEM_freeN(R.rectf1); - R.rectf1= NULL; - if(R.rectf2) MEM_freeN(R.rectf2); - R.rectf2= NULL; - /* fbuf and zbuf free, image size differs now */ - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot= NULL; - if(R.rectz) MEM_freeN(R.rectz); - R.rectz= NULL; + disprect.xmin= xminb+ xd*xpart; + disprect.ymin= yminb+ yd*ypart; - } - - /* if border: still do skybuf */ - if(R.r.mode & R_BORDER) { - if( (R.r.mode & R_MOVIECROP)==0) { - if(R.r.bufflag & 1) { - unsigned int *rt; - int x, y; - - R.xstart= -R.afmx; - R.ystart= -R.afmy; - rt= R.rectot; - for(y=0; y<R.recty; y++) { - for(x=0; x<R.rectx; x++, rt++) { - if(*rt==0) fillBackgroundImageChar((char *)rt, x, y); - } - } - } - } - } - - set_mblur_offs(0); - - /* mutexes free */ - SDL_DestroyMutex(load_ibuf_lock); - SDL_DestroyMutex(render_abuf_lock); - load_ibuf_lock= NULL; - render_abuf_lock= NULL; -} - -void render() { - /* yafray: render, see above */ - if (R.r.renderer==R_YAFRAY) - yafrayRender(); - else - mainRenderLoop(); -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -void RE_initrender(struct View3D *ogl_render_view3d) -{ - double start_time; - Image *bima; - char name[256]; - - /* scene data to R */ - R.r= G.scene->r; - R.r.postigamma= 1.0/R.r.postgamma; - - /* WINDOW size (sch='scherm' dutch for screen...) */ - R.r.xsch= (R.r.size*R.r.xsch)/100; - R.r.ysch= (R.r.size*R.r.ysch)/100; - - R.afmx= R.r.xsch/2; - R.afmy= R.r.ysch/2; - - /* to be sure: when a premature return (rectx can differ from xsch) */ - R.rectx= R.r.xsch; - R.recty= R.r.ysch; - - /* IS RENDERING ALLOWED? */ - - /* forbidden combination */ - if(R.r.mode & R_PANORAMA) { - if(R.r.mode & R_BORDER) { - error("No border supported for Panorama"); - G.afbreek= 1; - } - if(R.r.yparts>1) { - error("No Y-Parts supported for Panorama"); - G.afbreek= 1; + /* ensure we cover the entire picture, so last parts go to end */ + if(xd<xparts-1) { + disprect.xmax= disprect.xmin + xpart; + if(disprect.xmax > xmaxb) + disprect.xmax = xmaxb; } - if(R.r.mode & R_ORTHO) { - error("No Ortho render possible for Panorama"); - G.afbreek= 1; - } - } - - if(R.r.mode & R_BORDER) { - if(R.r.border.xmax <= R.r.border.xmin || - R.r.border.ymax <= R.r.border.ymin) { - error("No border area selected."); - G.afbreek= 1; - } - } - - if(R.r.xparts*R.r.yparts>=2 && (R.r.mode & R_MOVIECROP) && (R.r.mode & R_BORDER)) { - error("Combination of border, crop and parts not allowed"); - G.afbreek= 1; - return; - } - - if(R.r.xparts*R.r.yparts>64) { - error("No more than 64 parts supported"); - G.afbreek= 1; - return; - } - - if(R.r.yparts>1 && (R.r.mode & R_PANORAMA)) { - error("No Y-Parts supported for Panorama"); - G.afbreek= 1; - return; - } - - if(G.afbreek==1) return; - - /* TEST BACKBUF */ - /* If an image is specified for use as backdrop, that image is loaded */ - /* here. */ - if((R.r.bufflag & 1) && (G.scene->r.scemode & R_OGL)==0) { - if(R.r.alphamode == R_ADDSKY) { - strcpy(name, R.r.backbuf); - BLI_convertstringcode(name, G.sce, G.scene->r.cfra); - - if(R.backbuf) { - R.backbuf->id.us--; - bima= R.backbuf; - } - else bima= NULL; - - R.backbuf= add_image(name); - - if(bima && bima->id.us<1) { - free_image_buffers(bima); - } - - if(R.backbuf && R.backbuf->ibuf==NULL) { - R.backbuf->ibuf= IMB_loadiffname(R.backbuf->name, IB_rect); - if(R.backbuf->ibuf==NULL) R.backbuf->ok= 0; - else R.backbuf->ok= 1; - } - if(R.backbuf==NULL || R.backbuf->ok==0) { - // error() doesnt work with render window open - //error("No backbuf there!"); - printf("Error: No backbuf %s\n", name); - } - } - } - - if(R.r.mode & (R_OSA|R_MBLUR)) { - R.osa= R.r.osa; - if(R.osa>16) R.osa= 16; - - init_render_jit(R.osa); + else disprect.xmax= xmaxb; - } - else R.osa= 0; - - /* just prevents cpu cycles for larger render and copying */ - if((R.r.mode & R_OSA)==0) - R.r.filtertype= 0; - - renderloop_setblending(); // alpha, sky, gamma - - /* when rendered without camera object */ - /* it has to done here because of envmaps */ - R.near= 0.1; - R.far= 1000.0; - - - if(R.afmx<1 || R.afmy<1) { - error("Image too small"); - return; - } - R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp); - - start_time= PIL_check_seconds_timer(); - - if(R.r.scemode & R_OGL) { - R.rectx= R.r.xsch; - R.recty= R.r.ysch; - - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); - - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot= NULL; - - RE_local_init_render_display(); - drawview3d_render(ogl_render_view3d); - } - else if(R.r.scemode & R_DOSEQ) { - R.rectx= R.r.xsch; - R.recty= R.r.ysch; - if(R.r.mode & R_PANORAMA) { - R.rectx*= R.r.xparts; + if(yd<yparts-1) { + disprect.ymax= disprect.ymin + ypart; + if(disprect.ymax > ymaxb) + disprect.ymax = ymaxb; } + else disprect.ymax= ymaxb; - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= (unsigned int *)MEM_callocN(sizeof(int)*R.rectx*R.recty, "rectot"); - - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot= NULL; - - RE_local_timecursor((G.scene->r.cfra)); - - if(RE_local_test_break()==0) do_render_seq(); - - /* display */ - if(R.rectot) RE_local_render_display(0, R.recty-1, R.rectx, R.recty,R.rectot); - } - else { - if(G.scene->camera==0) { - G.scene->camera= scene_find_camera(G.scene); - } + rectx= disprect.xmax - disprect.xmin; + recty= disprect.ymax - disprect.ymin; - if(G.scene->camera==0) { - error("No camera"); - /* needed because R.rectx and R.recty can be unmatching R.rectot */ + /* so, now can we add this part? */ + if(rectx>0 && recty>0) { + RenderPart *pa= MEM_callocN(sizeof(RenderPart), "new part"); - if(R.rectot) MEM_freeN(R.rectot); - R.rectot= NULL; - if(R.rectftot) MEM_freeN(R.rectftot); - R.rectftot= NULL; - - G.afbreek=1; - return; - } - else { - - if(G.scene->camera->type==OB_CAMERA) { - Camera *cam= G.scene->camera->data; - if(cam->type==CAM_ORTHO) R.r.mode |= R_ORTHO; + /* Non-box filters need 2 pixels extra to work */ + if((re->r.filtertype || (re->r.mode & R_EDGE))) { + pa->crop= 2; + disprect.xmin -= pa->crop; + disprect.ymin -= pa->crop; + disprect.xmax += pa->crop; + disprect.ymax += pa->crop; + rectx+= 2*pa->crop; + recty+= 2*pa->crop; } - - render(); /* returns with complete rect xsch-ysch */ - } - } - - /* display again: fields/seq/parts/pano etc */ - if(R.rectot) { - RE_local_init_render_display(); - RE_local_render_display(0, R.recty-1, R.rectx, R.recty, R.rectot); - } - else RE_local_clear_render_display(R.win); - - if ((G.scene->r.scemode & R_OGL)==0) /* header gets scrabled if renderwindow holds OGL context */ - RE_local_printrenderinfo((PIL_check_seconds_timer() - start_time), -1); - - /* grms... this is a nasty global */ - do_gamma= 0; - - /* for now, we do always */ - convert_zbuf_to_distbuf(); - - /* these flags remain on, until reset in caller to render (renderwin.c) */ - R.flag &= (R_RENDERING|R_ANIMRENDER|R_REDRAW_PRV); -} + pa->disprect= disprect; + pa->rectx= rectx; + pa->recty= recty; -void RE_animrender(struct View3D *ogl_render_view3d) -{ - int cfrao; - char name[256]; - - if(G.scene==NULL) return; - if(G.scene->r.sfra > G.scene->r.efra) { - error("Startframe larger than Endframe"); - return; - } - - /* scenedata to R: (for backbuf, R.rectx etc) */ - R.r= G.scene->r; - - /* START ANIMLOOP, everywhere NOT the cfra from R.r is gebruikt: because of rest blender */ - cfrao= (G.scene->r.cfra); - - /* disable options for ogl render */ - if(G.scene->r.scemode & R_OGL) R.r.mode &= ~(R_PANORAMA|R_MOVIECROP); - - // these calculations apply for all movie formats - R.rectx= (R.r.size*R.r.xsch)/100; - R.recty= (R.r.size*R.r.ysch)/100; - if(R.r.mode & R_PANORAMA) { - R.rectx*= R.r.xparts; - R.recty*= R.r.yparts; - } - if(R.r.mode & R_MOVIECROP) { - initparts(); - setpart(R.parts.first); // this will adjust r.rectx - } - - if (0) { -#ifdef __sgi - } else if (R.r.imtype==R_MOVIE) { - start_movie(); -#endif -#if defined(_WIN32) && !defined(FREE_WINDOWS) - } else if (R.r.imtype == R_AVICODEC) { - start_avi_codec(); -#endif -#if WITH_QUICKTIME - } else if (R.r.imtype == R_QUICKTIME) { - start_qt(); -#endif - } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { - if ELEM(R.r.imtype, R_MOVIE, R_AVICODEC) { - printf("Selected movie format not supported on this platform,\nusing RAW AVI instead\n"); + BLI_addtail(&re->parts, pa); + re->i.totpart++; } - start_avi(); } -// set initial conditions for softbodies here -// ****************************************** - for((G.scene->r.cfra)=(G.scene->r.sfra); (G.scene->r.cfra)<=(G.scene->r.efra); (G.scene->r.cfra)++) { - double starttime= PIL_check_seconds_timer(); +} - R.flag |= R_ANIMRENDER; // unused now (ton) - RE_initrender(ogl_render_view3d); - - /* WRITE IMAGE */ - if(RE_local_test_break()==0) { +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - if (0) { -#ifdef __sgi - } else if (R.r.imtype == R_MOVIE) { - append_movie((G.scene->r.cfra)); -#endif -#if defined(_WIN32) && !defined(FREE_WINDOWS) - } else if (R.r.imtype == R_AVICODEC) { - append_avi_codec((G.scene->r.cfra)); -#endif -#ifdef WITH_QUICKTIME - } else if (R.r.imtype == R_QUICKTIME) { - append_qt((G.scene->r.cfra)); -#endif - } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { - append_avi((G.scene->r.cfra)); - } else { - makepicstring(name, (G.scene->r.cfra)); - schrijfplaatje(name); - if(RE_local_test_break()==0) printf("Saved: %s", name); - } +// exported to other files, belongs in include... later +SDL_mutex *render_abuf_lock=NULL, *load_ibuf_lock=NULL; - timestr(PIL_check_seconds_timer()-starttime, name); - printf(" Time: %s\n", name); - fflush(stdout); /* needed for renderd !! */ - } - if(G.afbreek==1) break; - } +/* **************************************************************** */ +/* sticky texture coords */ +/* **************************************************************** */ - G.scene->r.cfra= cfrao; +void RE_make_sticky(void) +{ + /* oldfile.txt */ +} - /* restore time */ - if(R.r.mode & (R_FIELDS|R_MBLUR)) { - /* applies changes fully */ - scene_update_for_newframe(G.scene, G.scene->lay); - } - if (0) { -#ifdef __sgi - } else if (R.r.imtype==R_MOVIE) { - end_movie(); -#endif -#if defined(_WIN32) && !defined(FREE_WINDOWS) - } else if (R.r.imtype == R_AVICODEC) { - end_avi_codec(); -#endif -#ifdef WITH_QUICKTIME - } else if (R.r.imtype == R_QUICKTIME) { - end_qt(); -#endif - } else if ELEM4(R.r.imtype, R_AVIRAW, R_AVIJPEG, R_MOVIE, R_AVICODEC) { - end_avi(); - } -} -/* *************************************************** */ -/* ******************* Screendumps ******************** */ -/* moved to the windowControl thing */ diff --git a/source/blender/render/intern/source/jitter.c b/source/blender/render/intern/source/jitter.c deleted file mode 100644 index 98bb1543068..00000000000 --- a/source/blender/render/intern/source/jitter.c +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Jitter offset table - * - * $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 ***** - */ - -#include <math.h> -#include <stdlib.h> -#include <string.h> -#include "MEM_guardedalloc.h" - -#include "BLI_arithb.h" -#include "BLI_rand.h" -#include "render.h" -#include "jitter.h" - - -float jit[64][2]; - -void init_render_jit(int nr); - - -void RE_jitterate1(float *jit1, float *jit2, int num, float rad1) -{ - int i , j , k; - float vecx, vecy, dvecx, dvecy, x, y, len; - - for (i = 2*num-2; i>=0 ; i-=2) { - dvecx = dvecy = 0.0; - x = jit1[i]; - y = jit1[i+1]; - for (j = 2*num-2; j>=0 ; j-=2) { - if (i != j){ - vecx = jit1[j] - x - 1.0; - vecy = jit1[j+1] - y - 1.0; - for (k = 3; k>0 ; k--){ - if( fabs(vecx)<rad1 && fabs(vecy)<rad1) { - len= sqrt(vecx*vecx + vecy*vecy); - if(len>0 && len<rad1) { - len= len/rad1; - dvecx += vecx/len; - dvecy += vecy/len; - } - } - vecx += 1.0; - - if( fabs(vecx)<rad1 && fabs(vecy)<rad1) { - len= sqrt(vecx*vecx + vecy*vecy); - if(len>0 && len<rad1) { - len= len/rad1; - dvecx += vecx/len; - dvecy += vecy/len; - } - } - vecx += 1.0; - - if( fabs(vecx)<rad1 && fabs(vecy)<rad1) { - len= sqrt(vecx*vecx + vecy*vecy); - if(len>0 && len<rad1) { - len= len/rad1; - dvecx += vecx/len; - dvecy += vecy/len; - } - } - vecx -= 2.0; - vecy += 1.0; - } - } - } - - x -= dvecx/18.0 ; - y -= dvecy/18.0; - x -= floor(x) ; - y -= floor(y); - jit2[i] = x; - jit2[i+1] = y; - } - memcpy(jit1,jit2,2 * num * sizeof(float)); -} - -void RE_jitterate2(float *jit1, float *jit2, int num, float rad2) -{ - int i, j; - float vecx, vecy, dvecx, dvecy, x, y; - - for (i=2*num -2; i>= 0 ; i-=2){ - dvecx = dvecy = 0.0; - x = jit1[i]; - y = jit1[i+1]; - for (j =2*num -2; j>= 0 ; j-=2){ - if (i != j){ - vecx = jit1[j] - x - 1.0; - vecy = jit1[j+1] - y - 1.0; - - if( fabs(vecx)<rad2) dvecx+= vecx*rad2; - vecx += 1.0; - if( fabs(vecx)<rad2) dvecx+= vecx*rad2; - vecx += 1.0; - if( fabs(vecx)<rad2) dvecx+= vecx*rad2; - - if( fabs(vecy)<rad2) dvecy+= vecy*rad2; - vecy += 1.0; - if( fabs(vecy)<rad2) dvecy+= vecy*rad2; - vecy += 1.0; - if( fabs(vecy)<rad2) dvecy+= vecy*rad2; - - } - } - - x -= dvecx/2 ; - y -= dvecy/2; - x -= floor(x) ; - y -= floor(y); - jit2[i] = x; - jit2[i+1] = y; - } - memcpy(jit1,jit2,2 * num * sizeof(float)); -} - - -void initjit(float *jitarr, int num) -{ - float *jit2, x, rad1, rad2, rad3; - int i; - - if(num==0) return; - - jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit"); - rad1= 1.0/sqrt((float)num); - rad2= 1.0/((float)num); - rad3= sqrt((float)num)/((float)num); - - BLI_srand(31415926 + num); - x= 0; - for(i=0; i<2*num; i+=2) { - jitarr[i]= x+ rad1*(0.5-BLI_drand()); - jitarr[i+1]= ((float)i/2)/num +rad1*(0.5-BLI_drand()); - x+= rad3; - x -= floor(x); - } - - for (i=0 ; i<24 ; i++) { - RE_jitterate1(jitarr, jit2, num, rad1); - RE_jitterate1(jitarr, jit2, num, rad1); - RE_jitterate2(jitarr, jit2, num, rad2); - } - - MEM_freeN(jit2); - - /* finally, move jittertab to be centered around (0,0) */ - for(i=0; i<2*num; i+=2) { - jitarr[i] -= 0.5; - jitarr[i+1] -= 0.5; - } - -} - -void init_render_jit(int nr) -{ - static int lastjit= 0; - - if(lastjit==nr) return; - - memset(jit, 0, 64*2*4); - initjit(jit[0], nr); - - lastjit= nr; -} - -/* eof */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c new file mode 100644 index 00000000000..67690fd69f6 --- /dev/null +++ b/source/blender/render/intern/source/pipeline.c @@ -0,0 +1,954 @@ +/** + * + * ***** BEGIN GPL 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. + * + * 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) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> + +#include "DNA_group_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_scene.h" +#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */ + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "PIL_time.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_pipeline.h" +#include "radio.h" + +#include "BSE_sequence.h" /* <----------------- bad!!! */ + +/* internal */ +#include "render_types.h" +#include "renderpipeline.h" +#include "renderdatabase.h" +#include "rendercore.h" +#include "envmap.h" +#include "initrender.h" +#include "shadbuf.h" +#include "zbuf.h" + +#include "SDL_thread.h" + +/* render flow + +1) Initialize state +- state data, tables +- movie/image file init +- everything that doesn't change during animation + +2) Initialize data +- camera, world, matrices +- make render verts, faces, halos, strands +- everything can change per frame/field + +3) Render Processor +- multiple layers +- tiles, rect, baking +- layers/tiles optionally to disk or directly in Render Result + +4) Composit Render Result +- also read external files etc + +5) Image Files +- save file or append in movie + +*/ + + +/* ********* globals ******** */ + +/* here we store all renders */ +static struct ListBase RenderList= {NULL, NULL}; + +/* hardcopy of current render, used while rendering for speed */ +Render R; + +/* ********* alloc and free ******** */ + + +static SDL_mutex *malloc_lock= NULL; + +void *RE_mallocN(int len, char *name) +{ + void *mem; + if(malloc_lock) SDL_mutexP(malloc_lock); + mem= MEM_mallocN(len, name); + if(malloc_lock) SDL_mutexV(malloc_lock); + return mem; +} +void *RE_callocN(int len, char *name) +{ + void *mem; + if(malloc_lock) SDL_mutexP(malloc_lock); + mem= MEM_callocN(len, name); + if(malloc_lock) SDL_mutexV(malloc_lock); + return mem; +} +void RE_freeN(void *poin) +{ + if(malloc_lock) SDL_mutexP(malloc_lock); + MEM_freeN(poin); + if(malloc_lock) SDL_mutexV(malloc_lock); +} + +/* ********************** */ + + +/* default callbacks, set in each new render */ +static void result_nothing(RenderResult *rr) {} +static void result_rcti_nothing(RenderResult *rr, rcti *rect) {} +static void stats_nothing(RenderStats *rs) {} +static void int_nothing(int val) {} +static int void_nothing(void) {return 0;} +static void print_error(const char *str) {printf("ERROR: %s\n", str);} + +static void free_render_result(RenderResult *res) +{ + if(res==NULL) return; + + while(res->layers.first) { + RenderLayer *rl= res->layers.first; + if(rl->rectf) RE_freeN(rl->rectf); + if(rl->rectz) RE_freeN(rl->rectz); + BLI_remlink(&res->layers, rl); + RE_freeN(rl); + } + + if(res->rect32) + MEM_freeN(res->rect32); + + RE_freeN(res); +} + +/* called by main render as well for parts */ +/* will read info from Render *re to define layers */ +/* called in threads */ +/* winrct is coordinate rect of entire image, partrct the part within */ +static RenderResult *new_render_result(Render *re, rcti *partrct, int crop) +{ + RenderResult *rr; + RenderLayer *rl; + int rectx, recty; + + rectx= partrct->xmax - partrct->xmin; + recty= partrct->ymax - partrct->ymin; + + if(rectx<=0 || recty<=0) + return NULL; + + rr= RE_callocN(sizeof(RenderResult), "new render result"); + rr->rectx= rectx; + rr->recty= recty; + /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ + rr->crop= crop; + + /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ + rr->tilerect.xmin= partrct->xmin - re->disprect.xmin; + rr->tilerect.xmax= partrct->xmax - re->disprect.xmax; + rr->tilerect.ymin= partrct->ymin - re->disprect.ymin; + rr->tilerect.ymax= partrct->ymax - re->disprect.ymax; + + /* check renderdata for amount of layers */ + /* for now just one */ + rl= RE_callocN(sizeof(RenderLayer), "new render layer"); + BLI_addtail(&rr->layers, rl); + + rl->rectf= RE_callocN(rectx*recty*sizeof(float)*4, "layer float rgba"); + rl->rectz= RE_callocN(rectx*recty*sizeof(float), "layer float Z"); + + return rr; +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) +/* caller is responsible for allocating rect in correct size! */ +void RE_ResultGet32(Render *re, unsigned int *rect) +{ + if(re->result) { + RenderLayer *rl= re->result->layers.first; + float *fp= rl->rectf; + if(fp) { + int tot= re->rectx*re->recty; + char *cp= (char *)rect; + + for(;tot>0; tot--, cp+=4, fp+=4) { + cp[0] = FTOCHAR(fp[0]); + cp[1] = FTOCHAR(fp[1]); + cp[2] = FTOCHAR(fp[2]); + cp[3] = FTOCHAR(fp[3]); + } + return; + } + } + /* else fill with black */ + memset(rect, sizeof(int)*re->rectx*re->recty, 0); +} + +/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */ +/* no test happens here if it fits... */ +/* is used within threads */ +static void merge_render_result(RenderResult *rr, RenderResult *rrpart) +{ + RenderLayer *rl= rr->layers.first; + RenderLayer *rlp= rrpart->layers.first; + float *rf, *rfp; + int *rz=NULL, *rzp; + int y, height, len, copylen; + + if(rlp->rectf==NULL) return; + if(rl->rectf==NULL) return; + + rzp= NULL; //rlp->rectz; + rfp= rlp->rectf; + + copylen=len= rrpart->rectx; + height= rrpart->recty; + + if(rrpart->crop) { /* filters add pixel extra */ + + if(rzp) rzp+= rrpart->crop + rrpart->crop*len; + if(rfp) rfp+= 4*(rrpart->crop + rrpart->crop*len); + + copylen= len-2*rrpart->crop; + height -= 2*rrpart->crop; + + // rz= re->rectz+ (pa->miny + rrpart->crop)*rr->rectx+ (pa->minx+rrpart->crop); + rf= rl->rectf+ ( (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop) )*4; + } + else { + // rz= re->rectz + (pa->disprect.ymin*rr->rectx + pa->disprect.xmin); + rf= rl->rectf+ (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin)*4; + } + + for(y=0; y<height; y++) { + if(rzp) { + memcpy(rz, rzp, 4*copylen); + rz+= rr->rectx; + rzp+= len; + } + if(rfp) { + memcpy(rf, rfp, 16*copylen); + rf+= 4*rr->rectx; + rfp+= 4*len; + } + } +} + + +/* *************************************************** */ + +Render *RE_GetRender(const char *name) +{ + Render *re; + + /* search for existing renders */ + for(re= RenderList.first; re; re= re->next) { + if(strncmp(re->name, name, RE_MAXNAME)==0) { + break; + } + } + return re; +} + +RenderResult *RE_GetResult(Render *re) +{ + if(re) + return re->result; + return NULL; +} + +RenderStats *RE_GetStats(Render *re) +{ + return &re->i; +} + +Render *RE_NewRender(const char *name) +{ + Render *re; + + /* only one render per name exists */ + re= RE_GetRender(name); + if(re) { + BLI_remlink(&RenderList, re); + RE_FreeRender(re); + } + + /* new render data struct */ + re= RE_callocN(sizeof(Render), "new render"); + BLI_addtail(&RenderList, re); + strncpy(re->name, name, RE_MAXNAME); + + /* set default empty callbacks */ + re->display_init= result_nothing; + re->display_clear= result_nothing; + re->display_draw= result_rcti_nothing; + re->timecursor= int_nothing; + re->test_break= void_nothing; + re->test_return= void_nothing; + re->error= print_error; + re->stats_draw= stats_nothing; + + /* init some variables */ + re->ycor= 1.0f; + + return re; +} + +/* only call this while you know it will remove the link too */ +void RE_FreeRender(Render *re) +{ + + free_renderdata_tables(re); + free_sample_tables(re); + + free_render_result(re->result); + + BLI_remlink(&RenderList, re); + RE_freeN(re); +} + +/* exit blender */ +void RE_FreeAllRender(void) +{ + while(RenderList.first) { + RE_FreeRender(RenderList.first); + } +} + +/* ********* initialize state ******** */ + + +/* what doesn't change during entire render sequence */ +/* disprect is optional, if NULL it assumes full window render */ +void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect) +{ + re->ok= TRUE; /* maybe flag */ + + re->i.starttime= PIL_check_seconds_timer(); + re->r= *rd; /* hardcopy */ + + re->winx= winx; + re->winy= winy; + if(disprect) { + re->disprect= *disprect; + re->rectx= disprect->xmax-disprect->xmin; + re->recty= disprect->ymax-disprect->ymin; + } + else { + re->disprect.xmin= re->disprect.xmax= 0; + re->disprect.xmax= winx; + re->disprect.ymax= winy; + re->rectx= winx; + re->recty= winy; + } + + if(re->rectx < 2 || re->recty < 2) { + re->error("Image too small"); + re->ok= 0; + } + else { + /* check state variables, osa? */ + if(re->r.mode & (R_OSA|R_MBLUR)) { + re->osa= re->r.osa; + if(re->osa>16) re->osa= 16; + } + else re->osa= 0; + + /* always call, checks for gamma, gamma tables and jitter too */ + make_sample_tables(re); + + /* initialize render result */ + free_render_result(re->result); + re->result= new_render_result(re, &re->disprect, 0); + + } +} + +void RE_SetDispRect (struct Render *re, rcti *disprect) +{ + re->disprect= *disprect; + re->rectx= disprect->xmax-disprect->xmin; + re->recty= disprect->ymax-disprect->ymin; + + /* initialize render result */ + free_render_result(re->result); + re->result= new_render_result(re, &re->disprect, 0); +} + +void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) +{ + /* re->ok flag? */ + + re->viewplane= *viewplane; + re->clipsta= clipsta; + re->clipend= clipend; + + i_window(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat); +} + +void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend) +{ + /* re->ok flag? */ + + re->viewplane= *viewplane; + re->clipsta= clipsta; + re->clipend= clipend; + re->r.mode |= R_ORTHO; + + i_ortho(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat); +} + +void RE_SetView(Render *re, float mat[][4]) +{ + /* re->ok flag? */ + Mat4CpyMat4(re->viewmat, mat); + Mat4Invert(re->viewinv, re->viewmat); +} + +/* image and movie output has to move to either imbuf or kernel */ + +void RE_display_init_cb(Render *re, void (*f)(RenderResult *rr)) +{ + re->display_init= f; +} +void RE_display_clear_cb(Render *re, void (*f)(RenderResult *rr)) +{ + re->display_clear= f; +} +void RE_display_draw_cb(Render *re, void (*f)(RenderResult *rr, rcti *rect)) +{ + re->display_draw= f; +} + +void RE_stats_draw_cb(Render *re, void (*f)(RenderStats *rs)) +{ + re->stats_draw= f; +} +void RE_timecursor_cb(Render *re, void (*f)(int)) +{ + re->timecursor= f; +} + +void RE_test_break_cb(Render *re, int (*f)(void)) +{ + re->test_break= f; +} +void RE_test_return_cb(Render *re, int (*f)(void)) +{ + re->test_return= f; +} +void RE_error_cb(Render *re, void (*f)(const char *str)) +{ + re->error= f; +} + + +/* ********* add object data (later) ******** */ + +/* object is considered fully prepared on correct time etc */ +/* includes lights */ +void RE_AddObject(Render *re, Object *ob) +{ + +} + +/* ********** basic thread control API ************ */ + +#define RE_MAX_THREAD 4 + +typedef struct ThreadSlot { + RenderPart *part; + int avail; +} ThreadSlot; + +static ThreadSlot threadslots[RE_MAX_THREAD]; + +static void init_threadslots(int tot) +{ + int a; + + if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD; + else if(tot<1) tot= 1; + + for(a=0; a< RE_MAX_THREAD; a++) { + threadslots[a].part= NULL; + if(a<tot) + threadslots[a].avail= 1; + else + threadslots[a].avail= 0; + } +} + +static int available_threadslots(void) +{ + int a, counter=0; + for(a=0; a< RE_MAX_THREAD; a++) + if(threadslots[a].avail) + counter++; + return counter; +} + +static void insert_threadslot(RenderPart *pa) +{ + int a; + for(a=0; a< RE_MAX_THREAD; a++) { + if(threadslots[a].avail) { + threadslots[a].avail= 0; + threadslots[a].part= pa; + pa->thread= a; + break; + } + } +} + +static void remove_threadslot(RenderPart *pa) +{ + int a; + for(a=0; a< RE_MAX_THREAD; a++) { + if(threadslots[a].part==pa) { + threadslots[a].avail= 1; + threadslots[a].part= NULL; + } + } +} + +/* ********** basic thread control API ************ */ + +static int do_part_thread(void *pa_v) +{ + RenderPart *pa= pa_v; + + /* need to return nicely all parts on esc */ + if(R.test_break()==0) { + + pa->result= new_render_result(&R, &pa->disprect, pa->crop); + + if(R.osa) + zbufshadeDA_tile(pa); + else + zbufshade_tile(pa); + + if(!R.test_break()) + merge_render_result(R.result, pa->result); + } + + pa->ready= 1; + remove_threadslot(pa); + + return 0; +} + +/* returns with render result filled, not threaded */ +static void render_tile_processor(Render *re) +{ + RenderPart *pa; + + if(re->test_break()) + return; + + re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime; + re->stats_draw(&re->i); + re->i.starttime= PIL_check_seconds_timer(); + + if(re->result==NULL) + return; + + initparts(re); + + /* assuming no new data gets added to dbase... */ + R= *re; + + for(pa= re->parts.first; pa; pa= pa->next) { + do_part_thread(pa); + + if(pa->result) { + if(!re->test_break()) { + re->display_draw(pa->result, NULL); + re->i.partsdone++; + } + free_render_result(pa->result); + pa->result= NULL; + } + if(re->test_break()) + break; + } + + re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime; + re->stats_draw(&re->i); + + freeparts(re); +} + +static RenderPart *find_nicest_part(Render *re) +{ + RenderPart *pa, *best= NULL; + int centx=re->winx/2, centy=re->winy/2, tot=1; + int mindist, distx, disty; + + /* find center of rendered parts, image center counts for 1 too */ + for(pa= re->parts.first; pa; pa= pa->next) { + if(pa->ready) { + centx+= (pa->disprect.xmin+pa->disprect.xmax)/2; + centy+= (pa->disprect.ymin+pa->disprect.ymax)/2; + tot++; + } + } + centx/=tot; + centy/=tot; + + /* closest of the non-rendering parts */ + mindist= re->winx*re->winy; + for(pa= re->parts.first; pa; pa= pa->next) { + if(pa->ready==0 && pa->nr==0) { + distx= centx - (pa->disprect.xmin+pa->disprect.xmax)/2; + disty= centy - (pa->disprect.ymin+pa->disprect.ymax)/2; + distx= (int)sqrt(distx*distx + disty*disty); + if(distx<mindist) { + best= pa; + mindist= distx; + } + } + } + return best; +} + +static void threaded_tile_processor(Render *re) +{ + RenderPart *pa; + int maxthreads=2, rendering=1, counter= 1; + + if(re->result==NULL) + return; + if(re->test_break()) + return; + + initparts(re); + init_threadslots(maxthreads); + + /* assuming no new data gets added to dbase... */ + R= *re; + + malloc_lock = SDL_CreateMutex(); + + while(rendering) { + + /* I noted that test_break() in a thread doesn't make ghost send ESC */ + if(available_threadslots() && !re->test_break()) { + pa= find_nicest_part(re); + if(pa) { + insert_threadslot(pa); + pa->nr= counter++; /* only for stats */ + SDL_CreateThread(do_part_thread, pa); + } + } + else + PIL_sleep_ms(50); + + /* check for ready ones to display, and if we need to continue */ + rendering= 0; + for(pa= re->parts.first; pa; pa= pa->next) { + if(pa->ready) { + if(pa->result) { + re->display_draw(pa->result, NULL); + free_render_result(pa->result); + pa->result= NULL; + re->i.partsdone++; + } + } + else rendering= 1; + } + + /* on break, wait for all slots to get freed */ + if(re->test_break() && available_threadslots()==maxthreads) + rendering= 0; + + } + + if(malloc_lock) SDL_DestroyMutex(malloc_lock); malloc_lock= NULL; + + freeparts(re); +} + +void RE_TileProcessor(Render *re) +{ + if(re->r.mode & R_THREADS) + threaded_tile_processor(re); + else + render_tile_processor(re); +} + + +/* ************ This part uses API, for rendering Blender scenes ********** */ + +void render_one_frame(Render *re) +{ + +// re->cfra= cfra; /* <- unused! */ + + /* make render verts/faces/halos/lamps */ + RE_Database_FromScene(re, re->scene, 1); + + RE_TileProcessor(re); + + /* free all render verts etc */ + RE_Database_Free(re); +} + +/* accumulates osa frames */ +static void do_render_blurred(Render *re, float frame) +{ + +} + +/* interleaves 2 frames */ +static void do_render_fields(Render *re) +{ + +} + +static void do_render_final(Render *re, Scene *scene) +{ + if(re->r.scemode & R_DOSEQ) { + re->result->rect32= MEM_callocN(sizeof(int)*re->rectx*re->recty, "rectot"); + if(!re->test_break()) + do_render_seq(re->result); + } + else { + + re->scene= scene; + + /* now use renderdata and camera to set viewplane */ + RE_SetCamera(re, re->scene->camera); + + if(re->r.mode & R_FIELDS) + do_render_fields(re); + else if(re->r.mode & R_MBLUR) + do_render_blurred(re, re->scene->r.cfra); + else + render_one_frame(re); + } + + + re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime; + re->stats_draw(&re->i); + + re->display_draw(re->result, NULL); + +} + + +static int is_rendering_allowed(Render *re) +{ + + /* forbidden combinations */ + if(re->r.mode & R_PANORAMA) { + if(re->r.mode & R_BORDER) { + re->error("No border supported for Panorama"); + return 0; + } + if(re->r.yparts>1) { + re->error("No Y-Parts supported for Panorama"); + return 0; + } + if(re->r.mode & R_ORTHO) { + re->error("No Ortho render possible for Panorama"); + return 0; + } + } + + if(re->r.mode & R_BORDER) { + if(re->r.border.xmax <= re->r.border.xmin || + re->r.border.ymax <= re->r.border.ymin) { + re->error("No border area selected."); + return 0; + } + } + + if(re->r.xparts*re->r.yparts>=2 && (re->r.mode & R_MOVIECROP) && (re->r.mode & R_BORDER)) { + re->error("Combination of border, crop and parts not allowed"); + return 0; + } + + if(re->r.xparts*re->r.yparts>64) { + re->error("No more than 64 parts supported"); + return 0; + } + + if(re->r.yparts>1 && (re->r.mode & R_PANORAMA)) { + re->error("No Y-Parts supported for Panorama"); + return 0; + } + + /* check valid camera */ + if(re->scene->camera==NULL) + re->scene->camera= scene_find_camera(re->scene); + if(re->scene->camera==NULL) { + re->error("No camera"); + return 0; + } + + + return 1; +} + +/* evaluating scene options for general Blender render */ +static int render_initialize_from_scene(Render *re, Scene *scene) +{ + int winx, winy; + rcti disprect; + + /* r.xsch and r.ysch has the actual view window size + r.border is the clipping rect */ + + /* calculate actual render result and display size */ + winx= (scene->r.size*scene->r.xsch)/100; + winy= (scene->r.size*scene->r.ysch)/100; + // if(scene->r.mode & R_PANORAMA) + // winx*= scene->r.xparts; + + /* only in movie case we render smaller part */ + if(scene->r.mode & R_BORDER) { + disprect.xmin= scene->r.border.xmin*winx; + disprect.xmax= scene->r.border.xmax*winx; + + disprect.ymin= scene->r.border.ymin*winy; + disprect.ymax= scene->r.border.ymax*winy; + } + else { + disprect.xmin= disprect.ymin= 0; + disprect.xmax= winx; + disprect.ymax= winy; + } + + RE_InitState(re, &scene->r, winx, winy, &disprect); + + re->scene= scene; + if(!is_rendering_allowed(re)) + return 0; + + re->display_init(re->result); + re->display_clear(re->result); + + return 1; +} + +/* general Blender frame render call */ +/* should return 1 when all is OK, otherwise it throws up errors */ +void RE_BlenderFrame(Render *re, Scene *scene, int frame) +{ + /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ + /* is also set by caller renderwin.c */ + G.rendering= 1; + + if(render_initialize_from_scene(re, scene)) { + do_render_final(re, scene); + } +} + + +/* saves images to disk */ +void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra) +{ + bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype); + int cfrao= scene->r.cfra; + char name[FILE_MAXDIR+FILE_MAXFILE]; + + /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ + /* is also set by caller renderwin.c */ + G.rendering= 1; + + if(!render_initialize_from_scene(re, scene)) + return; + + if(BKE_imtype_is_movie(scene->r.imtype)) + mh->start_movie(&G.scene->r, re->rectx, re->recty); + + for(scene->r.cfra= sfra; scene->r.cfra<=efra; G.scene->r.cfra++) { + + do_render_final(re, scene); + + /* write image or movie */ + if(re->test_break()==0) { + RenderResult *rr= re->result; + RenderLayer *rl= rr->layers.first; + + /* write movie or image */ + if(BKE_imtype_is_movie(scene->r.imtype)) { + if(rr->rect32==NULL) { + rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "temp 32 bits rect"); + } + RE_ResultGet32(re, rr->rect32); + mh->append_movie(scene->r.cfra, rr->rect32, rr->rectx, rr->recty); + printf("Append frame %d", scene->r.cfra); + } + else { + ImBuf *ibuf= IMB_allocImBuf(rr->rectx, rr->recty, scene->r.planes, 0, 0); + int ok; + + BKE_makepicstring(name, (scene->r.cfra)); + ibuf->rect= rr->rect32; /* if not exists, BKE_write_ibuf makes one */ + ibuf->rect_float= rl->rectf; + ibuf->zbuf_float= rl->rectz; + ok= BKE_write_ibuf(ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality); + IMB_freeImBuf(ibuf); /* imbuf knows which rects are not part of ibuf */ + + if(ok==0) { + printf("Render error: cannot save %s\n", name); + break; + } + else printf("Saved: %s", name); + } + + BLI_timestr(re->i.lastframetime, name); + printf(" Time: %s\n", name); + fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */ + } + + if(G.afbreek==1) break; + } + + /* end movie */ + if(BKE_imtype_is_movie(scene->r.imtype)) + mh->end_movie(); + + scene->r.cfra= cfrao; +} + + + diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c index f774a624ba9..73a8e86bc95 100644 --- a/source/blender/render/intern/source/pixelblending.c +++ b/source/blender/render/intern/source/pixelblending.c @@ -6,15 +6,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -28,29 +25,29 @@ * 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): Full recode, 2004-2006 Blender Foundation * - * Contributor(s): none yet. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> /* global includes */ -#include "render.h" - -/* local includes */ -#include "vanillaRenderPipe_types.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" /* own includes */ +#include "render_types.h" +#include "renderpipeline.h" #include "pixelblending.h" #include "gammaCorrectionTables.h" -/* externals */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + /* ------------------------------------------------------------------------- */ /* Debug/behaviour defines */ @@ -72,88 +69,6 @@ #define RE_EMPTY_COLOUR_FLOAT 0.0002 -/* functions --------------------------------------------------------------- */ - -/* - One things about key-alpha is that simply dividing by the alpha will - sometimes cause 'overflows' in that the pixel colours will be shot - way over full colour. This should be caught, and subsequently, the - operation will end up modifying the alpha as well. - - Actually, when the starting colour is premul, it shouldn't overflow - ever. Strange thing is that colours keep overflowing... - -*/ -void applyKeyAlphaCharCol(char* target) { - - if ((!(target[3] == 0)) - || (target[3] == 255)) { - /* else: nothing to do */ - /* check whether div-ing is enough */ - float cf[4]; - cf[0] = target[0]/target[3]; - cf[1] = target[1]/target[3]; - cf[2] = target[2]/target[3]; - if ((cf[0] <= 1.0) && (cf[1] <= 1.0) && (cf[2] <= 1.0)) { - /* all colours remain properly scaled? */ - /* scale to alpha */ - cf[0] = (float) target[0] * (255.0/ (float)target[3]); - cf[1] = (float) target[1] * (255.0/ (float)target[3]); - cf[2] = (float) target[2] * (255.0/ (float)target[3]); - - /* Clipping is important. */ - target[0] = (cf[0] > 255.0 ? 255 : (char) cf[0]); - target[1] = (cf[1] > 255.0 ? 255 : (char) cf[1]); - target[2] = (cf[2] > 255.0 ? 255 : (char) cf[2]); - - } else { - /* shouldn't happen! we were premul, remember? */ -/* should go to error handler: printf("Non-premul colour detected\n"); */ - } - } - -} - -/* ------------------------------------------------------------------------- */ - -void addAddSampColF(float *sampvec, float *source, int mask, int osaNr, - char addfac) -{ - int a; - - for(a=0; a < osaNr; a++) { - if(mask & (1<<a)) addalphaAddfacFloat(sampvec, source, addfac); - sampvec+= 4; - } -} - -/* ------------------------------------------------------------------------- */ - -void addOverSampColF(float *sampvec, float *source, int mask, int osaNr) -{ - int a; - - for(a=0; a < osaNr; a++) { - if(mask & (1<<a)) addAlphaOverFloat(sampvec, source); - sampvec+= 4; - } -} - -/* ------------------------------------------------------------------------- */ - -int addUnderSampColF(float *sampvec, float *source, int mask, int osaNr) -{ - int a, retval = osaNr; - - for(a=0; a < osaNr; a++) { - if(mask & (1<<a)) addAlphaUnderFloat(sampvec, source); - if(sampvec[3] > RE_FULL_COLOUR_FLOAT) retval--; - sampvec+= 4; - } - return retval; -} - - /* ------------------------------------------------------------------------- */ void addAlphaOverFloat(float *dest, float *source) @@ -211,106 +126,6 @@ void addAlphaUnderFloat(float *dest, float *source) } -/* ------------------------------------------------------------------------- */ - -void cpShortColV2CharColV(unsigned short *source, char *dest) -{ - dest[0] = source[0]>>8; - dest[1] = source[1]>>8; - dest[2] = source[2]>>8; - dest[3] = source[3]>>8; -} -/* ------------------------------------------------------------------------- */ - -void cpCharColV2ShortColV(char *source, unsigned short *dest) -{ - dest[0] = source[0]<<8; - dest[1] = source[1]<<8; - dest[2] = source[2]<<8; - dest[3] = source[3]<<8; -} - -/* ------------------------------------------------------------------------- */ - -void cpIntColV2CharColV(unsigned int *source, char *dest) -{ - dest[0] = source[0]>>24; - dest[1] = source[1]>>24; - dest[2] = source[2]>>24; - dest[3] = source[3]>>24; -} - -/* ------------------------------------------------------------------------- */ - -void cpCharColV2FloatColV(char *source, float *dest) -{ - dest[0] = source[0]/255.0; - dest[1] = source[1]/255.0; - dest[2] = source[2]/255.0; - dest[3] = source[3]/255.0; -} - -/* ------------------------------------------------------------------------- */ - -void cpShortColV2FloatColV(unsigned short *source, float *dest) -{ - dest[0] = source[0]/65535.0; - dest[1] = source[1]/65535.0; - dest[2] = source[2]/65535.0; - dest[3] = source[3]/65535.0; -} - -/* ------------------------------------------------------------------------- */ - -void cpFloatColV2CharColV(float* source, char *dest) -{ - /* can't this be done more efficient? hope the conversions are correct... */ - if (source[0] < 0.0) dest[0] = 0; - else if (source[0] > 1.0) dest[0] = 255; - else dest[0] = (char) (source[0] * 255.0); - - if (source[1] < 0.0) dest[1] = 0; - else if (source[1] > 1.0) dest[1] = 255; - else dest[1] = (char) (source[1] * 255.0); - - if (source[2] < 0.0) dest[2] = 0; - else if (source[2] > 1.0) dest[2] = 255; - else dest[2] = (char) (source[2] * 255.0); - - if (source[3] < 0.0) dest[3] = 0; - else if (source[3] > 1.0) dest[3] = 255; - else dest[3] = (char) (source[3] * 255.0); - -} - -/* ------------------------------------------------------------------------- */ - -void cpShortColV(unsigned short *source, unsigned short *dest) -{ - dest[0] = source[0]; - dest[1] = source[1]; - dest[2] = source[2]; - dest[3] = source[3]; -} - -/* ------------------------------------------------------------------------- */ -void cpFloatColV(float *source, float *dest) -{ - dest[0] = source[0]; - dest[1] = source[1]; - dest[2] = source[2]; - dest[3] = source[3]; -} - -/* ------------------------------------------------------------------------- */ - -void cpCharColV(char *source, char *dest) -{ - dest[0] = source[0]; - dest[1] = source[1]; - dest[2] = source[2]; - dest[3] = source[3]; -} /* ------------------------------------------------------------------------- */ void addalphaAddfacFloat(float *dest, float *source, char addfac) @@ -353,43 +168,27 @@ void addalphaAddfacFloat(float *dest, float *source, char addfac) } -/* ------------------------------------------------------------------------- */ - -void sampleShortColV2ShortColV(unsigned short *sample, unsigned short *dest, int osaNr) -{ - unsigned int intcol[4] = {0}; - unsigned short *scol = sample; - int a = 0; - - for(a=0; a < osaNr; a++, scol+=4) { - intcol[0]+= scol[0]; intcol[1]+= scol[1]; - intcol[2]+= scol[2]; intcol[3]+= scol[3]; - } - - /* Now normalise the integrated colour. It is guaranteed */ - /* to be correctly bounded. */ - dest[0]= intcol[0]/osaNr; - dest[1]= intcol[1]/osaNr; - dest[2]= intcol[2]/osaNr; - dest[3]= intcol[3]/osaNr; - -} /* ------------------------------------------------------------------------- */ /* filtered adding to scanlines */ -void add_filt_fmask(unsigned int mask, float *col, float *rb1, float *rb2, float *rb3) +void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w) { /* calc the value of mask */ - extern float *fmask1[], *fmask2[]; + float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2; + float *rb1, *rb2, *rb3; float val, r, g, b, al; unsigned int a, maskand, maskshift; int j; - al= col[3]; r= col[0]; g= col[1]; b= col[2]; + al= col[3]; + + rb2= rowbuf-4; + rb1= rb2-4*row_w; + rb3= rb2+4*row_w; maskand= (mask & 255); maskshift= (mask >>8); @@ -400,28 +199,28 @@ void add_filt_fmask(unsigned int mask, float *col, float *rb1, float *rb2, float val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift); if(val!=0.0) { - rb1[3]+= val*al; rb1[0]+= val*r; rb1[1]+= val*g; rb1[2]+= val*b; + rb1[3]+= val*al; } a+=3; val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift); if(val!=0.0) { - rb2[3]+= val*al; rb2[0]+= val*r; rb2[1]+= val*g; rb2[2]+= val*b; + rb2[3]+= val*al; } a+=3; val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift); if(val!=0.0) { - rb3[3]+= val*al; rb3[0]+= val*r; rb3[1]+= val*g; rb3[2]+= val*b; + rb3[3]+= val*al; } rb1+= 4; @@ -430,186 +229,6 @@ void add_filt_fmask(unsigned int mask, float *col, float *rb1, float *rb2, float } } - -void sampleFloatColV2FloatColVFilter(float *sample, float *dest1, float *dest2, float *dest3, int osaNr) -{ - float intcol[4] = {0}; - float *scol = sample; - int a = 0; - - if(osaNr==1) { - dest2[4]= sample[0]; - dest2[5]= sample[1]; - dest2[6]= sample[2]; - dest2[7]= sample[3]; - } - else { - if (do_gamma) { - /* use a LUT and interpolation to do the gamma correction */ - for(a=0; a < osaNr; a++, scol+=4) { - intcol[0] = gammaCorrect( (scol[0]<1.0) ? scol[0]:1.0 ); - intcol[1] = gammaCorrect( (scol[1]<1.0) ? scol[1]:1.0 ); - intcol[2] = gammaCorrect( (scol[2]<1.0) ? scol[2]:1.0 ); - intcol[3] = scol[3]; - add_filt_fmask(1<<a, intcol, dest1, dest2, dest3); - } - } - else { - for(a=0; a < osaNr; a++, scol+=4) { - add_filt_fmask(1<<a, scol, dest1, dest2, dest3); - } - } - } - -} - -/* ------------------------------------------------------------------------- */ -/* The following functions are 'old' blending functions: */ - -/* ------------------------------------------------------------------------- */ -void keyalpha(char *doel) /* makes premul 255 */ -{ - int c; - short div; - div= doel[3]; - if (!div) - { - doel[0] = (doel[0] ? 255 : 0); - doel[1] = (doel[1] ? 255 : 0); - doel[2] = (doel[2] ? 255 : 0); - } else - { - c= (doel[0]<<8)/div; - if(c>255) doel[0]=255; - else doel[0]= c; - c= (doel[1]<<8)/div; - if(c>255) doel[1]=255; - else doel[1]= c; - c= (doel[2]<<8)/div; - if(c>255) doel[2]=255; - else doel[2]= c; - } -} - -/* ------------------------------------------------------------------------- */ -/* fills in bron (source) under doel (target) with alpha of doel*/ -void addalphaUnder(char *doel, char *bron) -{ - int c; - int mul; - - if(doel[3]==255) return; - if( doel[3]==0) { /* tested */ - *((unsigned int *)doel)= *((unsigned int *)bron); - return; - } - - mul= 255-doel[3]; - - c= doel[0]+ ((mul*bron[0])/255); - if(c>255) doel[0]=255; - else doel[0]= c; - c= doel[1]+ ((mul*bron[1])/255); - if(c>255) doel[1]=255; - else doel[1]= c; - c= doel[2]+ ((mul*bron[2])/255); - if(c>255) doel[2]=255; - else doel[2]= c; - - c= doel[3]+ ((mul*bron[3])/255); - if(c>255) doel[3]=255; - else doel[3]= c; - - /* doel[0]= MAX2(doel[0], bron[0]); */ -} - -/* ------------------------------------------------------------------------- */ -/* gamma-corrected */ -void addalphaUnderGamma(char *doel, char *bron) -{ - unsigned int tot; - int c, doe, bro; - int mul; - - /* if doel[3]==0 or doel==255 has been handled in sky loop */ - mul= 256-doel[3]; - - doe= igamtab1[(int)doel[0]]; - bro= igamtab1[(int)bron[0]]; - tot= (doe+ ((mul*bro)>>8)); - if(tot>65535) tot=65535; - doel[0]= *((gamtab+tot)) >>8; - - doe= igamtab1[(int)doel[1]]; - bro= igamtab1[(int)bron[1]]; - tot= (doe+ ((mul*bro)>>8)); - if(tot>65535) tot=65535; - doel[1]= *((gamtab+tot)) >>8; - - doe= igamtab1[(int)doel[2]]; - bro= igamtab1[(int)bron[2]]; - tot= (doe+ ((mul*bro)>>8)); - if(tot>65535) tot=65535; - doel[2]= *((gamtab+tot)) >>8; - - c= doel[3]+ ((mul*bron[3])/255); - if(c>255) doel[3]=255; - else doel[3]= c; - /* doel[0]= MAX2(doel[0], bron[0]); */ -} - -/* ------------------------------------------------------------------------- */ -/* doel= bron over doel */ -void addalphaOver(char *doel, char *bron) -{ - int c; - int mul; - - if(bron[3]==0) return; - if( bron[3]==255) { /* tested */ - *((unsigned int *)doel)= *((unsigned int *)bron); - return; - } - - mul= 255-bron[3]; - - c= ((mul*doel[0])/255)+bron[0]; - if(c>255) doel[0]=255; - else doel[0]= c; - c= ((mul*doel[1])/255)+bron[1]; - if(c>255) doel[1]=255; - else doel[1]= c; - c= ((mul*doel[2])/255)+bron[2]; - if(c>255) doel[2]=255; - else doel[2]= c; - c= ((mul*doel[3])/255)+bron[3]; - if(c>255) doel[3]=255; - else doel[3]= c; -} - -/* ------------------------------------------------------------------------- */ -void addalphaAdd(char *doel, char *bron) /* adds bron (source) to doel (target) */ -{ - int c; - - if( doel[3]==0 || bron[3]==255) { /* tested */ - *((unsigned int *)doel)= *((unsigned int *)bron); - return; - } - c= doel[0]+bron[0]; - if(c>255) doel[0]=255; - else doel[0]= c; - c= doel[1]+bron[1]; - if(c>255) doel[1]=255; - else doel[1]= c; - c= doel[2]+bron[2]; - if(c>255) doel[2]=255; - else doel[2]= c; - c= doel[3]+bron[3]; - if(c>255) doel[3]=255; - else doel[3]= c; -} - /* ------------------------------------------------------------------------- */ void addalphaAddFloat(float *dest, float *source) { @@ -631,44 +250,136 @@ void addalphaAddFloat(float *dest, float *source) } -/* ALPHADDFAC: - * - * Z= X alphaover Y: - * Zrgb= (1-Xa)*Yrgb + Xrgb - * - * (1-fac)*(1-Xa) + fac <=> - * 1-Xa-fac+fac*Xa+fac <=> - * Xa*(fac-1)+1 - */ +/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ -/* doel= bron over doel */ -void RE_addalphaAddfac(char *doel, char *bron, char addfac) +/* Colour buffer related: */ +/* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value */ +/* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd. */ +/* This is the standard transformation, more elaborate tools are for later. */ +/* ------------------------------------------------------------------------- */ +void std_floatcol_to_charcol( float *buf, char *target) { + float col[3]; + + float dither_value; + + dither_value = ((BLI_frand()-0.5)*R.r.dither_intensity)/256.0; - int c, mul; - - mul= 255 - (bron[3]*(255-addfac))/255; - - c= ((mul*doel[0])/255)+bron[0]; - if(c>255) doel[0]=255; - else doel[0]= c; - c= ((mul*doel[1])/255)+bron[1]; - if(c>255) doel[1]=255; - else doel[1]= c; - c= ((mul*doel[2])/255)+bron[2]; - if(c>255) doel[2]=255; - else doel[2]= c; + /* alpha */ + if((buf[3]+dither_value)<=0.0) target[3]= 0; + else if((buf[3]+dither_value)>1.0) target[3]= 255; + else target[3]= 255.0*(buf[3]+dither_value); + + if(R.r.postgamma==1.0) { + /* r */ + col[0]= R.r.postmul*buf[0] + R.r.postadd + dither_value; + /* g */ + col[1]= R.r.postmul*buf[1] + R.r.postadd + dither_value; + /* b */ + col[2]= R.r.postmul*buf[2] + R.r.postadd + dither_value; + } + else { + /* putting the postmul within the pow() gives an + * easier control for the user, values from 1.0-2.0 + * are relevant then + */ + + /* r */ + col[0]= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd + dither_value; + /* g */ + col[1]= pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd + dither_value; + /* b */ + col[2]= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd + dither_value; + } - /* c= ((mul*doel[3])/255)+bron[3]; */ - c= doel[3]+bron[3]; - if(c>255) doel[3]=255; - else doel[3]= c; + if(R.r.posthue!=0.0 || R.r.postsat!=1.0) { + float hsv[3]; + + rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2); + hsv[0]+= R.r.posthue; + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv[1]*= R.r.postsat; + if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); + } + + if(col[0]<=0.0) target[0]= 0; + else if(col[0]>1.0) target[0]= 255; + else target[0]= 255.0*col[0]; + + if(col[1]<=0.0) target[1]= 0; + else if(col[1]>1.0) target[1]= 255; + else target[1]= 255.0*col[1]; + + if(col[2]<=0.0) target[2]= 0; + else if(col[2]>1.0) target[2]= 255; + else target[2]= 255.0*col[2]; } +/* ---------------------------------------------------------------------------- + +Colour buffer related: + +The colour buffer is a buffer of a single screen line. It contains +four fields of type RE_COLBUFTYPE per pixel. + +We can do several post-process steps. I would prefer to move them outside +the render module later on, but it's ok to leave it here for now. For the +time being, we have: +- post-process function + Does some operations with the colours. +- Multiply with some factor +- Add constant offset +- Apply extra gamma correction (seems weird...) +- key-alpha correction + Key alpha means 'un-applying' the alpha. For fully covered pixels, this + operation has no effect. + +- XXX WARNING! Added the inverse render gamma here, so this cannot be used external + without setting Osa or Gamma flags off (ton) + +---------------------------------------------------------------------------- */ +/* used external! */ +void transferColourBufferToOutput( float *buf, int y) +{ + /* Copy the contents of AColourBuffer3 to R.rectot + y * R.rectx */ + int x = 0; +// char *target = (char*) (R.rectot + (y * R.rectx)); + + /* Copy the first <R.rectx> pixels. We can do some more clipping on */ + /* the z buffer, I think. */ + while (x < R.rectx) { + + + /* invert gamma corrected additions */ + if(R.do_gamma) { + buf[0] = invGammaCorrect(buf[0]); + buf[1] = invGammaCorrect(buf[1]); + buf[2] = invGammaCorrect(buf[2]); + } + +// std_floatcol_to_charcol(buf, target); + + /* + Key-alpha mode: + Need to un-apply alpha if alpha is non-full. For full alpha, + the operation doesn't have effect. Do this after the post- + processing, so we can still use the benefits of that. + + */ + + if (R.r.alphamode == R_ALPHAKEY) { +// applyKeyAlphaCharCol(target); + } + +// target+=4; + buf+=4; + x++; + } +} -/* ------------------------------------------------------------------------- */ /* eof pixelblending.c */ diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c index 4878b738767..53bce2cbb84 100644 --- a/source/blender/render/intern/source/pixelshading.c +++ b/source/blender/render/intern/source/pixelshading.c @@ -1,14 +1,11 @@ /** * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,17 +19,9 @@ * 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$ + * Contributor(s): 2004-2006, Blender Foundation, full recode * + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -57,105 +46,23 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" -#include "render.h" +/* own module */ +#include "render_types.h" +#include "renderpipeline.h" +#include "renderdatabase.h" #include "texture.h" - -#include "vanillaRenderPipe_types.h" #include "pixelblending.h" -#include "rendercore.h" /* for some shading functions... */ +#include "rendercore.h" #include "shadbuf.h" -#include "zbufferdatastruct.h" - -#include "renderHelp.h" - #include "gammaCorrectionTables.h" -#include "errorHandler.h" #include "pixelshading.h" +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* ton: - - unified render now uses face render routines from rendercore.c - - todo still: shalo render and sky routines */ - - -/* ------------------------------------------------------------------------- */ -static int calcHaloZ(HaloRen *har, int zz) -{ - - if(har->type & HA_ONLYSKY) { - if(zz!=0x7FFFFFFF) zz= - 0x7FFFFF; - } - else { - zz= (zz>>8); - } - return zz; -} - -static void *renderHaloPixel(RE_COLBUFTYPE *collector, float x, float y, int haloNr) -{ - HaloRen *har = NULL; - float dist = 0.0; - 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... (nzc) */ - /* it checks for sky... which is info not available in unified (ton) */ - zz = calcHaloZ(har, 0x7FFFFFFF); - if(zz> har->zs) { - - /* 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) */ - - - -/* ------------------------------------------------------------------------- */ - -void *renderPixel(RE_COLBUFTYPE *collector, float x, float y, int *obdata, int mask) -{ - void *data = NULL; - float rco[3]; /* not used (yet?) */ - - if (obdata[3] & RE_POLY) { - data = shadepixel(x, y, obdata[0], obdata[1], mask, collector, rco); - } - 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[0], obdata[1], mask, collector, rco); - } - return data; - -} /* end of void renderPixel(float x, float y, int *obdata) */ - -/* ------------------------------------------------------------------------- */ - -void renderSpotHaloPixel(float x, float y, float* fcol) -{ - float rco[3]; /* unused */ - shadepixel(x, y, 0, 0, 0, fcol, rco); -} - - -/* ------------------------------------------------------------------------- */ extern float hashvectf[]; @@ -537,29 +444,14 @@ void shadeHaloFloat(HaloRen *har, float *col, int zz, */ -/* 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, float *rco) +void renderSkyPixelFloat(float *collector, float x, float y, float *rco) { - switch (keyingType) { - case RE_ALPHA_PREMUL: - case RE_ALPHA_KEY: + switch (R.r.alphamode) { + case R_ALPHAPREMUL: + case R_ALPHAKEY: /* Premul or key: don't fill, and don't change the values! */ /* key alpha used to fill in color in 'empty' pixels, doesn't work anymore this way */ collector[0] = 0.0; @@ -567,7 +459,7 @@ void renderSkyPixelFloat(RE_COLBUFTYPE *collector, float x, float y, float *rco) collector[2] = 0.0; collector[3] = 0.0; break; - case RE_ALPHA_SKY: + case R_ADDSKY: /* Fill in the sky as if it were a normal face. */ shadeSkyPixel(collector, x, y, rco); collector[3]= 0.0; @@ -577,123 +469,10 @@ void renderSkyPixelFloat(RE_COLBUFTYPE *collector, float x, float y, float *rco) } } - - -/* - 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) -{ - struct ImBuf *ibuf; - int iy, ix; - unsigned int* imBufPtr; - - /* check to be sure... */ - if (R.backbuf==NULL || R.backbuf->ok==0) { - /* bail out */ - 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; - } - - ibuf= R.backbuf->ibuf; - - /* Now for the real extraction: */ - /* Get the y-coordinate of the scanline? */ - ix= (int) (0.5f + ( ((x+R.afmx+R.xstart)/(float)R.r.xsch))*(float)ibuf->x); - iy= (int) (0.5f + ( ((y+R.afmy+R.ystart)/(float)R.r.ysch))*(float)ibuf->y); - - /* correct in case of fields rendering: */ - if(R.flag & R_SEC_FIELD) { - if((R.r.mode & R_ODDFIELD)==0) { - if( iy<ibuf->y) iy++; - } - else { - if( iy>0) iy--; - } - } - - /* Offset into the buffer: start of scanline y: */ - imBufPtr = ibuf->rect - + (iy * ibuf->x) - + ix; - - *( (int *)col) = *imBufPtr; - -} - -static void fillBackgroundImage(float *col, float x, float y) -{ - struct ImBuf *ibuf; - int iy, ix; - - /* check to be sure... */ - if (R.backbuf==NULL || R.backbuf->ok==0) { - /* bail out */ - col[0] = 0; - col[1] = 0; - col[2] = 0; - col[3] = 255; - return; - } - /* load image if not already done?*/ - if(R.backbuf->ibuf==NULL) { - R.backbuf->ok= 0; - return; - } - - ibuf= R.backbuf->ibuf; - - /* Now for the real extraction: */ - /* Get the y-coordinate of the scanline? */ - ix= (int) (( ((x+R.afmx+R.xstart)/(float)R.r.xsch))*(float)ibuf->x); - iy= (int) (( ((y+R.afmy+R.ystart)/(float)R.r.ysch))*(float)ibuf->y); - - /* correct in case of fields rendering: */ - if(R.flag & R_SEC_FIELD) { - if((R.r.mode & R_ODDFIELD)==0) { - if( iy<ibuf->y) iy++; - } - else { - if( iy>0) iy--; - } - } - - CLAMP(ix, 0, ibuf->x-1); - CLAMP(iy, 0, ibuf->y-1); - - /* Offset into the buffer: start of scanline y: */ - if(ibuf->rect_float) { - float *fp = ibuf->rect_float + 4*(iy * ibuf->x + ix); - QUATCOPY(col, fp); - } - else { - char *cp = (char *)(ibuf->rect + (iy * ibuf->x) + ix); - - col[0]= (1.0f/255.0f) * (float)cp[0]; - col[1]= (1.0f/255.0f) * (float)cp[1]; - col[2]= (1.0f/255.0f) * (float)cp[2]; - col[3]= (1.0f/255.0f) * (float)cp[3]; - } - -} - /* Stuff the sky colour into the collector. */ -void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco) +void shadeSkyPixel(float *collector, float fx, float fy, float *rco) { float view[3], dxyview[2]; @@ -707,7 +486,7 @@ void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco) /* 1. Do a backbuffer image: */ if(R.r.bufflag & 1) { - fillBackgroundImage(collector, fx, fy); +// fillBackgroundImage(collector, fx, fy); return; } else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) { /* @@ -730,26 +509,17 @@ void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco) /* 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[0]= (fx/(float)R.winx); + view[1]= (fy/(float)R.winy); view[2]= 0.0; - dxyview[0]= 1.0/(float)R.afmx; - dxyview[1]= 1.0/(float)R.afmy; + dxyview[0]= 1.0f/(float)R.winx; + dxyview[1]= 1.0f/(float)R.winy; } 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; - + calc_view_vector(view, fx, fy); fac= Normalise(view); + if(R.wrld.skytype & WO_SKYTEX) { dxyview[0]= 1.0/fac; dxyview[1]= R.ycor/fac; @@ -757,15 +527,10 @@ void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco) } if(R.r.mode & R_PANORAMA) { - float panoco, panosi; - float u, v; - - panoco = getPanovCo(); - panosi = getPanovSi(); - u= view[0]; v= view[2]; + float u= view[0]; float v= view[2]; - view[0]= panoco*u + panosi*v; - view[2]= -panosi*u + panoco*v; + view[0]= R.panoco*u + R.panosi*v; + view[2]= -R.panosi*u + R.panoco*v; } /* get sky colour in the collector */ diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c index a91219846de..19ec1dd546d 100644 --- a/source/blender/render/intern/source/ray.c +++ b/source/blender/render/intern/source/ray.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,15 +20,16 @@ * The Original Code is Copyright (C) 1990-1998 NeoGeo BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: 2004/2005 Blender Foundation, full recode * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> #include <string.h> #include <stdlib.h> +#include <float.h> #include "MEM_guardedalloc.h" @@ -42,17 +40,16 @@ #include "BKE_global.h" #include "BLI_arithb.h" -#include <BLI_rand.h> +#include "BLI_rand.h" +#include "BLI_jitter.h" -#include "render.h" +#include "render_types.h" +#include "renderpipeline.h" #include "rendercore.h" #include "pixelblending.h" #include "pixelshading.h" -#include "jitter.h" #include "texture.h" -#include "SDL_thread.h" - #define DDA_SHADOW 0 #define DDA_MIRROR 1 #define DDA_SHADOW_TRA 2 @@ -61,23 +58,17 @@ #define RAY_TRAFLIP 2 #define DEPTH_SHADOW_TRA 10 -/* from float.h */ -#define FLT_EPSILON 1.19209290e-07F +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* ********** structs *************** */ #define BRANCH_ARRAY 1024 - -typedef struct Octree { - struct Branch *adrbranch[BRANCH_ARRAY]; - struct Node *adrnode[4096]; - float ocsize; /* ocsize: mult factor, max size octree */ - float ocfacx,ocfacy,ocfacz; - float min[3], max[3]; - int ocres; - -} Octree; +#define NODE_ARRAY 4096 typedef struct Isect { float start[3], vec[3], end[3]; /* start+vec = end, in d3dda */ @@ -112,16 +103,10 @@ typedef struct Node /* ******** globals ***************** */ -static Octree g_oc; /* can be scene pointer or so later... */ - /* just for statistics */ -static int raycount, branchcount, nodecount; +static int raycount; static int accepted, rejected, coherent_ray; -/* prototypes ------------------------ */ -void freeoctree(void); -void makeoctree(void); -int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr); /* **************** ocval method ******************* */ /* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */ @@ -190,36 +175,42 @@ static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, /* ************* octree ************** */ -static Branch *addbranch(Branch *br, short oc) +static Branch *addbranch(Octree *oc, Branch *br, short ocb) { + int index; - if(br->b[oc]) return br->b[oc]; + if(br->b[ocb]) return br->b[ocb]; - branchcount++; - if(g_oc.adrbranch[branchcount>>12]==NULL) - g_oc.adrbranch[branchcount>>12]= MEM_callocN(4096*sizeof(Branch),"addbranch"); + oc->branchcount++; + index= oc->branchcount>>12; + + if(oc->adrbranch[index]==NULL) + oc->adrbranch[index]= MEM_callocN(4096*sizeof(Branch), "new oc branch"); - if(branchcount>= BRANCH_ARRAY*4096) { + if(oc->branchcount>= BRANCH_ARRAY*4096) { printf("error; octree branches full\n"); - branchcount=0; + oc->branchcount=0; } - return br->b[oc]=g_oc.adrbranch[branchcount>>12]+(branchcount & 4095); + return br->b[ocb]= oc->adrbranch[index]+(oc->branchcount & 4095); } -static Node *addnode(void) +static Node *addnode(Octree *oc) { + int index; + + oc->nodecount++; + index= oc->nodecount>>12; - nodecount++; - if(g_oc.adrnode[nodecount>>12]==NULL) - g_oc.adrnode[nodecount>>12]= MEM_callocN(4096*sizeof(Node),"addnode"); + if(oc->adrnode[index]==NULL) + oc->adrnode[index]= MEM_callocN(4096*sizeof(Node),"addnode"); - if(nodecount> 4096*4096) { + if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) { printf("error; octree nodes full\n"); - nodecount=0; + oc->nodecount=0; } - return g_oc.adrnode[nodecount>>12]+(nodecount & 4095); + return oc->adrnode[index]+(oc->nodecount & 4095); } static int face_in_node(VlakRen *vlr, short x, short y, short z, float rtf[][3]) @@ -262,7 +253,7 @@ static int face_in_node(VlakRen *vlr, short x, short y, short z, float rtf[][3]) return 0; } -static void ocwrite(VlakRen *vlr, short x, short y, short z, float rtf[][3]) +static void ocwrite(Octree *oc, VlakRen *vlr, short x, short y, short z, float rtf[][3]) { Branch *br; Node *no; @@ -273,19 +264,19 @@ static void ocwrite(VlakRen *vlr, short x, short y, short z, float rtf[][3]) x<<=2; y<<=1; - br= g_oc.adrbranch[0]; + br= oc->adrbranch[0]; - if(g_oc.ocres==512) { + if(oc->ocres==512) { oc0= ((x & 1024)+(y & 512)+(z & 256))>>8; - br= addbranch(br, oc0); + br= addbranch(oc, br, oc0); } - if(g_oc.ocres>=256) { + if(oc->ocres>=256) { oc0= ((x & 512)+(y & 256)+(z & 128))>>7; - br= addbranch(br, oc0); + br= addbranch(oc, br, oc0); } - if(g_oc.ocres>=128) { + if(oc->ocres>=128) { oc0= ((x & 256)+(y & 128)+(z & 64))>>6; - br= addbranch(br, oc0); + br= addbranch(oc, br, oc0); } oc0= ((x & 128)+(y & 64)+(z & 32))>>5; @@ -295,19 +286,19 @@ static void ocwrite(VlakRen *vlr, short x, short y, short z, float rtf[][3]) oc4= ((x & 8)+(y & 4)+(z & 2))>>1; oc5= ((x & 4)+(y & 2)+(z & 1)); - br= addbranch(br,oc0); - br= addbranch(br,oc1); - br= addbranch(br,oc2); - br= addbranch(br,oc3); - br= addbranch(br,oc4); + br= addbranch(oc, br,oc0); + br= addbranch(oc, br,oc1); + br= addbranch(oc, br,oc2); + br= addbranch(oc, br,oc3); + br= addbranch(oc, br,oc4); no= (Node *)br->b[oc5]; - if(no==NULL) br->b[oc5]= (Branch *)(no= addnode()); + if(no==NULL) br->b[oc5]= (Branch *)(no= addnode(oc)); while(no->next) no= no->next; a= 0; if(no->v[7]) { /* node full */ - no->next= addnode(); + no->next= addnode(oc); no= no->next; } else { @@ -320,7 +311,7 @@ static void ocwrite(VlakRen *vlr, short x, short y, short z, float rtf[][3]) } -static void d2dda(short b1, short b2, short c1, short c2, char *ocvlak, short rts[][3], float rtf[][3]) +static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[][3], float rtf[][3]) { int ocx1,ocx2,ocy1,ocy2; int x,y,dx=0,dy=0; @@ -333,7 +324,7 @@ static void d2dda(short b1, short b2, short c1, short c2, char *ocvlak, short rt ocy2= rts[b2][c2]; if(ocx1==ocx2 && ocy1==ocy2) { - ocvlak[g_oc.ocres*ocx1+ocy1]= 1; + ocface[oc->ocres*ocx1+ocy1]= 1; return; } @@ -377,8 +368,8 @@ static void d2dda(short b1, short b2, short c1, short c2, char *ocvlak, short rt while(TRUE) { - if(x<0 || y<0 || x>=g_oc.ocres || y>=g_oc.ocres); - else ocvlak[g_oc.ocres*x+y]= 1; + if(x<0 || y<0 || x>=oc->ocres || y>=oc->ocres); + else ocface[oc->ocres*x+y]= 1; labdao=labda; if(labdax==labday) { @@ -399,10 +390,10 @@ static void d2dda(short b1, short b2, short c1, short c2, char *ocvlak, short rt if(labda==labdao) break; if(labda>=1.0) break; } - ocvlak[g_oc.ocres*ocx2+ocy2]=1; + ocface[oc->ocres*ocx2+ocy2]=1; } -static void filltriangle(short c1, short c2, char *ocvlak, short *ocmin) +static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin) { short *ocmax; int a, x, y, y1, y2; @@ -410,14 +401,14 @@ static void filltriangle(short c1, short c2, char *ocvlak, short *ocmin) ocmax=ocmin+3; for(x=ocmin[c1];x<=ocmax[c1];x++) { - a= g_oc.ocres*x; + a= oc->ocres*x; for(y=ocmin[c2];y<=ocmax[c2];y++) { - if(ocvlak[a+y]) { + if(ocface[a+y]) { y++; - while(ocvlak[a+y] && y!=ocmax[c2]) y++; + while(ocface[a+y] && y!=ocmax[c2]) y++; for(y1=ocmax[c2];y1>y;y1--) { - if(ocvlak[a+y1]) { - for(y2=y;y2<=y1;y2++) ocvlak[a+y2]=1; + if(ocface[a+y1]) { + for(y2=y;y2<=y1;y2++) ocface[a+y2]=1; y1=0; } } @@ -427,35 +418,45 @@ static void filltriangle(short c1, short c2, char *ocvlak, short *ocmin) } } -void freeoctree(void) +void freeoctree(Render *re) { - int a= 0; - - while(g_oc.adrbranch[a]) { - MEM_freeN(g_oc.adrbranch[a]); - g_oc.adrbranch[a]= NULL; - a++; - } - - a= 0; - while(g_oc.adrnode[a]) { - MEM_freeN(g_oc.adrnode[a]); - g_oc.adrnode[a]= NULL; - a++; - } + Octree *oc= &re->oc; if(G.f & G_DEBUG) { - printf("branches %d nodes %d\n", branchcount, nodecount); + printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount); printf("raycount %d \n", raycount); printf("ray coherent %d \n", coherent_ray); printf("accepted %d rejected %d\n", accepted, rejected); } - branchcount= 0; - nodecount= 0; + + if(oc->adrbranch) { + int a= 0; + while(oc->adrbranch[a]) { + MEM_freeN(oc->adrbranch[a]); + oc->adrbranch[a]= NULL; + a++; + } + MEM_freeN(oc->adrbranch); + oc->adrbranch= NULL; + } + oc->branchcount= 0; + + if(oc->adrnode) { + int a= 0; + while(oc->adrnode[a]) { + MEM_freeN(oc->adrnode[a]); + oc->adrnode[a]= NULL; + a++; + } + MEM_freeN(oc->adrnode); + oc->adrnode= NULL; + } + oc->nodecount= 0; } -void makeoctree(void) +void makeoctree(Render *re) { + Octree *oc; VlakRen *vlr=NULL; VertRen *v1, *v2, *v3, *v4; float ocfac[3], t00, t01, t02; @@ -463,68 +464,68 @@ void makeoctree(void) int v; int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2; short rts[4][3], ocmin[6], *ocmax; - char *ocvlak; // front, top, size view of face, to fill in + char *ocface; // front, top, size view of face, to fill in - ocmax= ocmin+3; + oc= &re->oc; + oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches"); + oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes"); - memset(g_oc.adrnode, 0, sizeof(g_oc.adrnode)); - memset(g_oc.adrbranch, 0, sizeof(g_oc.adrbranch)); + ocmax= ocmin+3; - branchcount=0; - nodecount=0; + /* only for debug info */ raycount=0; accepted= 0; rejected= 0; coherent_ray= 0; /* fill main octree struct */ - g_oc.ocres= R.r.ocres; - ocres2= g_oc.ocres*g_oc.ocres; - INIT_MINMAX(g_oc.min, g_oc.max); + oc->ocres= re->r.ocres; + ocres2= oc->ocres*oc->ocres; + INIT_MINMAX(oc->min, oc->max); /* first min max octree space */ - for(v=0;v<R.totvlak;v++) { - if((v & 255)==0) vlr= R.blovl[v>>8]; + for(v=0;v<re->totvlak;v++) { + if((v & 255)==0) vlr= re->blovl[v>>8]; else vlr++; if(vlr->mat->mode & MA_TRACEBLE) { if((vlr->mat->mode & MA_WIRE)==0) { - DO_MINMAX(vlr->v1->co, g_oc.min, g_oc.max); - DO_MINMAX(vlr->v2->co, g_oc.min, g_oc.max); - DO_MINMAX(vlr->v3->co, g_oc.min, g_oc.max); + DO_MINMAX(vlr->v1->co, oc->min, oc->max); + DO_MINMAX(vlr->v2->co, oc->min, oc->max); + DO_MINMAX(vlr->v3->co, oc->min, oc->max); if(vlr->v4) { - DO_MINMAX(vlr->v4->co, g_oc.min, g_oc.max); + DO_MINMAX(vlr->v4->co, oc->min, oc->max); } } } } - if(g_oc.min[0] > g_oc.max[0]) return; /* empty octree */ + if(oc->min[0] > oc->max[0]) return; /* empty octree */ - g_oc.adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree"); + oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree"); /* the lookup table, per face, for which nodes to fill in */ - ocvlak= MEM_callocN( 3*ocres2 + 8, "ocvlak"); - memset(ocvlak, 0, 3*ocres2); + ocface= MEM_callocN( 3*ocres2 + 8, "ocface"); + memset(ocface, 0, 3*ocres2); for(c=0;c<3;c++) { /* octree enlarge, still needed? */ - g_oc.min[c]-= 0.01; - g_oc.max[c]+= 0.01; + oc->min[c]-= 0.01; + oc->max[c]+= 0.01; } - t00= g_oc.max[0]-g_oc.min[0]; - t01= g_oc.max[1]-g_oc.min[1]; - t02= g_oc.max[2]-g_oc.min[2]; + t00= oc->max[0]-oc->min[0]; + t01= oc->max[1]-oc->min[1]; + t02= oc->max[2]-oc->min[2]; /* this minus 0.1 is old safety... seems to be needed? */ - g_oc.ocfacx=ocfac[0]= (g_oc.ocres-0.1)/t00; - g_oc.ocfacy=ocfac[1]= (g_oc.ocres-0.1)/t01; - g_oc.ocfacz=ocfac[2]= (g_oc.ocres-0.1)/t02; + oc->ocfacx=ocfac[0]= (oc->ocres-0.1)/t00; + oc->ocfacy=ocfac[1]= (oc->ocres-0.1)/t01; + oc->ocfacz=ocfac[2]= (oc->ocres-0.1)/t02; - g_oc.ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */ + oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */ - for(v=0; v<R.totvlak; v++) { - if((v & 255)==0) vlr= R.blovl[v>>8]; + for(v=0; v<re->totvlak; v++) { + if((v & 255)==0) vlr= re->blovl[v>>8]; else vlr++; if(vlr->mat->mode & MA_TRACEBLE) { @@ -536,14 +537,14 @@ void makeoctree(void) v4= vlr->v4; for(c=0;c<3;c++) { - rtf[0][c]= (v1->co[c]-g_oc.min[c])*ocfac[c] ; + rtf[0][c]= (v1->co[c]-oc->min[c])*ocfac[c] ; rts[0][c]= (short)rtf[0][c]; - rtf[1][c]= (v2->co[c]-g_oc.min[c])*ocfac[c] ; + rtf[1][c]= (v2->co[c]-oc->min[c])*ocfac[c] ; rts[1][c]= (short)rtf[1][c]; - rtf[2][c]= (v3->co[c]-g_oc.min[c])*ocfac[c] ; + rtf[2][c]= (v3->co[c]-oc->min[c])*ocfac[c] ; rts[2][c]= (short)rtf[2][c]; if(v4) { - rtf[3][c]= (v4->co[c]-g_oc.min[c])*ocfac[c] ; + rtf[3][c]= (v4->co[c]-oc->min[c])*ocfac[c] ; rts[3][c]= (short)rtf[3][c]; } } @@ -563,44 +564,44 @@ void makeoctree(void) ocmin[c]= MIN4(oc1,oc2,oc3,oc4); ocmax[c]= MAX4(oc1,oc2,oc3,oc4); } - if(ocmax[c]>g_oc.ocres-1) ocmax[c]=g_oc.ocres-1; + if(ocmax[c]>oc->ocres-1) ocmax[c]=oc->ocres-1; if(ocmin[c]<0) ocmin[c]=0; } - d2dda(0,1,0,1,ocvlak+ocres2,rts,rtf); - d2dda(0,1,0,2,ocvlak,rts,rtf); - d2dda(0,1,1,2,ocvlak+2*ocres2,rts,rtf); - d2dda(1,2,0,1,ocvlak+ocres2,rts,rtf); - d2dda(1,2,0,2,ocvlak,rts,rtf); - d2dda(1,2,1,2,ocvlak+2*ocres2,rts,rtf); + d2dda(oc, 0,1,0,1,ocface+ocres2,rts,rtf); + d2dda(oc, 0,1,0,2,ocface,rts,rtf); + d2dda(oc, 0,1,1,2,ocface+2*ocres2,rts,rtf); + d2dda(oc, 1,2,0,1,ocface+ocres2,rts,rtf); + d2dda(oc, 1,2,0,2,ocface,rts,rtf); + d2dda(oc, 1,2,1,2,ocface+2*ocres2,rts,rtf); if(v4==NULL) { - d2dda(2,0,0,1,ocvlak+ocres2,rts,rtf); - d2dda(2,0,0,2,ocvlak,rts,rtf); - d2dda(2,0,1,2,ocvlak+2*ocres2,rts,rtf); + d2dda(oc, 2,0,0,1,ocface+ocres2,rts,rtf); + d2dda(oc, 2,0,0,2,ocface,rts,rtf); + d2dda(oc, 2,0,1,2,ocface+2*ocres2,rts,rtf); } else { - d2dda(2,3,0,1,ocvlak+ocres2,rts,rtf); - d2dda(2,3,0,2,ocvlak,rts,rtf); - d2dda(2,3,1,2,ocvlak+2*ocres2,rts,rtf); - d2dda(3,0,0,1,ocvlak+ocres2,rts,rtf); - d2dda(3,0,0,2,ocvlak,rts,rtf); - d2dda(3,0,1,2,ocvlak+2*ocres2,rts,rtf); + d2dda(oc, 2,3,0,1,ocface+ocres2,rts,rtf); + d2dda(oc, 2,3,0,2,ocface,rts,rtf); + d2dda(oc, 2,3,1,2,ocface+2*ocres2,rts,rtf); + d2dda(oc, 3,0,0,1,ocface+ocres2,rts,rtf); + d2dda(oc, 3,0,0,2,ocface,rts,rtf); + d2dda(oc, 3,0,1,2,ocface+2*ocres2,rts,rtf); } /* nothing todo with triangle..., just fills :) */ - filltriangle(0,1,ocvlak+ocres2,ocmin); - filltriangle(0,2,ocvlak,ocmin); - filltriangle(1,2,ocvlak+2*ocres2,ocmin); + filltriangle(oc, 0,1,ocface+ocres2,ocmin); + filltriangle(oc, 0,2,ocface,ocmin); + filltriangle(oc, 1,2,ocface+2*ocres2,ocmin); /* init static vars here */ face_in_node(vlr, 0,0,0, rtf); for(x=ocmin[0];x<=ocmax[0];x++) { - a= g_oc.ocres*x; + a= oc->ocres*x; for(y=ocmin[1];y<=ocmax[1];y++) { - if(ocvlak[a+y+ocres2]) { - b= g_oc.ocres*y+2*ocres2; + if(ocface[a+y+ocres2]) { + b= oc->ocres*y+2*ocres2; for(z=ocmin[2];z<=ocmax[2];z++) { - if(ocvlak[b+z] && ocvlak[a+z]) ocwrite(vlr, x,y,z, rtf); + if(ocface[b+z] && ocface[a+z]) ocwrite(oc, vlr, x,y,z, rtf); } } } @@ -608,17 +609,17 @@ void makeoctree(void) /* same loops to clear octree, doubt it can be done smarter */ for(x=ocmin[0];x<=ocmax[0];x++) { - a= g_oc.ocres*x; + a= oc->ocres*x; for(y=ocmin[1];y<=ocmax[1];y++) { /* x-y */ - ocvlak[a+y+ocres2]= 0; + ocface[a+y+ocres2]= 0; - b= g_oc.ocres*y + 2*ocres2; + b= oc->ocres*y + 2*ocres2; for(z=ocmin[2];z<=ocmax[2];z++) { /* y-z */ - ocvlak[b+z]= 0; + ocface[b+z]= 0; /* x-z */ - ocvlak[a+z]= 0; + ocface[a+z]= 0; } } } @@ -626,7 +627,7 @@ void makeoctree(void) } } - MEM_freeN(ocvlak); + MEM_freeN(ocface); } /* ************ raytracer **************** */ @@ -1007,23 +1008,23 @@ static Node *ocread(int x, int y, int z) x<<=2; y<<=1; - br= g_oc.adrbranch[0]; + br= R.oc.adrbranch[0]; - if(g_oc.ocres==512) { + if(R.oc.ocres==512) { oc1= ((x & 1024)+(y & 512)+(z & 256))>>8; br= br->b[oc1]; if(br==NULL) { return NULL; } } - if(g_oc.ocres>=256) { + if(R.oc.ocres>=256) { oc1= ((x & 512)+(y & 256)+(z & 128))>>7; br= br->b[oc1]; if(br==NULL) { return NULL; } } - if(g_oc.ocres>=128) { + if(R.oc.ocres>=128) { oc1= ((x & 256)+(y & 128)+(z & 64))>>6; br= br->b[oc1]; if(br==NULL) { @@ -1127,7 +1128,7 @@ static int d3dda(Isect *is) int ocx1,ocx2,ocy1, ocy2,ocz1,ocz2; /* clip with octree */ - if(branchcount==0) return 0; + if(R.oc.branchcount==0) return 0; /* do this before intersect calls */ is->vlrcontr= NULL; /* to check shared edge */ @@ -1150,14 +1151,14 @@ static int d3dda(Isect *is) u2= 1.0; /* clip with octree cube */ - if(cliptest(-ldx, is->start[0]-g_oc.min[0], &u1,&u2)) { - if(cliptest(ldx, g_oc.max[0]-is->start[0], &u1,&u2)) { + if(cliptest(-ldx, is->start[0]-R.oc.min[0], &u1,&u2)) { + if(cliptest(ldx, R.oc.max[0]-is->start[0], &u1,&u2)) { ldy= is->end[1] - is->start[1]; - if(cliptest(-ldy, is->start[1]-g_oc.min[1], &u1,&u2)) { - if(cliptest(ldy, g_oc.max[1]-is->start[1], &u1,&u2)) { + if(cliptest(-ldy, is->start[1]-R.oc.min[1], &u1,&u2)) { + if(cliptest(ldy, R.oc.max[1]-is->start[1], &u1,&u2)) { ldz= is->end[2] - is->start[2]; - if(cliptest(-ldz, is->start[2]-g_oc.min[2], &u1,&u2)) { - if(cliptest(ldz, g_oc.max[2]-is->start[2], &u1,&u2)) { + if(cliptest(-ldz, is->start[2]-R.oc.min[2], &u1,&u2)) { + if(cliptest(ldz, R.oc.max[2]-is->start[2], &u1,&u2)) { c1=1; if(u2<1.0) { is->end[0]= is->start[0]+u2*ldx; @@ -1179,15 +1180,15 @@ static int d3dda(Isect *is) if(c1==0) return 0; /* reset static variables in ocread */ - //ocread(g_oc.ocres, 0, 0); + //ocread(R.oc.ocres, 0, 0); /* setup 3dda to traverse octree */ - ox1= (is->start[0]-g_oc.min[0])*g_oc.ocfacx; - oy1= (is->start[1]-g_oc.min[1])*g_oc.ocfacy; - oz1= (is->start[2]-g_oc.min[2])*g_oc.ocfacz; - ox2= (is->end[0]-g_oc.min[0])*g_oc.ocfacx; - oy2= (is->end[1]-g_oc.min[1])*g_oc.ocfacy; - oz2= (is->end[2]-g_oc.min[2])*g_oc.ocfacz; + ox1= (is->start[0]-R.oc.min[0])*R.oc.ocfacx; + oy1= (is->start[1]-R.oc.min[1])*R.oc.ocfacy; + oz1= (is->start[2]-R.oc.min[2])*R.oc.ocfacz; + ox2= (is->end[0]-R.oc.min[0])*R.oc.ocfacx; + oy2= (is->end[1]-R.oc.min[1])*R.oc.ocfacy; + oz2= (is->end[2]-R.oc.min[2])*R.oc.ocfacz; ocx1= (int)ox1; ocy1= (int)oy1; @@ -1522,9 +1523,9 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen float ref[3]; VECCOPY(isec.start, start); - isec.end[0]= start[0]+g_oc.ocsize*vec[0]; - isec.end[1]= start[1]+g_oc.ocsize*vec[1]; - isec.end[2]= start[2]+g_oc.ocsize*vec[2]; + isec.end[0]= start[0]+R.oc.ocsize*vec[0]; + isec.end[1]= start[1]+R.oc.ocsize*vec[1]; + isec.end[2]= start[2]+R.oc.ocsize*vec[2]; isec.mode= DDA_MIRROR; isec.vlrorig= vlr; @@ -1712,7 +1713,7 @@ void init_jitter_plane(LampRen *lar) } /* table around origin, -0.5*size to 0.5*size */ -static float *give_jitter_plane(LampRen *lar, int xs, int ys) +static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys) { int tot; @@ -1720,7 +1721,7 @@ static float *give_jitter_plane(LampRen *lar, int xs, int ys) if(lar->ray_samp_type & LA_SAMP_JITTER) { /* made it threadsafe */ - if(ys & 1) { + if(thread & 1) { if(lar->xold1!=xs || lar->yold1!=ys) { jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(1), BLI_thread_frand(1)); lar->xold1= xs; lar->yold1= ys; @@ -1886,9 +1887,9 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) vec[2]-= vec[2]; } VECCOPY(isec.start, ship->co); - isec.end[0]= isec.start[0] + g_oc.ocsize*vec[0]; - isec.end[1]= isec.start[1] + g_oc.ocsize*vec[1]; - isec.end[2]= isec.start[2] + g_oc.ocsize*vec[2]; + isec.end[0]= isec.start[0] + R.oc.ocsize*vec[0]; + isec.end[1]= isec.start[1] + R.oc.ocsize*vec[1]; + isec.end[2]= isec.start[2] + R.oc.ocsize*vec[2]; if( d3dda(&isec)) { float fac; @@ -1976,13 +1977,13 @@ void init_ao_sphere(float *sphere, int tot, int iter) } -static float *threadsafe_table_sphere(int test, int xs, int ys) +static float *threadsafe_table_sphere(int test, int thread, int xs, int ys) { static float sphere1[2*3*256]; static float sphere2[2*3*256]; static int xs1=-1, xs2=-1, ys1=-1, ys2=-1; - if(ys & 1) { + if(thread & 1) { if(xs==xs1 && ys==ys1) return sphere1; if(test) return NULL; xs1= xs; ys1= ys; @@ -1996,7 +1997,7 @@ static float *threadsafe_table_sphere(int test, int xs, int ys) } } -static float *sphere_sampler(int type, int resol, int xs, int ys) +static float *sphere_sampler(int type, int resol, int thread, int xs, int ys) { int tot; float *vec; @@ -2023,14 +2024,14 @@ static float *sphere_sampler(int type, int resol, int xs, int ys) float ang, *vec1; int a; - sphere= threadsafe_table_sphere(1, xs, ys); // returns table if xs and ys were equal to last call + sphere= threadsafe_table_sphere(1, thread, xs, ys); // returns table if xs and ys were equal to last call if(sphere==NULL) { - sphere= threadsafe_table_sphere(0, xs, ys); + sphere= threadsafe_table_sphere(0, thread, xs, ys); // random rotation - ang= BLI_thread_frand(ys & 1); + ang= BLI_thread_frand(thread); sinfi= sin(ang); cosfi= cos(ang); - ang= BLI_thread_frand(ys & 1); + ang= BLI_thread_frand(thread); sint= sin(ang); cost= cos(ang); vec= R.wrld.aosphere; @@ -2047,11 +2048,11 @@ static float *sphere_sampler(int type, int resol, int xs, int ys) /* extern call from shade_lamp_loop, ambient occlusion calculus */ -void ray_ao(ShadeInput *shi, World *wrld, float *shadfac) +void ray_ao(ShadeInput *shi, float *shadfac) { Isect isec; float *vec, *nrm, div, bias, sh=0; - float maxdist = wrld->aodist; + float maxdist = R.wrld.aodist; int j= -1, tot, actual=0, skyadded=0; isec.vlrorig= shi->vlr; @@ -2071,10 +2072,10 @@ void ray_ao(ShadeInput *shi, World *wrld, float *shadfac) nrm= shi->facenor; } - vec= sphere_sampler(wrld->aomode, wrld->aosamp, shi->xs, shi->ys); + vec= sphere_sampler(R.wrld.aomode, R.wrld.aosamp, shi->thread, shi->xs, shi->ys); // warning: since we use full sphere now, and dotproduct is below, we do twice as much - tot= 2*wrld->aosamp*wrld->aosamp; + tot= 2*R.wrld.aosamp*R.wrld.aosamp; while(tot--) { @@ -2099,10 +2100,10 @@ void ray_ao(ShadeInput *shi, World *wrld, float *shadfac) /* do the trace */ if (d3dda(&isec)) { - if (wrld->aomode & WO_AODIST) sh+= exp(-isec.labda*wrld->aodistfac); + if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); else sh+= 1.0; } - else if(wrld->aocolor!=WO_AOPLAIN) { + else if(R.wrld.aocolor!=WO_AOPLAIN) { float skycol[4]; float fac, view[3]; @@ -2111,7 +2112,7 @@ void ray_ao(ShadeInput *shi, World *wrld, float *shadfac) view[2]= -vec[2]; Normalise(view); - if(wrld->aocolor==WO_AOSKYCOL) { + if(R.wrld.aocolor==WO_AOSKYCOL) { fac= 0.5*(1.0+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); shadfac[0]+= (1.0-fac)*R.wrld.horr + fac*R.wrld.zenr; shadfac[1]+= (1.0-fac)*R.wrld.horg + fac*R.wrld.zeng; @@ -2133,7 +2134,7 @@ void ray_ao(ShadeInput *shi, World *wrld, float *shadfac) if(actual==0) shadfac[3]= 1.0; else shadfac[3] = 1.0 - sh/((float)actual); - if(wrld->aocolor!=WO_AOPLAIN && skyadded) { + if(R.wrld.aocolor!=WO_AOPLAIN && skyadded) { div= shadfac[3]/((float)skyadded); shadfac[0]*= div; // average color times distances/hits formula @@ -2162,9 +2163,9 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) if(lar->type==LA_SUN || lar->type==LA_HEMI) { - lampco[0]= shi->co[0] - g_oc.ocsize*lar->vec[0]; - lampco[1]= shi->co[1] - g_oc.ocsize*lar->vec[1]; - lampco[2]= shi->co[2] - g_oc.ocsize*lar->vec[2]; + lampco[0]= shi->co[0] - R.oc.ocsize*lar->vec[0]; + lampco[1]= shi->co[1] - R.oc.ocsize*lar->vec[1]; + lampco[2]= shi->co[2] - R.oc.ocsize*lar->vec[2]; } else { VECCOPY(lampco, lar->co); @@ -2202,7 +2203,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) else shadfac[3]= 1.0; // 1.0=full light fac= 0.0; - jitlamp= give_jitter_plane(lar, shi->xs, shi->ys); + jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys); a= lar->ray_totsamp; @@ -2284,9 +2285,9 @@ void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co) if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1; if(lar->type==LA_SUN || lar->type==LA_HEMI) { - lampco[0]= shi->co[0] - g_oc.ocsize*lar->vec[0]; - lampco[1]= shi->co[1] - g_oc.ocsize*lar->vec[1]; - lampco[2]= shi->co[2] - g_oc.ocsize*lar->vec[2]; + lampco[0]= shi->co[0] - R.oc.ocsize*lar->vec[0]; + lampco[1]= shi->co[1] - R.oc.ocsize*lar->vec[1]; + lampco[2]= shi->co[2] - R.oc.ocsize*lar->vec[2]; } else { VECCOPY(lampco, lar->co); diff --git a/source/blender/render/intern/source/renderHelp.c b/source/blender/render/intern/source/renderHelp.c deleted file mode 100644 index aba78079472..00000000000 --- a/source/blender/render/intern/source/renderHelp.c +++ /dev/null @@ -1,306 +0,0 @@ -/** - * - * ***** 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 ***** - * Some helpful conversions/functions. - * - * $Id$ - */ - -#include <math.h> -#include <limits.h> -#include <stdlib.h> - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "BKE_utildefines.h" -#include "BLI_arithb.h" - -#include "render.h" -#include "renderHelp.h" -#include "zbuf.h" - -static float panovco, panovsi; -static float panophi=0.0; -static float tempPanoPhi; - -static int panotestclip(float *v); - -void pushTempPanoPhi(float p) { - tempPanoPhi = panophi; - panophi = p; -} - -void popTempPanoPhi() { - panophi = tempPanoPhi; -} - -float getPanoPhi(){ - return panophi; -} -float getPanovCo(){ - return panovco; -} -float getPanovSi(){ - return panovsi; -} - -void setPanoRot(int part) -{ -/* extern float panovco, panovsi; */ - static float alpha= 1.0; - - /* part==0 init all */ - - if(part==0) { - - alpha= ((float)R.r.xsch)/R.viewfac; - alpha= 2.0*atan(alpha/2.0); - } - - - /* rotate it all around the y-as with phi degrees */ - - panophi= -0.5*(R.r.xparts-1)*alpha + part*alpha; - - panovsi= sin(-panophi); - panovco= cos(-panophi); - -} - - - - -static int panotestclip(float *v) -{ - /* to be used for halos en infos */ - float abs4; - short c=0; - - if((R.r.mode & R_PANORAMA)==0) return RE_testclip(v); - - abs4= fabs(v[3]); - - if(v[2]< -abs4) c=16; /* this used to be " if(v[2]<0) ", see clippz() */ - else if(v[2]> abs4) c+= 32; - - if( v[1]>abs4) c+=4; - else if( v[1]< -abs4) c+=8; - - abs4*= R.r.xparts; - if( v[0]>abs4) c+=2; - else if( v[0]< -abs4) c+=1; - - return c; -} - -/* - - This adds the hcs coordinates to vertices. It iterates over all - vertices, halos and faces. After the conversion, we clip in hcs. - - Elsewhere, all primites are converted to vertices. - Called in - - envmapping (envmap.c) - - shadow buffering (shadbuf.c) - - preparation for rendering (renderPreAndPost.c) - -*/ - -/* move to renderer */ -void setzbufvlaggen( void (*projectfunc)(float *, float *) ) -/* homocos too */ -{ - VlakRen *vlr = NULL; - VertRen *ver = NULL; - HaloRen *har = NULL; - float zn, vec[3], si, co, hoco[4]; - int a; - float panophi = 0.0; - - panophi = getPanoPhi(); - si= sin(panophi); - co= cos(panophi); - - /* calculate view coordinates (and zbuffer value) */ - for(a=0; a< R.totvert;a++) { - if((a & 255)==0) ver= RE_findOrAddVert(a); - else ver++; - - if(R.r.mode & R_PANORAMA) { - vec[0]= co*ver->co[0] + si*ver->co[2]; - vec[1]= ver->co[1]; - vec[2]= -si*ver->co[0] + co*ver->co[2]; - } - else { - VECCOPY(vec, ver->co); - } - /* Go from wcs to hcs ... */ - projectfunc(vec, ver->ho); - /* ... and clip in that system. */ - ver->clip = RE_testclip(ver->ho); - /* - Because all other ops are performed in other systems, this is - the only thing that has to be done. - */ - } - - /* calculate view coordinates (and zbuffer value) */ - for(a=0; a<R.tothalo; a++) { - if((a & 255)==0) har= R.bloha[a>>8]; - else har++; - - if(R.r.mode & R_PANORAMA) { - vec[0]= co*har->co[0] + si*har->co[2]; - vec[1]= har->co[1]; - vec[2]= -si*har->co[0] + co*har->co[2]; - } - else { - VECCOPY(vec, har->co); - } - - projectfunc(vec, hoco); - - /* we clip halos less critical, but not for the Z */ - hoco[0]*= 0.5; - hoco[1]*= 0.5; - - if( panotestclip(hoco) ) { - har->miny= har->maxy= -10000; /* that way render clips it */ - } - else if(hoco[3]<0.0) { - har->miny= har->maxy= -10000; /* render clips it */ - } - else /* do the projection...*/ - { - /* bring back hocos */ - hoco[0]*= 2.0; - hoco[1]*= 2.0; - - zn= hoco[3]; - har->xs= 0.5*R.rectx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/ - har->ys= 0.5*R.recty*(1.0+hoco[1]/zn); - - /* this should be the zbuffer coordinate */ - har->zs= 0x7FFFFF*(hoco[2]/zn); - /* taking this from the face clip functions? seems ok... */ - har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); - - vec[0]+= har->hasize; - projectfunc(vec, hoco); - vec[0]-= har->hasize; - zn= hoco[3]; - har->rad= fabs(har->xs- 0.5*R.rectx*(1.0+hoco[0]/zn)); - - /* this clip is not really OK, to prevent stars to become too large */ - if(har->type & HA_ONLYSKY) { - if(har->rad>3.0) har->rad= 3.0; - } - - har->radsq= har->rad*har->rad; - - har->miny= har->ys - har->rad/R.ycor; - har->maxy= har->ys + har->rad/R.ycor; - - /* the Zd value is still not really correct for pano */ - - vec[2]-= har->hasize; /* z negative, otherwise it's clipped */ - projectfunc(vec, hoco); - zn= hoco[3]; - zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn)); - har->zd= CLAMPIS(zn, 0, INT_MAX); - - } - - } - - /* set flags at 0 if clipped away */ - for(a=0; a<R.totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; - else vlr++; - - vlr->flag |= R_VISIBLE; - if(vlr->v4) { - if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip & vlr->v4->clip) vlr->flag &= ~R_VISIBLE; - } - else if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip) vlr->flag &= ~R_VISIBLE; - - } - -} - -/* ------------------------------------------------------------------------- */ -/* move to renderer */ - -void set_normalflags(void) -{ - VlakRen *vlr = NULL; - float *v1, xn, yn, zn; - int a1, doflip; - - /* switch normal 'snproj' values (define which axis is the optimal one for calculations) */ - for(a1=0; a1<R.totvlak; a1++) { - if((a1 & 255)==0) vlr= R.blovl[a1>>8]; - else vlr++; - - /* abuse of this flag... this is code that just sets face normal in direction of camera */ - /* that convention we should get rid of */ - if((vlr->flag & R_NOPUNOFLIP)==0) { - - doflip= 0; - if(R.r.mode & R_ORTHO) { - if(vlr->n[2]>0.0) doflip= 1; - } - else { - v1= vlr->v1->co; - if( (v1[0]*vlr->n[0] +v1[1]*vlr->n[1] +v1[2]*vlr->n[2])<0.0 ) doflip= 1; - } - if(doflip) { - vlr->n[0]= -vlr->n[0]; - vlr->n[1]= -vlr->n[1]; - vlr->n[2]= -vlr->n[2]; - } - } - - /* recalculate puno. Displace & flipped matrices can screw up */ - vlr->puno= 0; - if(!(vlr->flag & R_TANGENT)) { - if( Inpf(vlr->n, vlr->v1->n) < 0.0 ) vlr->puno |= ME_FLIPV1; - if( Inpf(vlr->n, vlr->v2->n) < 0.0 ) vlr->puno |= ME_FLIPV2; - if( Inpf(vlr->n, vlr->v3->n) < 0.0 ) vlr->puno |= ME_FLIPV3; - if(vlr->v4 && Inpf(vlr->n, vlr->v4->n) < 0.0 ) vlr->puno |= ME_FLIPV4; - } - xn= fabs(vlr->n[0]); - yn= fabs(vlr->n[1]); - zn= fabs(vlr->n[2]); - if(zn>=xn && zn>=yn) vlr->snproj= 0; - else if(yn>=xn && yn>=zn) vlr->snproj= 1; - else vlr->snproj= 2; - - } -} diff --git a/source/blender/render/intern/source/renderPreAndPost.c b/source/blender/render/intern/source/renderPreAndPost.c deleted file mode 100644 index 0753a73276b..00000000000 --- a/source/blender/render/intern/source/renderPreAndPost.c +++ /dev/null @@ -1,103 +0,0 @@ -/** - * - * ***** 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 ***** - * Prepare the scene data for rendering. - * - * $Id$ - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_group_types.h" - -#include "render.h" -#include "renderPreAndPost.h" -#include "RE_callbacks.h" - -#include "shadbuf.h" -#include "envmap.h" -#include "renderHelp.h" -#include "radio.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/** - * Rotate all objects, make shadowbuffers and environment maps. - */ -void prepareScene() -{ - GroupObject *go; - extern void makeoctree(void); - - RE_local_get_renderdata(); - - /* SHADOW BUFFER */ - for(go=R.lights.first; go; go= go->next) { - LampRen *lar= go->lampren; - if(lar->shb) makeshadowbuf(lar); - if(RE_local_test_break()) break; - } - - /* yafray: 'direct' radiosity, environment maps and octree init not needed for yafray render */ - /* although radio mode could be useful at some point, later */ - if (R.r.renderer==R_INTERN) { - - /* RADIO */ - if(R.r.mode & R_RADIO) do_radio_render(); - - /* octree */ - if(R.r.mode & R_RAYTRACE) makeoctree(); - - /* ENVIRONMENT MAPS */ - make_envmaps(); - - } -} - -void finalizeScene(void) -{ - extern void freeoctree(void); - - /* Among other things, it releases the shadow buffers. */ - RE_local_free_renderdata(); - /* yafray: freeoctree not needed after yafray render, not initialized, see above */ - if (R.r.renderer==R_INTERN) { - if(R.r.mode & R_RAYTRACE) freeoctree(); - } -} - - -void doClipping( void (*projectfunc)(float *, float *) ) -{ - setzbufvlaggen(projectfunc); -} - -/* eof */ diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 379b5415604..b226346ede9 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,11 +20,10 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: Hos, Robert Wenzlaff. + * Contributors: 2004/2005/2006 Blender Foundation, full recode * - * Contributor(s): Hos, Robert Wenzlaff. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ /* system includes */ @@ -36,83 +32,81 @@ #include <stdlib.h> /* External modules: */ -#include "MEM_guardedalloc.h" -#include "BLI_arithb.h" #include "MTC_matrixops.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_jitter.h" #include "BKE_utildefines.h" -#include "DNA_camera_types.h" #include "DNA_group_types.h" #include "DNA_image_types.h" #include "DNA_lamp_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_texture_types.h" #include "BKE_global.h" +#include "BKE_material.h" #include "BKE_node.h" #include "BKE_texture.h" -#include "BLI_rand.h" - /* local include */ -#include "RE_callbacks.h" -#include "render.h" -#include "zbuf.h" /* stuff like bgnaccumbuf, fillrect, ...*/ +#include "renderpipeline.h" +#include "render_types.h" +#include "renderdatabase.h" #include "pixelblending.h" #include "pixelshading.h" -#include "vanillaRenderPipe.h" /* transfercolour... */ #include "gammaCorrectionTables.h" #include "shadbuf.h" -#include "renderHelp.h" +#include "zbuf.h" -#include "jitter.h" #include "texture.h" /* own include */ #include "rendercore.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "SDL_thread.h" - -/* global for this file. struct render will be more dynamic later, to allow multiple renderers */ -RE_Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -float bluroffsx=0.0, bluroffsy=0.0; // set in initrender.c (bad, ton) - -/* x and y are current pixels to be rendered */ +/* x and y are current pixels in rect to be rendered */ +/* do not normalize! */ void calc_view_vector(float *view, float x, float y) { - + if(R.r.mode & R_ORTHO) { view[0]= view[1]= 0.0; } else { - view[0]= (x+(R.xstart)+bluroffsx +0.5); + /* move x and y to real viewplane coords */ + x= (x/(float)R.winx); + view[0]= R.viewplane.xmin + x*(R.viewplane.xmax - R.viewplane.xmin); - if(R.flag & R_SEC_FIELD) { - if(R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor; - else view[1]= (y+R.ystart+1.0)*R.ycor; - } - else view[1]= (y+R.ystart+bluroffsy+0.5)*R.ycor; - } - view[2]= -R.viewfac; + y= (y/(float)R.winy); + view[1]= R.viewplane.ymin + y*(R.viewplane.ymax - R.viewplane.ymin); + +// if(R.flag & R_SEC_FIELD) { +// if(R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor; +// else view[1]= (y+R.ystart+1.0)*R.ycor; +// } +// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor; + } + + view[2]= -R.clipsta; if(R.r.mode & R_PANORAMA) { - float panoco, panosi, u, v; - panoco = getPanovCo(); - panosi = getPanovSi(); - - u= view[0]; v= view[2]; - view[0]= panoco*u + panosi*v; - view[2]= -panosi*u + panoco*v; + float u= view[0]; float v= view[2]; + view[0]= R.panoco*u + R.panosi*v; + view[2]= -R.panosi*u + R.panoco*v; } + } #if 0 @@ -194,32 +188,6 @@ float mistfactor(float zcor, float *co) /* dist en height, return alpha */ return (1.0-fac)* (1.0-R.wrld.misi); } -/* external for preview only */ -void RE_sky_char(float *view, char *col) -{ - float f, colf[3]; - float dither_value; - - dither_value = ( (BLI_frand()-0.5)*R.r.dither_intensity)/256.0; - - shadeSkyPixelFloat(colf, view, view, NULL); - - f= 255.0*(colf[0]+dither_value); - if(f<=0.0) col[0]= 0; else if(f>255.0) col[0]= 255; - else col[0]= (char)f; - f= 255.0*(colf[1]+dither_value); - if(f<=0.0) col[1]= 0; else if(f>255.0) col[1]= 255; - else col[1]= (char)f; - f= 255.0*(colf[2]+dither_value); - if(f<=0.0) col[2]= 0; else if(f>255.0) col[2]= 255; - else col[2]= (char)f; - col[3]= 1; /* to prevent wrong optimalisation alphaover of flares */ -} - - -/* ************************************** */ - - static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens) { double a, b, c, disc, nray[3], npos[3]; @@ -433,9 +401,18 @@ static void renderspothalo(ShadeInput *shi, float *col, float alpha) } -static int calchalo_z(HaloRen *har, int zz) + +/* also used in zbuf.c */ +int count_mask(unsigned short mask) { + if(R.samples) + return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]); + return 0; +} +static int calchalo_z(HaloRen *har, int zz) +{ + if(har->type & HA_ONLYSKY) { if(zz!=0x7FFFFFFF) zz= - 0x7FFFFF; } @@ -445,186 +422,119 @@ static int calchalo_z(HaloRen *har, int zz) return zz; } -static void scanlinehaloPS(int *rectz, long *rectdelta, float *rowbuf, short ys) +static void halo_pixelstruct(HaloRen *har, float *rb, float dist, float xn, float yn, PixStr *ps) { - HaloRen *har = NULL; - PixStr *ps; - float dist, xsq, ysq, xn, yn; - float *rb; float col[4], accol[4]; - int a, *rz, zz, didgamma=0; - long *rd; - short minx, maxx, x, amount, amountm, flarec; - - for(a=0; a<R.tothalo; a++) { - if((a & 255)==0) { - har= R.bloha[a>>8]; - if( RE_local_test_break() ) break; - } - else har++; - - if(ys>har->maxy); - else if(ys<har->miny); - else { - minx= floor(har->xs-har->rad); - maxx= ceil(har->xs+har->rad); + int amount, amountm, zz, flarec; + + amount= 0; + accol[0]=accol[1]=accol[2]=accol[3]= 0.0; + flarec= har->flarec; + + while(ps) { + amountm= count_mask(ps->mask); + amount+= amountm; + + zz= calchalo_z(har, ps->z); + if(zz> har->zs) { + float fac; - if(maxx<0); - else if(R.rectx<minx); - else { - if(minx<0) minx= 0; - if(maxx>=R.rectx) maxx= R.rectx-1; - - rb= rowbuf + 4*minx; - rd= rectdelta + minx; - rz= rectz + minx; - - yn= (ys-har->ys)*R.ycor; - ysq= yn*yn; - for(x=minx; x<=maxx; x++) { - - xn= x-har->xs; - xsq= xn*xn; - dist= xsq+ysq; - - if(dist<har->radsq) { - - /* well yah, halo adding shouldnt be done gamma corrected, have to bypass it this way */ - /* alternative is moving it outside of thread renderlineDA */ - /* on positive side; the invert correct cancels out correcting halo color */ - if(do_gamma && didgamma==0) { - float *buf= rowbuf; - int xt; - for(xt=0; xt<R.rectx; xt++, buf+=4) { - buf[0]= sasqrt(buf[0]); // invers gamma 2.0 - buf[1]= sasqrt(buf[1]); - buf[2]= sasqrt(buf[2]); - } - didgamma= 1; - } - - flarec= har->flarec; /* har->pixels is only allowed to count once */ - - if(*rd) { /* theres a pixel struct */ - - ps= (PixStr *)(*rd); - amount= 0; - accol[0]=accol[1]=accol[2]=accol[3]= 0.0; - - while(ps) { - amountm= count_mask(ps->mask); - amount+= amountm; - - zz= calchalo_z(har, ps->z); - if(zz> har->zs) { - float fac; - - shadeHaloFloat(har, col, zz, dist, xn, yn, flarec); - fac= ((float)amountm)/(float)R.osa; - accol[0]+= fac*col[0]; - accol[1]+= fac*col[1]; - accol[2]+= fac*col[2]; - accol[3]+= fac*col[3]; - flarec= 0; - } - - ps= ps->next; - } - /* now do the sky sub-pixels */ - amount= R.osa-amount; - if(amount) { - float fac; - - shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec); - fac= ((float)amount)/(float)R.osa; - accol[0]+= fac*col[0]; - accol[1]+= fac*col[1]; - accol[2]+= fac*col[2]; - accol[3]+= fac*col[3]; - } - col[0]= accol[0]; - col[1]= accol[1]; - col[2]= accol[2]; - col[3]= accol[3]; - - addalphaAddfacFloat(rb, col, har->add); - } - else { - zz= calchalo_z(har, *rz); - if(zz> har->zs) { - - shadeHaloFloat(har, col, zz, dist, xn, yn, flarec); - addalphaAddfacFloat(rb, col, har->add); - } - } - } - rb+=4; - rz++; - rd++; - } - } + shadeHaloFloat(har, col, zz, dist, xn, yn, flarec); + fac= ((float)amountm)/(float)R.osa; + accol[0]+= fac*col[0]; + accol[1]+= fac*col[1]; + accol[2]+= fac*col[2]; + accol[3]+= fac*col[3]; + flarec= 0; } + + ps= ps->next; } + /* now do the sky sub-pixels */ + amount= R.osa-amount; + if(amount) { + float fac; - /* the entire scanline has to be put back in gammaspace */ - if(didgamma) { - float *buf= rowbuf; - int xt; - for(xt=0; xt<R.rectx; xt++, buf+=4) { - buf[0]*= (buf[0]); // gamma 2.0 - buf[1]*= (buf[1]); - buf[2]*= (buf[2]); - } + shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec); + fac= ((float)amount)/(float)R.osa; + accol[0]+= fac*col[0]; + accol[1]+= fac*col[1]; + accol[2]+= fac*col[2]; + accol[3]+= fac*col[3]; } - + col[0]= accol[0]; + col[1]= accol[1]; + col[2]= accol[2]; + col[3]= accol[3]; + + addalphaAddfacFloat(rb, col, har->add); + } -static void scanlinehalo(int *rectz, float *rowbuf, short ys) +static void halo_tile(RenderPart *pa, float *pass) { HaloRen *har = NULL; + rcti disprect= pa->disprect; float dist, xsq, ysq, xn, yn, *rb; float col[4]; - int a, *rz, zz; - short minx, maxx, x; + long *rd= NULL; + int a, *rz, zz, y; + short minx, maxx, miny, maxy, x; for(a=0; a<R.tothalo; a++) { - if((a & 255)==0) har= R.bloha[a>>8]; + if((a & 255)==0) { + if(R.test_break() ) break; + har= R.bloha[a>>8]; + } else har++; - if(RE_local_test_break() ) break; - - if(ys>har->maxy); - else if(ys<har->miny); + /* clip halo with y */ + if(disprect.ymin > har->maxy); + else if(disprect.ymax < har->miny); else { + minx= floor(har->xs-har->rad); maxx= ceil(har->xs+har->rad); - if(maxx<0); - else if(R.rectx<minx); + if(disprect.xmin > maxx); + else if(disprect.xmax < minx); else { - if(minx<0) minx= 0; - if(maxx>=R.rectx) maxx= R.rectx-1; - - rb= rowbuf + 4*minx; - rz= rectz + minx; - - yn= (ys-har->ys)*R.ycor; - ysq= yn*yn; - for(x=minx; x<=maxx; x++) { - zz= calchalo_z(har, *rz); - if(zz> har->zs) { + minx= MAX2(minx, disprect.xmin); + maxx= MIN2(maxx, disprect.xmax); + + miny= MAX2(har->miny, disprect.ymin); + maxy= MIN2(har->maxy, disprect.ymax); + + for(y=miny; y<maxy; y++) { + int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin); + rb= pass + 4*rectofs; + rz= pa->rectz + rectofs; + + if(pa->rectdaps) + rd= pa->rectdaps + rectofs; + + yn= (y-har->ys)*R.ycor; + ysq= yn*yn; + + for(x=minx; x<maxx; x++, rb+=4, rz++) { xn= x- har->xs; xsq= xn*xn; dist= xsq+ysq; if(dist<har->radsq) { - shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec); - addalphaAddfacFloat(rb, col, har->add); + if(rd && *rd) { + halo_pixelstruct(har, rb, dist, xn, yn, (PixStr *)*rd); + } + else { + zz= calchalo_z(har, *rz); + if(zz> har->zs) { + shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec); + addalphaAddfacFloat(rb, col, har->add); + } + } } + if(rd) rd++; } - - rb+=4; - rz++; } } } @@ -727,7 +637,7 @@ static float area_lamp_energy(float *co, float *vn, LampRen *lar) return pow(fac*lar->areasize, lar->k); // corrected for buttons size and lar->dist^2 } -float spec(float inp, int hard) +static float spec(float inp, int hard) { float b1; @@ -767,7 +677,7 @@ float spec(float inp, int hard) return inp; } -float Phong_Spec( float *n, float *l, float *v, int hard, int tangent ) +static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent ) { float h[3]; float rslt; @@ -788,7 +698,7 @@ float Phong_Spec( float *n, float *l, float *v, int hard, int tangent ) /* reduced cook torrance spec (for off-specular peak) */ -float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent) +static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent) { float i, nh, nv, h[3]; @@ -812,7 +722,7 @@ float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent) } /* Blinn spec */ -float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent) +static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent) { float i, nh, nv, nl, vh, h[3]; float a, b, c, g=0.0, p, f, ang; @@ -866,7 +776,7 @@ float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, i } /* cartoon render spec */ -float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent) +static float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent) { float h[3]; float ang; @@ -890,7 +800,7 @@ float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tan } /* Ward isotropic gaussian spec */ -float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent) +static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent) { float i, nh, nv, nl, h[3], angle, alpha; @@ -916,13 +826,13 @@ float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent) angle = tan(saacos(nh)); alpha = MAX2(rms,0.001); - i= nl * (1.0/(4*PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl))); + i= nl * (1.0/(4*M_PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl))); return i; } /* cartoon render diffuse */ -float Toon_Diff( float *n, float *l, float *v, float size, float smooth ) +static float Toon_Diff( float *n, float *l, float *v, float size, float smooth ) { float rslt, ang; @@ -941,7 +851,7 @@ float Toon_Diff( float *n, float *l, float *v, float size, float smooth ) /* 'nl' is either dot product, or return value of area light */ /* in latter case, only last multiplication uses 'nl' */ -static float OrenNayar_Diff_i(float nl, float *n, float *l, float *v, float rough ) +static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough ) { float i, nh, nv, vh, realnl, h[3]; float a, b, t, A, B; @@ -1000,15 +910,8 @@ static float OrenNayar_Diff_i(float nl, float *n, float *l, float *v, float roug return i; } -/* Oren Nayar diffuse */ -float OrenNayar_Diff(float *n, float *l, float *v, float rough ) -{ - float nl= n[0]*l[0] + n[1]*l[1] + n[2]*l[2]; - return OrenNayar_Diff_i(nl, n, l, v, rough); -} - /* Minnaert diffuse */ -float Minnaert_Diff(float nl, float *n, float *v, float darkness) +static float Minnaert_Diff(float nl, float *n, float *v, float darkness) { float i, nv; @@ -1030,7 +933,7 @@ float Minnaert_Diff(float nl, float *n, float *v, float darkness) return i; } -float Fresnel_Diff(float *vn, float *lv, float *view, float fac_i, float fac) +static float Fresnel_Diff(float *vn, float *lv, float *view, float fac_i, float fac) { return fresnel_fac(lv, vn, fac_i, fac); } @@ -1084,6 +987,7 @@ void calc_R_ref(ShadeInput *shi) } +/* called from ray.c */ void shade_color(ShadeInput *shi, ShadeResult *shr) { Material *ma= shi->mat; @@ -1114,91 +1018,8 @@ void shade_color(ShadeInput *shi, ShadeResult *shr) shr->alpha= shi->alpha; } -/* r g b = current value, col = new value, fac==0 is no change */ -/* if g==NULL, it only does r channel */ -void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col) -{ - float tmp, facm= 1.0-fac; - - switch (type) { - case MA_RAMP_BLEND: - *r = facm*(*r) + fac*col[0]; - if(g) { - *g = facm*(*g) + fac*col[1]; - *b = facm*(*b) + fac*col[2]; - } - break; - case MA_RAMP_ADD: - *r += fac*col[0]; - if(g) { - *g += fac*col[1]; - *b += fac*col[2]; - } - break; - case MA_RAMP_MULT: - *r *= (facm + fac*col[0]); - if(g) { - *g *= (facm + fac*col[1]); - *b *= (facm + fac*col[2]); - } - break; - case MA_RAMP_SCREEN: - *r = 1.0 - (facm + fac*(1.0 - col[0])) * (1.0 - *r); - if(g) { - *g = 1.0 - (facm + fac*(1.0 - col[1])) * (1.0 - *g); - *b = 1.0 - (facm + fac*(1.0 - col[2])) * (1.0 - *b); - } - break; - case MA_RAMP_SUB: - *r -= fac*col[0]; - if(g) { - *g -= fac*col[1]; - *b -= fac*col[2]; - } - break; - case MA_RAMP_DIV: - if(col[0]!=0.0) - *r = facm*(*r) + fac*(*r)/col[0]; - if(g) { - if(col[1]!=0.0) - *g = facm*(*g) + fac*(*g)/col[1]; - if(col[2]!=0.0) - *b = facm*(*b) + fac*(*b)/col[2]; - } - break; - case MA_RAMP_DIFF: - *r = facm*(*r) + fac*fabs(*r-col[0]); - if(g) { - *g = facm*(*g) + fac*fabs(*g-col[1]); - *b = facm*(*b) + fac*fabs(*b-col[2]); - } - break; - case MA_RAMP_DARK: - tmp= fac*col[0]; - if(tmp < *r) *r= tmp; - if(g) { - tmp= fac*col[1]; - if(tmp < *g) *g= tmp; - tmp= fac*col[2]; - if(tmp < *b) *b= tmp; - } - break; - case MA_RAMP_LIGHT: - tmp= fac*col[0]; - if(tmp > *r) *r= tmp; - if(g) { - tmp= fac*col[1]; - if(tmp > *g) *g= tmp; - tmp= fac*col[2]; - if(tmp > *b) *b= tmp; - } - break; - } - -} - /* ramp for at end of shade */ -void ramp_diffuse_result(float *diff, ShadeInput *shi) +static void ramp_diffuse_result(float *diff, ShadeInput *shi) { Material *ma= shi->mat; float col[4], fac=0; @@ -1218,7 +1039,7 @@ void ramp_diffuse_result(float *diff, ShadeInput *shi) } /* r,g,b denote energy, ramp is used with different values to make new material color */ -void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b) +static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b) { Material *ma= shi->mat; float col[4], colt[3], fac=0; @@ -1267,7 +1088,7 @@ void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, fl } } -void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi) +static void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi) { Material *ma= shi->mat; float col[4]; @@ -1286,7 +1107,7 @@ void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi) } /* is = dot product shade, t = spec energy */ -void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec) +static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec) { Material *ma= shi->mat; float col[4]; @@ -1323,32 +1144,32 @@ void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec) -static void ambient_occlusion(World *wrld, ShadeInput *shi, ShadeResult *shr) +static void ambient_occlusion(ShadeInput *shi, ShadeResult *shr) { float f, shadfac[4]; - if((wrld->mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) && shi->amb!=0.0) { - ray_ao(shi, wrld, shadfac); + if((R.wrld.mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) && shi->amb!=0.0) { + ray_ao(shi, shadfac); - if(wrld->aocolor==WO_AOPLAIN) { - if (wrld->aomix==WO_AOADDSUB) shadfac[3] = 2.0*shadfac[3]-1.0; - else if (wrld->aomix==WO_AOSUB) shadfac[3] = shadfac[3]-1.0; + if(R.wrld.aocolor==WO_AOPLAIN) { + if (R.wrld.aomix==WO_AOADDSUB) shadfac[3] = 2.0*shadfac[3]-1.0; + else if (R.wrld.aomix==WO_AOSUB) shadfac[3] = shadfac[3]-1.0; - f= wrld->aoenergy*shadfac[3]*shi->amb; + f= R.wrld.aoenergy*shadfac[3]*shi->amb; add_to_diffuse(shr->diff, shi, f, f, f, f); } else { - if (wrld->aomix==WO_AOADDSUB) { + if (R.wrld.aomix==WO_AOADDSUB) { shadfac[0] = 2.0*shadfac[0]-1.0; shadfac[1] = 2.0*shadfac[1]-1.0; shadfac[2] = 2.0*shadfac[2]-1.0; } - else if (wrld->aomix==WO_AOSUB) { + else if (R.wrld.aomix==WO_AOSUB) { shadfac[0] = shadfac[0]-1.0; shadfac[1] = shadfac[1]-1.0; shadfac[2] = shadfac[2]-1.0; } - f= wrld->aoenergy*shi->amb; + f= R.wrld.aoenergy*shi->amb; add_to_diffuse(shr->diff, shi, f, f*shadfac[0], f*shadfac[1], f*shadfac[2]); } } @@ -1410,7 +1231,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) if(lar->shb) i = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp); else { float shad[4]; - //ray_shadow(shi, lar, shad); + ray_shadow(shi, lar, shad); i= shad[3]; } @@ -1435,7 +1256,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) /* single sided? */ if( shi->facenor[0]*lv[0] + shi->facenor[1]*lv[1] + shi->facenor[2]*lv[2] > -0.01) { - //ray_shadow(shi, lar, shad); + ray_shadow(shi, lar, shad); shadfac[3]+= shad[3]; ir+= 1.0; } @@ -1451,7 +1272,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) if((R.wrld.mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) && shi->amb!=0.0) { float f; - ray_ao(shi, &R.wrld, shadfac); // shadfac==0: full light + ray_ao(shi, shadfac); // shadfac==0: full light shadfac[3]= 1.0-shadfac[3]; f= R.wrld.aoenergy*shadfac[3]*shi->amb; @@ -1511,7 +1332,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) shr->diff[2]= shi->b*shi->emit; } - ambient_occlusion(&R.wrld, shi, shr); + ambient_occlusion(shi, shr); for(go=lights->first; go; go= go->next) { lar= go->lampren; @@ -1681,7 +1502,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) } /* diffuse shaders (oren nayer gets inp from area light) */ - if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff_i(inp, vn, lv, view, ma->roughness); + if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness); else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]); else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness); else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]); @@ -1709,7 +1530,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp); } else if(lar->mode & LA_SHAD_RAY) { - //ray_shadow(shi, lar, shadfac); + ray_shadow(shi, lar, shadfac); } /* warning, here it skips the loop */ @@ -2016,9 +1837,9 @@ void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, i if(mode & MA_TANGENT_V) { float *s1, *s2, *s3; - s1= RE_vertren_get_tangent(v1, 0); - s2= RE_vertren_get_tangent(v2, 0); - s3= RE_vertren_get_tangent(v3, 0); + s1= RE_vertren_get_tangent(&R, v1, 0); + s2= RE_vertren_get_tangent(&R, v2, 0); + s3= RE_vertren_get_tangent(&R, v3, 0); if(s1 && s2 && s3) { shi->tang[0]= (l*s3[0] - u*s1[0] - v*s2[0]); shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]); @@ -2177,9 +1998,9 @@ void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, i if(mode & MA_RADIO) { float *r1, *r2, *r3; - r1= RE_vertren_get_rad(v1, 0); - r2= RE_vertren_get_rad(v2, 0); - r3= RE_vertren_get_rad(v3, 0); + r1= RE_vertren_get_rad(&R, v1, 0); + r2= RE_vertren_get_rad(&R, v2, 0); + r3= RE_vertren_get_rad(&R, v3, 0); if(r1 && r2 && r3) { shi->rad[0]= (l*r3[0] - u*r1[0] - v*r2[0]); @@ -2200,9 +2021,9 @@ void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, i if(texco & TEXCO_STRESS) { float *s1, *s2, *s3; - s1= RE_vertren_get_stress(v1, 0); - s2= RE_vertren_get_stress(v2, 0); - s3= RE_vertren_get_stress(v3, 0); + s1= RE_vertren_get_stress(&R, v1, 0); + s2= RE_vertren_get_stress(&R, v2, 0); + s3= RE_vertren_get_stress(&R, v3, 0); if(s1 && s2 && s3) { shi->stress= l*s3[0] - u*s1[0] - v*s2[0]; if(shi->stress<1.0f) shi->stress-= 1.0f; @@ -2250,18 +2071,6 @@ static float isec_view_line(float *view, float *v3, float *v4) } #endif -void matlayer_blend(MaterialLayer *ml, float blendfac, ShadeResult *target, ShadeResult *src) -{ - - if(ml->flag & ML_DIFFUSE) - ramp_blend(ml->blendmethod, target->diff, target->diff+1, target->diff+2, blendfac*src->alpha, src->diff); - - if(ml->flag & ML_SPECULAR) - ramp_blend(ml->blendmethod, target->spec, target->spec+1, target->spec+2, blendfac*src->alpha, src->spec); - - if(ml->flag & ML_ALPHA) - ramp_blend(ml->blendmethod, &target->alpha, NULL, NULL, blendfac, &src->alpha); -} /* also used as callback for nodes */ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) @@ -2301,7 +2110,7 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) /* note, facenr declared volatile due to over-eager -O2 optimizations * on cygwin (particularly -frerun-cse-after-loop) */ -void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float *col, float *rco) +void *shadepixel(RenderPart *pa, float x, float y, int z, volatile int facenr, int mask, float *col, float *rco) { ShadeResult shr; ShadeInput shi; @@ -2310,10 +2119,11 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * if(facenr< 0) { /* error */ return NULL; } - /* currently in use for dithering (soft shadow) and detecting thread */ + /* currently in use for dithering (soft shadow) node preview */ shi.xs= (int)(x+0.5f); shi.ys= (int)(y+0.5f); - shi.do_preview= 0; + shi.thread= pa->thread; + shi.do_preview= R.r.scemode & R_NODE_PREVIEW; /* mask is used to indicate amount of samples (ray shad/mir and AO) */ shi.mask= mask; @@ -2327,7 +2137,7 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * VertRen *v1; float alpha, fac, zcor; - vlr= RE_findOrAddVlak( (facenr-1) & 0x7FFFFF); + vlr= RE_findOrAddVlak(&R, (facenr-1) & 0x7FFFFF); shi.vlr= vlr; shi.mat= vlr->mat; @@ -2341,7 +2151,7 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * v1= vlr->v1; /* COXYZ AND VIEW VECTOR */ - calc_view_vector(shi.view, x, y); + calc_view_vector(shi.view, x, y); /* returns not normalized, so is in viewplane coords */ /* wire cannot use normal for calculating shi.co */ if(shi.mat->mode & MA_WIRE) { @@ -2364,11 +2174,11 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */ if(R.r.mode & R_ORTHO) { /* x and y 3d coordinate can be derived from pixel coord and winmat */ - float fx= 2.0/(R.rectx*R.winmat[0][0]); - float fy= 2.0/(R.recty*R.winmat[1][1]); + float fx= 2.0/(R.winx*R.winmat[0][0]); + float fy= 2.0/(R.winy*R.winmat[1][1]); - shi.co[0]= (0.5 + x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0]; - shi.co[1]= (0.5 + y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1]; + shi.co[0]= (0.5 + x - 0.5*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + shi.co[1]= (0.5 + y - 0.5*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; /* using a*x + b*y + c*z = d equation, (a b c) is normal */ if(shi.facenor[2]!=0.0f) @@ -2407,15 +2217,15 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * /* pixel dx/dy for render coord */ if(shi.osatex || (R.r.mode & R_SHADOW) ) { - float u= dface/(div-shi.facenor[0]); - float v= dface/(div- R.ycor*shi.facenor[1]); + float u= dface/(div - R.viewdx*shi.facenor[0]); + float v= dface/(div - R.viewdy*shi.facenor[1]); - shi.dxco[0]= shi.co[0]- (shi.view[0]-1.0)*u; + shi.dxco[0]= shi.co[0]- (shi.view[0]-R.viewdx)*u; shi.dxco[1]= shi.co[1]- (shi.view[1])*u; shi.dxco[2]= shi.co[2]- (shi.view[2])*u; shi.dyco[0]= shi.co[0]- (shi.view[0])*v; - shi.dyco[1]= shi.co[1]- (shi.view[1]-1.0*R.ycor)*v; + shi.dyco[1]= shi.co[1]- (shi.view[1]-R.viewdy)*v; shi.dyco[2]= shi.co[2]- (shi.view[2])*v; } @@ -2424,14 +2234,14 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * /* rco might be used for sky texture */ VECCOPY(rco, shi.co); - /* cannot normalise earlier, code above needs it at pixel level */ + /* cannot normalise earlier, code above needs it at viewplane level */ fac= Normalise(shi.view); zcor*= fac; // for mist, distance of point from camera if(shi.osatex) { if( (shi.mat->texco & TEXCO_REFL) ) { - shi.dxview= -1.0/fac; - shi.dyview= -R.ycor/fac; + shi.dxview= -R.viewdx/fac; + shi.dyview= -R.viewdy/fac; } } @@ -2443,12 +2253,12 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * /* this only avalailable for scanline */ if(shi.mat->texco & TEXCO_WINDOW) { - shi.winco[0]= (x+(R.xstart))/(float)R.afmx; - shi.winco[1]= (y+(R.ystart))/(float)R.afmy; + shi.winco[0]= -1.0f + 2.0f*x/(float)R.winx; + shi.winco[1]= -1.0f + 2.0f*y/(float)R.winy; shi.winco[2]= 0.0; if(shi.osatex) { - shi.dxwin[0]= 0.5/(float)R.r.xsch; - shi.dywin[1]= 0.5/(float)R.r.ysch; + shi.dxwin[0]= 2.0/(float)R.winx; + shi.dywin[1]= 2.0/(float)R.winy; shi.dxwin[1]= shi.dxwin[2]= 0.0; shi.dywin[0]= shi.dywin[2]= 0.0; } @@ -2464,15 +2274,18 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * v2= vlr->v2; v3= vlr->v3; } - s1= RE_vertren_get_sticky(v1, 0); - s2= RE_vertren_get_sticky(v2, 0); - s3= RE_vertren_get_sticky(v3, 0); + s1= RE_vertren_get_sticky(&R, v1, 0); + s2= RE_vertren_get_sticky(&R, v2, 0); + s3= RE_vertren_get_sticky(&R, v3, 0); if(s1 && s2 && s3) { - extern float Zmulx, Zmuly; + float Zmulx, Zmuly; float hox, hoy, l, dl, u, v; float s00, s01, s10, s11, detsh; + /* XXXX */ + Zmulx= R.winx; Zmuly= R.winy; + 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]; @@ -2598,12 +2411,12 @@ void *shadepixel(float x, float y, int z, volatile int facenr, int mask, float * return vlr; } -static void shadepixel_sky(float x, float y, int z, int facenr, int mask, float *colf) +static void shadepixel_sky(RenderPart *pa, float x, float y, int z, int facenr, int mask, float *colf) { VlakRen *vlr; float collector[4], rco[3]; - vlr= shadepixel(x, y, z, facenr, mask, colf, rco); + vlr= shadepixel(pa, x, y, z, facenr, mask, colf, rco); if(colf[3] != 1.0) { /* bail out when raytrace transparency (sky included already) */ if(vlr && (R.r.mode & R_RAYTRACE)) @@ -2615,120 +2428,30 @@ static void shadepixel_sky(float x, float y, int z, int facenr, int mask, float } } -/* ************* pixel struct ******** */ - -static PixStrMain psmfirst; -static int psmteller; - -static PixStr *addpsmain(void) -{ - PixStrMain *psm; - - psm= &psmfirst; - - while(psm->next) { - psm= psm->next; - } - - psm->next= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain),"pixstrMain"); - - psm= psm->next; - psm->next=0; - psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr),"pixstr"); - psmteller= 0; - - return psm->ps; -} - -static void freeps(void) -{ - PixStrMain *psm,*next; - - psm= &psmfirst; - - while(psm) { - next= psm->next; - if(psm->ps) { - MEM_freeN(psm->ps); - psm->ps= 0; - } - if(psm!= &psmfirst) MEM_freeN(psm); - psm= next; - } - - psmfirst.next= 0; - psmfirst.ps= 0; -} - -static void addps(long *rd, int facenr, int z, unsigned short mask) -{ - static PixStr *cur; - PixStr *ps, *last = NULL; - - if(*rd) { - ps= (PixStr *)(*rd); - - while(ps) { - if( ps->facenr == facenr ) { - ps->mask |= mask; - return; - } - last= ps; - ps= ps->next; - } - } - - /* make new PS (pixel struct) */ - if((psmteller & 4095)==0) cur= addpsmain(); - else cur++; - psmteller++; - - if(last) last->next= cur; - else *rd= (long)cur; - - cur->next= NULL; - cur->facenr= facenr; - cur->z= z; - cur->mask = mask; -} - - -int count_mask(unsigned short mask) -{ - extern char cmask[256]; - return (cmask[mask & 255]+cmask[mask>>8]); -} - -static void edge_enhance(void) +/* adds only alpha values */ +static void edge_enhance_calc(RenderPart *pa, float *rectf) { /* use zbuffer to define edges, add it to the image */ - int val, y, x, col, *rz, *rz1, *rz2, *rz3; + int y, x, col, *rz, *rz1, *rz2, *rz3; int zval1, zval2, zval3; - char *cp; + float *rf; /* shift values in zbuffer 4 to the right, for filter we need multiplying with 12 max */ - rz= (int *)R.rectz; + rz= pa->rectz; if(rz==NULL) return; - for(y=0; y<R.recty; y++) { - for(x=0; x<R.rectx; x++, rz++) (*rz)>>= 4; + for(y=0; y<pa->recty; y++) { + for(x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4; } - rz1= (int *)R.rectz; - rz2= rz1+R.rectx; - rz3= rz2+R.rectx; - - if(R.r.mode & R_OSA) { - cp= (char *)(R.rectaccu+R.rectx); - } - else { - cp= (char *)(R.rectot+R.rectx); - } - cp+= 4; + rz1= pa->rectz; + rz2= rz1+pa->rectx; + rz3= rz2+pa->rectx; - for(y=0; y<R.recty-2; y++) { - - for(x=0; x<R.rectx-2; x++, rz++, rz1++, rz2++, rz3++, cp+=4) { + rf= rectf+pa->rectx+1; + + for(y=0; y<pa->recty-2; y++) { + for(x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) { /* prevent overflow with sky z values */ zval1= rz1[0] + 2*rz1[1] + rz1[2]; @@ -2742,482 +2465,348 @@ static void edge_enhance(void) else col= (R.r.edgeint*col)>>8; if(col>0) { - if(col>255) col= 255; + float fcol; - if(R.r.mode & R_OSA) { - col/= R.osa; - - val= cp[3]+col; - if(val>255) cp[3]= 255; else cp[3]= val; - } - else { - val= cp[0]- col; - if(val<0) cp[0]= 0; else cp[0]= val; - val= cp[1]- col; - if(val<0) cp[1]= 0; else cp[1]= val; - val= cp[2]- col; - if(val<0) cp[2]= 0; else cp[2]= val; - } + if(col>255) fcol= 1.0f; + else fcol= (float)col/255.0f; + + if(R.osa) + *rf+= fcol/(float)R.osa; + else + *rf= fcol; } } - rz++; rz1+= 2; rz2+= 2; rz3+= 2; - cp+= 8; + rf+= 2; } +} +static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect) +{ + float addcol[4]; + int pix; + + for(pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) { + if(*arect != 0.0f) { + addcol[0]= *arect * R.r.edgeR; + addcol[1]= *arect * R.r.edgeG; + addcol[2]= *arect * R.r.edgeB; + addcol[3]= *arect; + addAlphaOverFloat(rectf, addcol); + } + } } + /* ********************* MAINLOOPS ******************** */ -struct renderlineDA { - long *rd; - int *rz; - float *rb1, *rb2, *rb3; - float *acol; - int y; -}; - -static int do_renderlineDA(void *poin) + +static void shadeDA_tile(RenderPart *pa, float *rectf, float *recta) { - struct renderlineDA *rl= poin; PixStr *ps; float xs, ys; - float fcol[4], *acol=NULL, *rb1, *rb2, *rb3; - long *rd= rl->rd; + float fcol[4], *rf, *grf, *acol= NULL; + long *rd, *rectdaps= pa->rectdaps; int zbuf, samp, curmask, face, mask, fullmask; - int b, x, full_osa, seed; + int b, x, y, full_osa, seed, crop=0; - /* we set per pixel a fixed seed, for random AO and shadow samples */ - seed= (R.ystart + rl->y + R.afmy)*R.r.xsch + R.xstart + R.afmx; + if(R.test_break()) return; + /* we set per pixel a fixed seed, for random AO and shadow samples */ + seed= pa->rectx*pa->disprect.ymin; + fullmask= (1<<R.osa)-1; - rb1= rl->rb1; - rb2= rl->rb2; - rb3= rl->rb3; - if(R.flag & R_ZTRA) { /* zbuf tra */ - abufsetrow(rl->acol, rl->y); - acol= rl->acol; + /* might need it for gamma, in end of this function */ + grf= rectf; + + /* filtered render, for now we assume only 1 filter size */ + if(pa->crop) { + crop= 1; + rectf+= 4*(pa->rectx + 1); + rectdaps+= pa->rectx + 1; + if(recta) recta+= 4*(pa->rectx + 1); } + + for(y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++) { + rf= rectf; + rd= rectdaps; + if(recta) acol= recta; - for(x=0; x<R.rectx; x++, rd++) { - - BLI_thread_srandom(rl->y & 1, seed+x); - - ps= (PixStr *)(*rd); - mask= 0; - - /* complex loop, because empty spots are sky, without mask */ - while(TRUE) { - - if(ps==NULL) { - face= 0; - curmask= (~mask) & fullmask; - zbuf= *(rl->rz+x); - } - else { - face= ps->facenr; - curmask= ps->mask; - zbuf= ps->z; - } - - /* check osa level */ - if(face==0) full_osa= 0; - else { - VlakRen *vlr= RE_findOrAddVlak( (face-1) & 0x7FFFFF); - full_osa= (vlr->flag & R_FULL_OSA); - } + for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, rf+=4) { + BLI_thread_srandom(pa->thread, seed+x); - if(full_osa) { - for(samp=0; samp<R.osa; samp++) { - if(curmask & (1<<samp)) { - xs= (float)x + jit[samp][0]; - ys= (float)rl->y + jit[samp][1]; - shadepixel_sky(xs, ys, zbuf, face, (1<<samp), fcol); - - if(acol && acol[3]!=0.0) addAlphaOverFloat(fcol, acol); - if(do_gamma) { - fcol[0]= gammaCorrect(fcol[0]); - fcol[1]= gammaCorrect(fcol[1]); - fcol[2]= gammaCorrect(fcol[2]); + ps= (PixStr *)(*rd); + mask= 0; + + /* complex loop, because empty spots are sky, without mask */ + while(TRUE) { + + if(ps==NULL) { + face= 0; + curmask= (~mask) & fullmask; + zbuf= 0x7FFFFFFF; + } + else { + face= ps->facenr; + curmask= ps->mask; + zbuf= ps->z; + } + + /* check osa level */ + if(face==0) full_osa= 0; + else { + VlakRen *vlr= RE_findOrAddVlak(&R, (face-1) & 0x7FFFFF); + full_osa= (vlr->flag & R_FULL_OSA); + } + + if(full_osa) { + for(samp=0; samp<R.osa; samp++) { + if(curmask & (1<<samp)) { + xs= (float)x + R.jit[samp][0]; + ys= (float)y + R.jit[samp][1]; + shadepixel_sky(pa, xs, ys, zbuf, face, (1<<samp), fcol); + + if(acol && acol[3]!=0.0) addAlphaOverFloat(fcol, acol); + if(R.do_gamma) { + fcol[0]= gammaCorrect(fcol[0]); + fcol[1]= gammaCorrect(fcol[1]); + fcol[2]= gammaCorrect(fcol[2]); + } + add_filt_fmask(1<<samp, fcol, rf, pa->rectx); } - add_filt_fmask(1<<samp, fcol, rb1, rb2, rb3); } } - } - else { - extern char *centmask; // initrender.c - extern float centLut[16]; - - b= centmask[curmask]; - xs= (float)x+centLut[b & 15]; - ys= (float)rl->y+centLut[b>>4]; - shadepixel_sky(xs, ys, zbuf, face, curmask, fcol); + else { + b= R.samples->centmask[curmask]; + xs= (float)x+R.samples->centLut[b & 15]; + ys= (float)y+R.samples->centLut[b>>4]; + shadepixel_sky(pa, xs, ys, zbuf, face, curmask, fcol); + + if(acol && acol[3]!=0.0) addAlphaOverFloat(fcol, acol); + + if(R.do_gamma) { + fcol[0]= gammaCorrect(fcol[0]); + fcol[1]= gammaCorrect(fcol[1]); + fcol[2]= gammaCorrect(fcol[2]); + } + add_filt_fmask(curmask, fcol, rf, pa->rectx); + } - if(acol && acol[3]!=0.0) addAlphaOverFloat(fcol, acol); + mask |= curmask; - if(do_gamma) { - fcol[0]= gammaCorrect(fcol[0]); - fcol[1]= gammaCorrect(fcol[1]); - fcol[2]= gammaCorrect(fcol[2]); - } - add_filt_fmask(curmask, fcol, rb1, rb2, rb3); + if(ps==NULL) break; + else ps= ps->next; } - - mask |= curmask; - - if(ps==NULL) break; - else ps= ps->next; + if(acol) acol+=4; } - rb1+=4; - rb2+=4; - rb3+=4; - if(acol) acol+=4; + rectf+= 4*pa->rectx; + rectdaps+= pa->rectx; + if(recta) recta+= 4*pa->rectx; + seed+= pa->rectx; + + if(y&1) if(R.test_break()) break; } - - return 1; + + if(R.do_gamma) { + for(y= pa->rectx*pa->recty; y>0; y--, grf+=4) { + grf[0] = invGammaCorrect(grf[0]); + grf[1] = invGammaCorrect(grf[1]); + grf[2] = invGammaCorrect(grf[2]); + } + } + } -void zbufshadeDA(void) /* Delta Accum Pixel Struct */ -{ - extern float Zjitx,Zjity; - struct renderlineDA rl1, rl2; - float xd, yd, *rf; - long *rd; - int *rz, *rp, *rt; - float *rowbuf1, *rowbuf2, *rowbuf3, *rowbuf0, *rowbuf1a, *rowbuf2a, *rb3; - int a; - short v, x, y; +/* ************* pixel struct ******** */ - R.rectdaps= MEM_callocN(sizeof(long)*R.rectx*R.recty+4,"zbufDArectd"); + +static PixStrMain *addpsmain(ListBase *lb) +{ + PixStrMain *psm; - if(R.flag & R_ZTRA) { - bgnaccumbuf(); - rl1.acol= MEM_callocN((R.rectx+4)*4*sizeof(float), "Acol"); - rl2.acol= MEM_callocN((R.rectx+4)*4*sizeof(float), "Acol"); - } + psm= (PixStrMain *)RE_mallocN(sizeof(PixStrMain),"pixstrMain"); + BLI_addtail(lb, psm); + + psm->ps= (PixStr *)RE_mallocN(4096*sizeof(PixStr),"pixstr"); + psm->counter= 0; - psmteller= 0; + return psm; +} - if(R.r.mode & R_EDGE) { - R.rectaccu= (int *)MEM_callocN(sizeof(int)*R.rectx*R.recty,"zbufshadeDA"); +static void freeps(ListBase *lb) +{ + PixStrMain *psm, *psmnext; + + for(psm= lb->first; psm; psm= psmnext) { + psmnext= psm->next; + if(psm->ps) + RE_freeN(psm->ps); + RE_freeN(psm); } +} - for(v=0; v<R.osa; v++) { - - xd= jit[v][0]; - yd= jit[v][1]; - Zjitx= -xd -0.5; - Zjity= -yd -0.5; - - if((R.r.mode & R_MBLUR)==0) RE_local_printrenderinfo(0.0, v); - - /* RECTDELTA */ - fillrect(R.rectot,R.rectx,R.recty,0); - - zbufferall(); - - rd= R.rectdaps; - rp= R.rectot; - rz= R.rectz; - for(y=0; y<R.recty; y++) { - for(x=0; x<R.rectx; x++, rp++, rd++) { - if(*rp) { - addps(rd, *rp, *(rz+x), 1<<v); - } - } - rz+= R.rectx; - } - - if(R.r.mode & R_EDGE) edge_enhance(); - - if(RE_local_test_break()) break; - } +static void addps(ListBase *lb, long *rd, int facenr, int z, unsigned short mask) +{ + PixStrMain *psm; + PixStr *ps, *last= NULL; - rd= R.rectdaps; - rz= R.rectz; - rt= R.rectot; - rf= R.rectftot; - - /* the rowbuf is 4 pixels larger than an image! */ - rowbuf0= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - rowbuf1= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - rowbuf2= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - rowbuf1a= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - rowbuf2a= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - rowbuf3= MEM_callocN((R.rectx+4)*4*sizeof(float), "ZbufshadeDA3"); - - for(y=0; y<=R.recty; y++, rd+=R.rectx, rt+=R.rectx, rz+= R.rectx) { - - if(y<R.recty) { - rl1.rd= rd; - rl1.rz= rz; - rl1.y= y; - rl1.rb1= rowbuf1; - rl1.rb2= rowbuf2; - rl1.rb3= rowbuf3; - - if( (R.r.mode & R_THREADS) && y!=R.recty-1) { // odd amount of total y pixels... - if((y & 1)==0) { - SDL_Thread *thread; - - thread = SDL_CreateThread(do_renderlineDA, &rl1); - if ( thread == NULL ) { - fprintf(stderr, "Unable to create thread"); - G.afbreek= 1; - break; - } - - rl2.rd= rd+R.rectx; - rl2.rz= rz+R.rectx; - rl2.y= y+1; - rl2.rb1= rowbuf0; - rl2.rb2= rowbuf1a; - rl2.rb3= rowbuf2a; - - do_renderlineDA(&rl2); - SDL_WaitThread(thread, NULL); - - if(R.r.filtertype) { - float *rb1= rowbuf1, *rb2= rowbuf2, *rb1a= rowbuf1a, *rb2a= rowbuf2a; - a= 4*(R.rectx + 4); - while(a--) { - *rb1 += *rb1a; - *rb2 += *rb2a; - *(rb1a++)= 0; rb1++; - *(rb2a++)= 0; rb2++; - } - } - else { - SWAP(float *, rowbuf1a, rowbuf1); - } - } - } - else do_renderlineDA(&rl1); - - } - if(y>0) { - /* halos are alpha-added, not in thread loop (yet) because of gauss mask */ - if(R.flag & R_HALO) { - /* one scanline older... */ - scanlinehaloPS(rz-R.rectx, rd-R.rectx, rowbuf3+4, y-1); - } - - /* convert 4x32 bits buffer to 4x8, this can't be threaded due to gauss */ - transferColourBufferToOutput(rowbuf3+4, y-1); - if(R.rectftot) { - memcpy(rf, rowbuf3+4, 4*sizeof(float)*R.rectx); - rf+= 4*R.rectx; - } - - } - if(y<R.recty) { - memset(rowbuf3, 0, (R.rectx+4)*4*sizeof(int)); - rb3= rowbuf3; - rowbuf3= rowbuf2; - rowbuf2= rowbuf1; - rowbuf1= rowbuf0; - rowbuf0= rb3; - - if( y>0) { - if((y & 1)==0) { - RE_local_render_display(y-2, y-1, R.rectx, R.recty, R.rectot); - } + if(*rd) { + ps= (PixStr *)(*rd); + + while(ps) { + if( ps->facenr == facenr ) { + ps->mask |= mask; + return; } + last= ps; + ps= ps->next; } - if(RE_local_test_break()) break; } + + /* make new PS (pixel struct) */ + psm= lb->last; + + if(psm->counter==4095) + psm= addpsmain(lb); + + ps= psm->ps + psm->counter++; + + if(last) last->next= ps; + else *rd= (long)ps; + + ps->next= NULL; + ps->facenr= facenr; + ps->z= z; + ps->mask = mask; +} - if( (R.r.mode & R_EDGE) && RE_local_test_break()==0) { - if(R.rectftot) { - float *rtf= R.rectftot, colf[4]; - rp= R.rectaccu; - for(a= R.rectx*R.recty; a>0; a--, rtf+=4, rp++) { - cpCharColV2FloatColV((char *)rp, colf); - addAlphaOverFloat(rtf, colf); - } - RE_floatbuffer_to_output(); - } - else { - rt= R.rectot; - rp= R.rectaccu; - for(a= R.rectx*R.recty; a>0; a--, rt++, rp++) { - addalphaOver((char *)rt, (char *)rp); +static void make_pixelstructs(RenderPart *pa, ListBase *lb) +{ + long *rd= pa->rectdaps; + int *rp= pa->rectp; + int *rz= pa->rectz; + int x, y; + int mask= 1<<pa->sample; + + for(y=0; y<pa->recty; y++) { + for(x=0; x<pa->rectx; x++, rd++, rp++) { + if(*rp) { + addps(lb, rd, *rp, *(rz+x), mask); } } + rz+= pa->rectx; } - - MEM_freeN(R.rectdaps); - freeps(); - MEM_freeN(rowbuf0); - MEM_freeN(rowbuf1); - MEM_freeN(rowbuf2); - MEM_freeN(rowbuf1a); - MEM_freeN(rowbuf2a); - MEM_freeN(rowbuf3); - R.rectdaps= NULL; - - if(R.r.mode & R_EDGE) if(R.rectaccu) MEM_freeN(R.rectaccu); - R.rectaccu= NULL; - if(R.flag & R_ZTRA) { - endaccumbuf(); - MEM_freeN(rl1.acol); - MEM_freeN(rl2.acol); - } - -} /* end of void zbufshadeDA() */ - -/* ------------------------------------------------------------------------ */ - -struct renderline { - float *rowbuf, *acol; - int *rp; - int *rz; - short ys; - float y; -}; +} -static int do_renderline(void *poin) +/* supposed to be fully threadable! */ +void zbufshadeDA_tile(RenderPart *pa) { - struct renderline *rl= poin; - float *fcol= rl->rowbuf; - float *acol=NULL; - int x, *rz, *rp, seed; + RenderLayer *rl= pa->result->layers.first; + ListBase psmlist= {NULL, NULL}; + float *acolrect= NULL, *edgerect= NULL; - /* we set per pixel a fixed seed, for random AO and shadow samples */ - seed= (R.ystart + rl->y + R.afmy)*R.r.xsch + R.xstart + R.afmx; + set_part_zbuf_clipflag(pa); - if(R.flag & R_ZTRA) { /* zbuf tra */ - abufsetrow(rl->acol, rl->ys); - acol= rl->acol; - } + /* allocate the necessary buffers */ + pa->rectdaps= RE_callocN(sizeof(long)*pa->rectx*pa->recty+4, "zbufDArectd"); + /* zbuffer inits these rects */ + pa->rectp= RE_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); + pa->rectz= RE_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); + if(R.r.mode & R_EDGE) edgerect= RE_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); + + /* initialize pixelstructs */ + addpsmain(&psmlist); - for(x=0, rz= rl->rz, rp= rl->rp; x<R.rectx; x++, rz++, rp++, fcol+=4) { - BLI_thread_srandom(rl->ys & 1, seed+x); + for(pa->sample=0; pa->sample<R.osa; pa->sample++) { + zbuffer_solid(pa); + make_pixelstructs(pa, &psmlist); - shadepixel_sky((float)x, rl->y, *rz, *rp, 0, fcol); - if(acol) { - if(acol[3]!=0.0) addAlphaOverFloat(fcol, acol); - acol+= 4; - } + if(R.r.mode & R_EDGE) edge_enhance_calc(pa, edgerect); + if(R.test_break()) break; } - - if(R.flag & R_HALO) { - scanlinehalo(rl->rz, rl->rowbuf, rl->ys); + + /* we do transp layer first, so its get added with filter in main buffer... still incorrect though */ + if(R.flag & R_ZTRA) { + acolrect= RE_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); + zbuffer_transp_shade(pa, acolrect); } - transferColourBufferToOutput(rl->rowbuf, rl->ys); - - if(R.rectftot) { - memcpy(R.rectftot + 4*rl->ys*R.rectx, rl->rowbuf, 4*sizeof(float)*R.rectx); - } + /* shades solid and adds transparent layer */ + shadeDA_tile(pa, rl->rectf, acolrect); + + /* extra layers */ + if(R.r.mode & R_EDGE) + edge_enhance_add(pa, rl->rectf, edgerect); + if(R.flag & R_HALO) + halo_tile(pa, rl->rectf); + + /* free all */ + RE_freeN(pa->rectp); pa->rectp= NULL; + RE_freeN(pa->rectz); pa->rectz= NULL; + RE_freeN(pa->rectdaps); pa->rectdaps= NULL; + if(acolrect) RE_freeN(acolrect); + if(edgerect) RE_freeN(edgerect); + + freeps(&psmlist); - return 1; } -void zbufshade(void) -{ - struct renderline rl1, rl2; - extern float Zjitx,Zjity; - int *rz, *rp; - float fy; - int y; +/* ------------------------------------------------------------------------ */ - rl1.rowbuf= MEM_callocN((R.rectx+4)*4*sizeof(float), "Zbufshade"); - rl2.rowbuf= MEM_callocN((R.rectx+4)*4*sizeof(float), "Zbufshade"); +/* supposed to be fully threadable! */ +void zbufshade_tile(RenderPart *pa) +{ + RenderLayer *rl= pa->result->layers.first; + float *fcol; + int x, y, *rp, *rz; - Zjitx=Zjity= -0.5; - - zbufferall(); - - /* SHADE */ - rp= R.rectot; - rz= R.rectz; - - if(R.flag & R_ZTRA) { - rl1.acol= MEM_callocN((R.rectx+4)*4*sizeof(float), "Acol"); - rl2.acol= MEM_callocN((R.rectx+4)*4*sizeof(float), "Acol"); - bgnaccumbuf(); - } - - for(y=0; y<R.recty; y++) { - fy= y; - - rl1.rp= rp; - rl1.rz= rz; - rl1.y= fy; - rl1.ys= y; - - if(R.r.mode & R_THREADS) { - SDL_Thread *thread; - - thread = SDL_CreateThread(do_renderline, &rl1); - if ( thread == NULL ) { - fprintf(stderr, "Unable to create thread"); - G.afbreek= 1; - break; + set_part_zbuf_clipflag(pa); + + /* zbuffer code clears/inits rects */ + rp= pa->rectp= RE_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); + rz= pa->rectz= RE_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); + + zbuffer_solid(pa); + + if(!R.test_break()) { + fcol= rl->rectf; + for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { + for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, rp++, fcol+=4) { + shadepixel_sky(pa, (float)x, (float)y, *rz, *rp, 0, fcol); } - rp+= R.rectx; - rz+= R.rectx; - - if(y < R.recty-1) { - rl2.rp= rp; - rl2.rz= rz; - rl2.y= fy+1.0; - rl2.ys= y+1; - do_renderline(&rl2); - rp+= R.rectx; - rz+= R.rectx; - y++; - } - SDL_WaitThread(thread, NULL); - } - else { - do_renderline(&rl1); - rp+= R.rectx; - rz+= R.rectx; + if(y&1) if(R.test_break()) break; } - - if(y & 1) { - RE_local_render_display(y-1, y, R.rectx, R.recty, R.rectot); - } - - if(RE_local_test_break()) break; } - MEM_freeN(rl1.rowbuf); - MEM_freeN(rl2.rowbuf); + if(!R.test_break()) + if(R.flag & R_ZTRA) + zbuffer_transp_shade(pa, rl->rectf); - if(R.flag & R_ZTRA) { - endaccumbuf(); - MEM_freeN(rl1.acol); - MEM_freeN(rl2.acol); + if(!R.test_break()) { + if(R.r.mode & R_EDGE) { + fillrect(pa->rectp, pa->rectx, pa->recty, 0); + edge_enhance_calc(pa, (float *)pa->rectp); + edge_enhance_add(pa, rl->rectf, (float *)pa->rectp); + } } - if(R.r.mode & R_EDGE) edge_enhance(); + if(!R.test_break()) + if(R.flag & R_HALO) + halo_tile(pa, rl->rectf); -} /* end of void zbufshade() */ + RE_freeN(pa->rectp); pa->rectp= NULL; + RE_freeN(pa->rectz); pa->rectz= NULL; +} /* ------------------------------------------------------------------------ */ -void RE_shadehalo(HaloRen *har, char *col, float *colf, int zz, float dist, float xn, float yn, short flarec) -{ - - shadeHaloFloat(har, colf, zz, dist, xn, yn, flarec); - - if(colf[0]<=0.0) col[0]= 0; else if(colf[0]>=1.0) col[0]= 255; else col[0]= 255.0*colf[0]; - if(colf[1]<=0.0) col[1]= 0; else if(colf[1]>=1.0) col[1]= 255; else col[1]= 255.0*colf[1]; - if(colf[2]<=0.0) col[2]= 0; else if(colf[2]>=1.0) col[2]= 255; else col[2]= 255.0*colf[2]; - if(colf[3]<=0.0) col[3]= 0; else if(colf[3]>=1.0) col[3]= 255; else col[3]= 255.0*colf[3]; - -} - static void renderhalo(HaloRen *har) /* postprocess version */ { - +#if 0 float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf; int *rectt, *rt; int minx, maxx, miny, maxy, x, y; @@ -3262,7 +2851,7 @@ static void renderhalo(HaloRen *har) /* postprocess version */ if(R.rectftot) addalphaAddfacFloat(rtf, colf, har->add); else { std_floatcol_to_charcol(colf, col); - RE_addalphaAddfac((char *)rt, col, har->add); + addalphaAddfac((char *)rt, col, har->add); } } rt++; @@ -3272,14 +2861,15 @@ static void renderhalo(HaloRen *har) /* postprocess version */ rectt+= R.rectx; rectft+= 4*R.rectx; - if(RE_local_test_break()) break; + if(R.test_break()) break; } } } +#endif } /* ------------------------------------------------------------------------ */ -void RE_renderflare(HaloRen *har) +static void renderflare(HaloRen *har) { extern float hashvectf[]; HaloRen fla; @@ -3333,12 +2923,12 @@ void RE_renderflare(HaloRen *har) fla.radsq= fla.rad*fla.rad; - vec[0]= 1.4*rc[5]*(har->xs-R.afmx); - vec[1]= 1.4*rc[5]*(har->ys-R.afmy); + vec[0]= 1.4*rc[5]*(har->xs-R.winx/2); + vec[1]= 1.4*rc[5]*(har->ys-R.winy/2); vec[2]= 32.0*sqrt(vec[0]*vec[0] + vec[1]*vec[1] + 1.0); - fla.xs= R.afmx + vec[0] + (1.2+rc[8])*R.rectx*vec[0]/vec[2]; - fla.ys= R.afmy + vec[1] + (1.2+rc[8])*R.rectx*vec[1]/vec[2]; + fla.xs= R.winx/2 + vec[0] + (1.2+rc[8])*R.rectx*vec[0]/vec[2]; + fla.ys= R.winy/2 + vec[1] + (1.2+rc[8])*R.rectx*vec[1]/vec[2]; if(R.flag & R_SEC_FIELD) { if(R.r.mode & R_ODDFIELD) fla.ys += 0.5; @@ -3355,36 +2945,35 @@ void RE_renderflare(HaloRen *har) rc+= 7; } -} /* end of void renderflare(HaloRen *har) */ +} +/* needs recode... integrate this! */ void add_halo_flare(void) { -/* extern void RE_projectverto(); */ /* zbuf.c */ HaloRen *har = NULL; int a, mode; mode= R.r.mode; R.r.mode &= ~R_PANORAMA; - R.xstart= -R.afmx; - R.ystart= -R.afmy; - R.xend= R.xstart+R.rectx-1; - R.yend= R.ystart+R.recty-1; +// R.xstart= -R.afmx; +// R.ystart= -R.afmy; +// R.xend= R.xstart+R.rectx-1; +// R.yend= R.ystart+R.recty-1; - RE_setwindowclip(1,-1); /* no jit:(-1) */ - setzbufvlaggen(RE_projectverto); +// RE_setwindowclip(1,-1); /* no jit:(-1) */ + project_renderdata(&R, projectverto, 0, 0); for(a=0; a<R.tothalo; a++) { if((a & 255)==0) har= R.bloha[a>>8]; else har++; if(har->flarec) { - RE_renderflare(har); + renderflare(har); } } R.r.mode= mode; - if(R.rectftot) RE_floatbuffer_to_output(); } diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d37c73dc932..098d4491060 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,15 +20,14 @@ * 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. + * Contributor(s): 2004-2006, Blender Foundation, full recode * * ***** END GPL/BL DUAL LICENSE BLOCK ***** - * Storage, retrieval and query of render specific data. */ /* + * Storage, retrieval and query of render specific data. + * * All data from a Blender scene is converter by the renderconverter/ * into a special format that is used by the render module to make * images out of. These functions interface to the render-specific @@ -57,6 +53,7 @@ * */ +#include <limits.h> #include <math.h> #include <string.h> @@ -66,14 +63,20 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_texture_types.h" #include "BKE_texture.h" -#include "render.h" +#include "RE_render_ext.h" /* externtex */ -/* ------------------------------------------------------------------------- */ +#include "renderpipeline.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "texture.h" +#include "zbuf.h" +/* ------------------------------------------------------------------------- */ /* More dynamic allocation of options for render vertices, so we dont have to reserve this space inside vertices. @@ -99,30 +102,30 @@ typedef struct VertTableNode { float *stress; } VertTableNode; -float *RE_vertren_get_sticky(VertRen *ver, int verify) +float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify) { float *sticky; int nr= ver->index>>8; - sticky= R.vertnodes[nr].sticky; + sticky= re->vertnodes[nr].sticky; if(sticky==NULL) { if(verify) - sticky= R.vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table"); + sticky= re->vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table"); else return NULL; } return sticky + (ver->index & 255)*RE_STICKY_ELEMS; } -float *RE_vertren_get_stress(VertRen *ver, int verify) +float *RE_vertren_get_stress(Render *re, VertRen *ver, int verify) { float *stress; int nr= ver->index>>8; - stress= R.vertnodes[nr].stress; + stress= re->vertnodes[nr].stress; if(stress==NULL) { if(verify) - stress= R.vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table"); + stress= re->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table"); else return NULL; } @@ -130,30 +133,30 @@ float *RE_vertren_get_stress(VertRen *ver, int verify) } /* this one callocs! */ -float *RE_vertren_get_rad(VertRen *ver, int verify) +float *RE_vertren_get_rad(Render *re, VertRen *ver, int verify) { float *rad; int nr= ver->index>>8; - rad= R.vertnodes[nr].rad; + rad= re->vertnodes[nr].rad; if(rad==NULL) { if(verify) - rad= R.vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table"); + rad= re->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table"); else return NULL; } return rad + (ver->index & 255)*RE_RAD_ELEMS; } -float *RE_vertren_get_strand(VertRen *ver, int verify) +float *RE_vertren_get_strand(Render *re, VertRen *ver, int verify) { float *strand; int nr= ver->index>>8; - strand= R.vertnodes[nr].strand; + strand= re->vertnodes[nr].strand; if(strand==NULL) { if(verify) - strand= R.vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table"); + strand= re->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table"); else return NULL; } @@ -161,15 +164,15 @@ float *RE_vertren_get_strand(VertRen *ver, int verify) } /* needs calloc */ -float *RE_vertren_get_tangent(VertRen *ver, int verify) +float *RE_vertren_get_tangent(Render *re, VertRen *ver, int verify) { float *tangent; int nr= ver->index>>8; - tangent= R.vertnodes[nr].tangent; + tangent= re->vertnodes[nr].tangent; if(tangent==NULL) { if(verify) - tangent= R.vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table"); + tangent= re->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table"); else return NULL; } @@ -177,36 +180,35 @@ float *RE_vertren_get_tangent(VertRen *ver, int verify) } -VertRen *RE_findOrAddVert(int nr) +VertRen *RE_findOrAddVert(Render *re, int nr) { VertTableNode *temp; VertRen *v; - static int rvertnodeslen=TABLEINITSIZE; int a; if(nr<0) { printf("error in findOrAddVert: %d\n",nr); - return R.vertnodes[0].vert; + return NULL; } a= nr>>8; - if (a>=rvertnodeslen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */ - temp= R.vertnodes; + if (a>=re->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= re->vertnodes; - R.vertnodes= MEM_mallocN(sizeof(VertTableNode)*(rvertnodeslen+TABLEINITSIZE) , "vertnodes"); - memcpy(R.vertnodes, temp, rvertnodeslen*sizeof(VertTableNode)); - memset(R.vertnodes+rvertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode)); + re->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(re->vertnodeslen+TABLEINITSIZE) , "vertnodes"); + if(temp) memcpy(re->vertnodes, temp, re->vertnodeslen*sizeof(VertTableNode)); + memset(re->vertnodes+re->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode)); - rvertnodeslen+=TABLEINITSIZE; - MEM_freeN(temp); + re->vertnodeslen+=TABLEINITSIZE; + if(temp) MEM_freeN(temp); } - v= R.vertnodes[a].vert; + v= re->vertnodes[a].vert; if(v==NULL) { int i; v= (VertRen *)MEM_callocN(256*sizeof(VertRen),"findOrAddVert"); - R.vertnodes[a].vert= v; + re->vertnodes[a].vert= v; for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) { v[a].index= i; @@ -216,74 +218,80 @@ VertRen *RE_findOrAddVert(int nr) return v; } -void RE_free_vertex_tables(void) +void free_renderdata_tables(Render *re) { int a=0; - while(R.vertnodes[a].vert) { - if(R.vertnodes[a].vert) { - MEM_freeN(R.vertnodes[a].vert); - R.vertnodes[a].vert= NULL; - - if(R.vertnodes[a].rad) { - MEM_freeN(R.vertnodes[a].rad); - R.vertnodes[a].rad= NULL; - } - if(R.vertnodes[a].sticky) { - MEM_freeN(R.vertnodes[a].sticky); - R.vertnodes[a].sticky= NULL; - } - if(R.vertnodes[a].strand) { - MEM_freeN(R.vertnodes[a].strand); - R.vertnodes[a].strand= NULL; - } - if(R.vertnodes[a].tangent) { - MEM_freeN(R.vertnodes[a].tangent); - R.vertnodes[a].tangent= NULL; - } - if(R.vertnodes[a].stress) { - MEM_freeN(R.vertnodes[a].stress); - R.vertnodes[a].stress= NULL; - } + if(re->blovl) { + for(a=0; re->blovl[a]; a++) + MEM_freeN(re->blovl[a]); + + MEM_freeN(re->blovl); + re->blovl= NULL; + re->blovllen= 0; + } + + if(re->bloha) { + for(a=0; re->bloha[a]; a++) + MEM_freeN(re->bloha[a]); + + MEM_freeN(re->bloha); + re->bloha= NULL; + re->blohalen= 0; + } + + if(re->vertnodes) { + for(a=0; re->vertnodes[a].vert; a++) { + MEM_freeN(re->vertnodes[a].vert); + + if(re->vertnodes[a].rad) + MEM_freeN(re->vertnodes[a].rad); + if(re->vertnodes[a].sticky) + MEM_freeN(re->vertnodes[a].sticky); + if(re->vertnodes[a].strand) + MEM_freeN(re->vertnodes[a].strand); + if(re->vertnodes[a].tangent) + MEM_freeN(re->vertnodes[a].tangent); + if(re->vertnodes[a].stress) + MEM_freeN(re->vertnodes[a].stress); } - a++; + + MEM_freeN(re->vertnodes); + re->vertnodes= NULL; + re->vertnodeslen= 0; } } -/* only once, on startup */ -void RE_init_vertex_tables(void) -{ - R.vertnodes= MEM_callocN(sizeof(VertTableNode)*TABLEINITSIZE , "vertnodes"); -} /* ------------------------------------------------------------------------ */ -int rblohalen=TABLEINITSIZE; -HaloRen *RE_findOrAddHalo(int nr) + +HaloRen *RE_findOrAddHalo(Render *re, int nr) { HaloRen *h, **temp; int a; if(nr<0) { printf("error in findOrAddHalo: %d\n",nr); - return R.bloha[0]; + return NULL; } a= nr>>8; - if (a>=rblohalen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */ + if (a>=re->blohalen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */ //printf("Allocating %i more halo groups. %i total.\n", - // TABLEINITSIZE, rblohalen+TABLEINITSIZE ); - temp=R.bloha; - R.bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(rblohalen+TABLEINITSIZE) , "Bloha"); - memcpy(R.bloha, temp, rblohalen*sizeof(void*)); - memset(&(R.bloha[rblohalen]), 0, TABLEINITSIZE*sizeof(void*)); - rblohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ - MEM_freeN(temp); + // TABLEINITSIZE, re->blohalen+TABLEINITSIZE ); + temp=re->bloha; + + re->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(re->blohalen+TABLEINITSIZE) , "Bloha"); + if(temp) memcpy(re->bloha, temp, re->blohalen*sizeof(void*)); + memset(&(re->bloha[re->blohalen]), 0, TABLEINITSIZE*sizeof(void*)); + re->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if(temp) MEM_freeN(temp); } - h= R.bloha[a]; - if(h==0) { + h= re->bloha[a]; + if(h==NULL) { h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen),"findOrAdHalo"); - R.bloha[a]= h; + re->bloha[a]= h; } h+= (nr & 255); return h; @@ -291,34 +299,34 @@ HaloRen *RE_findOrAddHalo(int nr) /* ------------------------------------------------------------------------ */ -VlakRen *RE_findOrAddVlak(int nr) +VlakRen *RE_findOrAddVlak(Render *re, int nr) { VlakRen *v, **temp; - static int rblovllen=TABLEINITSIZE; int a; if(nr<0) { printf("error in findOrAddVlak: %d\n",nr); - return R.blovl[0]; + return re->blovl[0]; } a= nr>>8; - if (a>=rblovllen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */ + if (a>=re->blovllen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */ // printf("Allocating %i more face groups. %i total.\n", - // TABLEINITSIZE, rblovllen+TABLEINITSIZE ); - temp=R.blovl; - R.blovl=(VlakRen**)MEM_callocN(sizeof(void*)*(rblovllen+TABLEINITSIZE) , "Blovl"); - memcpy(R.blovl, temp, rblovllen*sizeof(void*)); - memset(&(R.blovl[rblovllen]), 0, TABLEINITSIZE*sizeof(void*)); - rblovllen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ - MEM_freeN(temp); + // TABLEINITSIZE, re->blovllen+TABLEINITSIZE ); + temp= re->blovl; + + re->blovl=(VlakRen**)MEM_callocN(sizeof(void*)*(re->blovllen+TABLEINITSIZE) , "Blovl"); + if(temp) memcpy(re->blovl, temp, re->blovllen*sizeof(void*)); + memset(&(re->blovl[re->blovllen]), 0, TABLEINITSIZE*sizeof(void*)); + re->blovllen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if(temp) MEM_freeN(temp); } - v= R.blovl[a]; + v= re->blovl[a]; - if(v==0) { + if(v==NULL) { v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen),"findOrAddVlak"); - R.blovl[a]= v; + re->blovl[a]= v; } v+= (nr & 255); return v; @@ -326,7 +334,7 @@ VlakRen *RE_findOrAddVlak(int nr) /* ------------------------------------------------------------------------- */ -HaloRen *RE_inithalo(Material *ma, float *vec, float *vec1, +HaloRen *RE_inithalo(Render *re, Material *ma, float *vec, float *vec1, float *orco, float hasize, float vectsize, int seed) { HaloRen *har; @@ -336,18 +344,18 @@ HaloRen *RE_inithalo(Material *ma, float *vec, float *vec1, if(hasize==0.0) return NULL; - RE_projectverto(vec, hoco); + projectverto(vec, re->winmat, hoco); if(hoco[3]==0.0) return NULL; if(vec1) { - RE_projectverto(vec1, hoco1); + projectverto(vec1, re->winmat, hoco1); if(hoco1[3]==0.0) return NULL; } - har= RE_findOrAddHalo(R.tothalo++); + har= RE_findOrAddHalo(re, re->tothalo++); VECCOPY(har->co, vec); har->hasize= hasize; - /* projectvert is done in function 'zbufvlaggen' because of parts/border/pano */ + /* actual projectvert is done in function transform_renderdata() because of parts/border/pano */ /* halovect */ if(vec1) { @@ -355,14 +363,14 @@ HaloRen *RE_inithalo(Material *ma, float *vec, float *vec1, har->type |= HA_VECT; zn= hoco[3]; - har->xs= 0.5*R.rectx*(hoco[0]/zn); - har->ys= 0.5*R.recty*(hoco[1]/zn); + har->xs= 0.5*re->winx*(hoco[0]/zn); + har->ys= 0.5*re->winy*(hoco[1]/zn); har->zs= 0x7FFFFF*(hoco[2]/zn); har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); - xn= har->xs - 0.5*R.rectx*(hoco1[0]/hoco1[3]); - yn= har->ys - 0.5*R.recty*(hoco1[1]/hoco1[3]); + xn= har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]); + yn= har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]); if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0; else zn= atan2(yn, xn); @@ -435,4 +443,228 @@ HaloRen *RE_inithalo(Material *ma, float *vec, float *vec1, return har; } + +/* -------------------------- operations on entire database ----------------------- */ + +static float get_pano_rot(Render *re, int part) +{ + static float alpha= 1.0; + + /* part==0 init all */ + if(part==0) { + alpha= ((float)re->r.xsch)/re->viewfac; + alpha= 2.0*atan(alpha/2.0); + } + + /* rotate it all around the y-as with phi degrees */ + return 0.5*(re->r.xparts-1)*alpha + part*alpha; +} + +/* ugly function for halos in panorama */ +static int panotestclip(Render *re, int do_pano, float *v) +{ + /* to be used for halos en infos */ + float abs4; + short c=0; + + if(do_pano) return testclip(v); + + abs4= fabs(v[3]); + + if(v[2]< -abs4) c=16; /* this used to be " if(v[2]<0) ", see clippz() */ + else if(v[2]> abs4) c+= 32; + + if( v[1]>abs4) c+=4; + else if( v[1]< -abs4) c+=8; + + abs4*= re->r.xparts; + if( v[0]>abs4) c+=2; + else if( v[0]< -abs4) c+=1; + + return c; +} + +/* + This adds the hcs coordinates to vertices. It iterates over all + vertices, halos and faces. After the conversion, we clip in hcs. + + Elsewhere, all primites are converted to vertices. + Called in + - envmapping (envmap.c) + - shadow buffering (shadbuf.c) +*/ + +void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int part) +{ + VlakRen *vlr = NULL; + VertRen *ver = NULL; + HaloRen *har = NULL; + float zn, vec[3], hoco[4]; + int a; + + if(do_pano) { + float panophi= get_pano_rot(re, part); + + re->panosi= sin(panophi); + re->panoco= cos(panophi); + } + + /* calculate view coordinates (and zbuffer value) */ + for(a=0; a< re->totvert;a++) { + if((a & 255)==0) ver= RE_findOrAddVert(re, a); + else ver++; + + if(do_pano) { + vec[0]= re->panoco*ver->co[0] + re->panosi*ver->co[2]; + vec[1]= ver->co[1]; + vec[2]= -re->panosi*ver->co[0] + re->panoco*ver->co[2]; + } + else { + VECCOPY(vec, ver->co); + } + /* Go from wcs to hcs ... */ + projectfunc(vec, re->winmat, ver->ho); + /* ... and clip in that system. */ + ver->clip = testclip(ver->ho); + /* + Because all other ops are performed in other systems, this is + the only thing that has to be done. + */ + } + + /* calculate view coordinates (and zbuffer value) */ + for(a=0; a<re->tothalo; a++) { + if((a & 255)==0) har= re->bloha[a>>8]; + else har++; + + if(do_pano) { + vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2]; + vec[1]= har->co[1]; + vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2]; + } + else { + VECCOPY(vec, har->co); + } + + projectfunc(vec, re->winmat, hoco); + + /* we clip halos less critical, but not for the Z */ + hoco[0]*= 0.5; + hoco[1]*= 0.5; + + if( panotestclip(re, do_pano, hoco) ) { + har->miny= har->maxy= -10000; /* that way render clips it */ + } + else if(hoco[3]<0.0) { + har->miny= har->maxy= -10000; /* render clips it */ + } + else /* do the projection...*/ + { + /* bring back hocos */ + hoco[0]*= 2.0; + hoco[1]*= 2.0; + + zn= hoco[3]; + har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/ + har->ys= 0.5*re->winy*(1.0+hoco[1]/zn); + + /* this should be the zbuffer coordinate */ + har->zs= 0x7FFFFF*(hoco[2]/zn); + /* taking this from the face clip functions? seems ok... */ + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + vec[0]+= har->hasize; + projectfunc(vec, re->winmat, hoco); + vec[0]-= har->hasize; + zn= hoco[3]; + har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn)); + + /* this clip is not really OK, to prevent stars to become too large */ + if(har->type & HA_ONLYSKY) { + if(har->rad>3.0) har->rad= 3.0; + } + + har->radsq= har->rad*har->rad; + + har->miny= har->ys - har->rad/re->ycor; + har->maxy= har->ys + har->rad/re->ycor; + + /* the Zd value is still not really correct for pano */ + + vec[2]-= har->hasize; /* z negative, otherwise it's clipped */ + projectfunc(vec, re->winmat, hoco); + zn= hoco[3]; + zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn)); + har->zd= CLAMPIS(zn, 0, INT_MAX); + + } + + } + + /* set flags at 0 if clipped away */ + for(a=0; a<re->totvlak; a++) { + if((a & 255)==0) vlr= re->blovl[a>>8]; + else vlr++; + + vlr->flag |= R_VISIBLE; + if(vlr->v4) { + if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip & vlr->v4->clip) vlr->flag &= ~R_VISIBLE; + } + else if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip) vlr->flag &= ~R_VISIBLE; + + } + +} + /* ------------------------------------------------------------------------- */ + +void set_normalflags(Render *re) +{ + VlakRen *vlr = NULL; + float *v1, xn, yn, zn; + int a1, doflip; + + /* switch normal 'snproj' values (define which axis is the optimal one for calculations) */ + for(a1=0; a1<re->totvlak; a1++) { + if((a1 & 255)==0) vlr= re->blovl[a1>>8]; + else vlr++; + + /* abuse of this flag... this is code that just sets face normal in direction of camera */ + /* that convention we should get rid of */ + if((vlr->flag & R_NOPUNOFLIP)==0) { + + doflip= 0; + if(re->r.mode & R_ORTHO) { + if(vlr->n[2]>0.0) doflip= 1; + } + else { + v1= vlr->v1->co; + if( (v1[0]*vlr->n[0] +v1[1]*vlr->n[1] +v1[2]*vlr->n[2])<0.0 ) doflip= 1; + } + if(doflip) { + vlr->n[0]= -vlr->n[0]; + vlr->n[1]= -vlr->n[1]; + vlr->n[2]= -vlr->n[2]; + } + } + + /* recalculate puno. Displace & flipped matrices can screw up */ + vlr->puno= 0; + if(!(vlr->flag & R_TANGENT)) { + if( Inpf(vlr->n, vlr->v1->n) < 0.0 ) vlr->puno |= ME_FLIPV1; + if( Inpf(vlr->n, vlr->v2->n) < 0.0 ) vlr->puno |= ME_FLIPV2; + if( Inpf(vlr->n, vlr->v3->n) < 0.0 ) vlr->puno |= ME_FLIPV3; + if(vlr->v4 && Inpf(vlr->n, vlr->v4->n) < 0.0 ) vlr->puno |= ME_FLIPV4; + } + xn= fabs(vlr->n[0]); + yn= fabs(vlr->n[1]); + zn= fabs(vlr->n[2]); + if(zn>=xn && zn>=yn) vlr->snproj= 0; + else if(yn>=xn && yn>=zn) vlr->snproj= 1; + else vlr->snproj= 2; + + } +} + + + diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 9ff3c104d0a..1403139269f 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -1,14 +1,10 @@ -/* shadbuf.c RENDER - * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +/* + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,20 +18,10 @@ * 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. + * Contributor(s): 2004-2006, Blender Foundation * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** - * - * april 95 - * - * $Id$ - * - * 27-Jun-2001 switched the shadow buffer for UR to the object-shadow - * buffers, and removed all references and fixes for UR rendering from - * this one. - * */ + * ***** END GPL LICENSE BLOCK ***** + */ #include <math.h> #include <string.h> @@ -45,16 +31,18 @@ #include "DNA_lamp_types.h" #include "BKE_utildefines.h" + #include "BLI_arithb.h" +#include "BLI_jitter.h" -#include "render.h" +#include "renderpipeline.h" +#include "render_types.h" +#include "renderdatabase.h" #include "shadbuf.h" -#include "renderHelp.h" -#include "jitter.h" #include "zbuf.h" -/* XXX, could be better implemented... +/* XXX, could be better implemented... this is for endian issues */ #if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) #define RCOMP 3 @@ -70,80 +58,27 @@ /* ------------------------------------------------------------------------- */ +/* initshadowbuf() in convertBlenderScene.c */ -void RE_initshadowbuf(LampRen *lar, float mat[][4]) -{ - struct ShadBuf *shb; - float hoek, temp, viewinv[4][4]; - - /* if(la->spsi<16) return; */ - - /* memory reservation */ - shb= (struct ShadBuf *)MEM_callocN( sizeof(struct ShadBuf),"initshadbuf"); - lar->shb= shb; - - if(shb==NULL) return; - - VECCOPY(shb->co, lar->co); - - /* percentage render: keep track of min and max */ - shb->size= (lar->bufsize*R.r.size)/100; - if(shb->size<512) shb->size= 512; - else if(shb->size > lar->bufsize) shb->size= lar->bufsize; - - shb->size &= ~15; /* make sure its multiples of 16 */ - - shb->samp= lar->samp; - shb->soft= lar->soft; - shb->shadhalostep= lar->shadhalostep; - - shb->zbuf= (unsigned long *)MEM_mallocN( sizeof(unsigned long)*(shb->size*shb->size)/256, "initshadbuf2"); - shb->cbuf= (char *)MEM_callocN( (shb->size*shb->size)/256, "initshadbuf3"); - - if(shb->zbuf==0 || shb->cbuf==0) { - if(shb->zbuf) MEM_freeN(shb->zbuf); - MEM_freeN(lar->shb); - lar->shb= 0; - return; - } - - MTC_Mat4Ortho(mat); - MTC_Mat4Invert(shb->winmat, mat); /* winmat is temp */ - - /* matrix: combination of inverse view and lampmat */ - /* calculate again: the ortho-render has no correct viewinv */ - MTC_Mat4Invert(viewinv, R.viewmat); - MTC_Mat4MulMat4(shb->viewmat, viewinv, shb->winmat); - - /* projection */ - hoek= saacos(lar->spotsi); - temp= 0.5*shb->size*cos(hoek)/sin(hoek); - shb->d= lar->clipsta; - - shb->pixsize= (shb->d)/temp; - - shb->far= lar->clipend; - /* bias is percentage, made 2x karger because of correction for angle of incidence */ - /* when a ray is closer to parallel of a face, bias value is increased during render */ - shb->bias= (0.02*lar->bias)*0x7FFFFFFF; - shb->bias= shb->bias*(100/R.r.size); - -} /* ------------------------------------------------------------------------- */ - -static void lrectreadRectz(int x1, int y1, int x2, int y2, char *r1) /* reads part from rectz in r1 */ +static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1) { - unsigned int len4, *rz; - - if(x1>=R.rectx || x2>=R.rectx || y1>=R.recty || y2>=R.recty) return; - if(x1>x2 || y1>y2) return; - - len4= 4*(x2- x1+1); - rz= R.rectz+R.rectx*y1+x1; - for(;y1<=y2;y1++) { - memcpy(r1,rz,len4); - rz+= R.rectx; + int len4, *rz; + int x2, y2; + + x2= x1+tile; + y2= y1+tile; + if(x2>=size) x2= size-1; + if(y2>=size) y2= size-1; + + if(x1>=x2 || y1>=y2) return; + + len4= 4*(x2- x1); + rz= rectz + size*y1 + x1; + for(; y1<y2; y1++) { + memcpy(r1, rz, len4); + rz+= size; r1+= len4; } } @@ -180,7 +115,7 @@ static float *give_jitter_tab(int samp) for(a=0; a<samp-1; a++) offset+= tab[a]; if(ctab[samp]==0) { - initjit(jit[offset], samp*samp); + BLI_initjit(jit[offset], samp*samp); ctab[samp]= 1; } @@ -188,56 +123,35 @@ static float *give_jitter_tab(int samp) } -void makeshadowbuf(LampRen *lar) +void makeshadowbuf(Render *re, LampRen *lar) { struct ShadBuf *shb= lar->shb; - float panophi; - float temp, wsize, dist; - int *rz, *rz1, verg, verg1; + float wsize, dist; + int *rectz, *rz, *rz1, verg, verg1; unsigned long *ztile; - int a, x, y, minx, miny, byt1, byt2, tempmode; - short temprx,tempry, square; + int a, x, y, minx, miny, byt1, byt2, square; char *rc, *rcline, *ctile, *zt; - panophi = getPanoPhi(); - - /* store viewvars */ - temprx= R.rectx; tempry= R.recty; - tempmode= R.r.mode; - R.r.mode &= ~R_ORTHO; - R.rectx= R.recty= shb->size; - shb->jit= give_jitter_tab(shb->samp); - /* matrices and window: in R.winmat the transformation is being put, + /* matrices and window: in winmat the transformation is being put, transforming from observer view to lamp view, including lamp window matrix */ - wsize= shb->pixsize*(shb->size/2.0); - i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->far, shb->winmat); + i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->clipend, shb->winmat); MTC_Mat4MulMat4(shb->persmat, shb->viewmat, shb->winmat); /* temp, will be restored */ - MTC_Mat4SwapMat4(shb->persmat, R.winmat); + MTC_Mat4SwapMat4(shb->persmat, re->winmat); /* zbuffering */ - if(R.rectz) MEM_freeN(R.rectz); - R.rectz= (unsigned int *)MEM_mallocN(sizeof(int)*shb->size*shb->size,"makeshadbuf"); - rcline= MEM_mallocN(256*4+sizeof(int),"makeshadbuf2"); - - /* store: panorama rot */ - temp= panophi; - panophi= 0.0; - pushTempPanoPhi(0.0); - - /* pano interference here? */ - setzbufvlaggen(projectvert); + rectz= MEM_mallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf"); + rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2"); - popTempPanoPhi(); - panophi= temp; + project_renderdata(re, projectvert, 0, 0); - zbuffershad(lar); + zbuffer_shadow(re, lar, rectz, shb->size); square= lar->mode & LA_SQUARE; @@ -263,7 +177,7 @@ void makeshadowbuf(LampRen *lar) rz1= (&verg)+1; } else { - lrectreadRectz(x, y, MIN2(shb->size-1,x+15), MIN2(shb->size-1,y+15), rcline); + copy_to_ztile(rectz, shb->size, x, y, 16, rcline); rz1= (int *)rcline; verg= (*rz1 & 0xFFFFFF00); @@ -334,12 +248,10 @@ void makeshadowbuf(LampRen *lar) } MEM_freeN(rcline); - MEM_freeN(R.rectz); R.rectz= NULL; + MEM_freeN(rectz); - /* old globals back */ - R.rectx= temprx; R.recty= tempry; - R.r.mode= tempmode; - MTC_Mat4SwapMat4(shb->persmat, R.winmat); + /* old matrix back */ + MTC_Mat4SwapMat4(shb->persmat, re->winmat); /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */ } @@ -455,7 +367,7 @@ float testshadowbuf(struct ShadBuf *shb, float *rco, float *dxco, float *dyco, f xs1= siz*(1.0+co[0]/co[3]); ys1= siz*(1.0+co[1]/co[3]); - /* Clip for z: near and far clip values of the shadow buffer. We + /* Clip for z: clipsta and clipend clip values of the shadow buffer. We * can test for -1.0/1.0 because of the properties of the * coordinate transformations. */ fac= (co[2]/co[3]); diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index b3d053b3f34..fae58a1ec29 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1,17 +1,12 @@ -/* texture.c - * - * +/* * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,11 +20,9 @@ * 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. + * Contributor(s): 2004-2006, Blender Foundation, full recode * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -37,10 +30,6 @@ #include <string.h> #include <math.h> -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include "MTC_matrixops.h" #include "BLI_blenlib.h" @@ -70,11 +59,19 @@ #include "BKE_key.h" #include "BKE_ipo.h" -#include "render.h" +#include "renderpipeline.h" +#include "render_types.h" #include "rendercore.h" #include "envmap.h" #include "texture.h" +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + /* prototypes */ static int calcimanr(int cfra, Tex *tex); @@ -174,12 +171,6 @@ void init_render_texture(Tex *tex) } } } - if(tex->imaflag & (TEX_ANTIALI+TEX_ANTISCALE)) { - if(tex->ima && tex->ima->lastquality<R.osa) { - if(tex->ima->ibuf) IMB_freeImBuf(tex->ima->ibuf); - tex->ima->ibuf= 0; - } - } if(tex->type==TEX_PLUGIN) { if(tex->plugin && tex->plugin->doit) { @@ -194,8 +185,8 @@ void init_render_texture(Tex *tex) tex->extend= TEX_CLIP; if(tex->env) { - if(R.flag & R_RENDERING) { - if(tex->env->stype==ENV_ANIM) RE_free_envmapdata(tex->env); + if(G.rendering) { + if(tex->env->stype==ENV_ANIM) BKE_free_envmapdata(tex->env); } } } @@ -1232,34 +1223,6 @@ int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexRes return retval; } -/* preview render */ -int multitex_ext(Tex *tex, float *texvec, float *tin, float *tr, float *tg, float *tb, float *ta) -{ - TexResult texr; - float dummy[3]; - int retval; - - /* does not return Tin, hackish... */ - if(tex->type==TEX_STUCCI) { - texr.nor= dummy; - dummy[0]= 1.0; - dummy[1]= dummy[2]= 0.0; - } - else texr.nor= NULL; - - retval= multitex(tex, texvec, NULL, NULL, 0, &texr); - if(tex->type==TEX_STUCCI) { - *tin= 0.5 + 0.7*texr.nor[0]; - CLAMP(*tin, 0.0, 1.0); - } - else *tin= texr.tin; - *tr= texr.tr; - *tg= texr.tg; - *tb= texr.tb; - *ta= texr.ta; - return retval; -} - /* ------------------------------------------------------------------------- */ /* in = destination, tex = texture, out = previous color */ diff --git a/source/blender/render/intern/source/vanillaRenderPipe.c b/source/blender/render/intern/source/vanillaRenderPipe.c deleted file mode 100644 index 1b74adaae9c..00000000000 --- a/source/blender/render/intern/source/vanillaRenderPipe.c +++ /dev/null @@ -1,1641 +0,0 @@ -/** - * - * ***** 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 ***** - * vanillaRenderPipe.c - * - * 28-06-2000 nzc - * - * $Id$ - * - */ - -/* - The render pipe - --------------- - - The overall results of the render pass should end up in R.rectot. This - buffer already exists, and although its contents may change, its location - may not. A lot of other routines depend on it! - -*/ - -/* global includes */ -#include <math.h> -#include <limits.h> /* INT_MIN,MAX are used here */ -#include <stdlib.h> -#include "MTC_vectorops.h" -#include "MTC_matrixops.h" -#include "MEM_guardedalloc.h" - -#include "DNA_camera_types.h" -#include "DNA_object_types.h" -#include "BKE_global.h" -#include "BKE_utildefines.h" - -#include "BLI_arithb.h" -#include "BLI_rand.h" - -/* local includes (from the render module) */ -#include "RE_callbacks.h" -#include "render.h" /* all kinds of stuff */ -#include "zbuf.h" /* for vergzvlak, zbufclip, zbufclipwire */ -#include "edgeRender.h" /* all edge rendering stuff */ -#include "pixelshading.h" /* painting the pixels */ -#include "rendercore.h" - -/* general calculus and data manipulation, also local */ -#include "gammaCorrectionTables.h" -#include "jitter.h" -#include "pixelblending.h" -#include "zbufferdatastruct.h" - -/* own includes */ -#include "vanillaRenderPipe.h" - -#include "SDL_thread.h" - -/* threshold for alpha */ -#define RE_FULL_ALPHA_FLOAT 0.9998 - -/* ------------------------------------------------------------------------- */ -/* Debug defines: disable all for production level code. */ -/* These variables control faking of rendered colours, extra tracing, */ -/* extra error checking and such. */ -/* ------------------------------------------------------------------------- */ - -/* if defined: _very_ explicit tracing and checking enabled */ -/* #define RE_FULL_SAFETY */ -/* if defined: use 'simple' alpha thresholding on oversampling */ -/* #define RE_SIMPLE_ALPHA_THRESHOLD */ - -/* ------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------- */ - -/* External : -------------------------------------------------------------- */ - -extern float centLut[16]; /* Lookup for jitter offsets. */ -extern unsigned int Zsample; /* Nr. of the currently active oversample. This */ - /* counter must be set explicitly by the */ - /* function that builds the z-buffer. */ - /* The buffer-filling functions use it. */ -extern float Zjitx,Zjity; /* The x,y values for jitter offset */ - -extern float Zmulx, Zmuly; /* Some kind of scale? */ - -extern char cmask[256]; /* When a pixel is supersampled, we must */ -extern char *centmask; /* compute its colour on a point _on_ the face. */ - /* These two are used to compute an offset to */ - /* guarantee we use valid coordinates. */ - -extern RE_APixstrExt *APixbufExt;/*Zbuffer: linked list of face, halo indices*/ - -/* Globals : --------------------------------------------------------------- */ - /* we use 2 x three lines, for gaussian sample */ -RE_COLBUFTYPE *AColourBuffer0; /* Buffer for colours of 1 line of pixels */ -RE_COLBUFTYPE *AColourBuffer1; /* Buffer for colours of 1 line of pixels */ -RE_COLBUFTYPE *AColourBuffer2; /* Buffer for colours of 1 line of pixels */ -RE_COLBUFTYPE *AColourBuffer1a; /* Buffer for colours of 1 line of pixels */ -RE_COLBUFTYPE *AColourBuffer2a; /* Buffer for colours of 1 line of pixels */ -RE_COLBUFTYPE *AColourBuffer3; /* Buffer for colours of 1 line of pixels */ - -static int Aminy; /* y value of first line in the accu buffer */ -static int Amaxy; /* y value of last line in the accu buffer */ - /* -also used to clip when zbuffering */ - -/* Buffer width refers to the size of the buffers we build. Image size is */ -/* the same as R.rectx, R.recty. */ -static int zBufferWidth; /* special width because zbuffer needs to be */ - /* wider */ - -static int Azvoordeel; /* A small offset for transparent rendering. */ -int alphaLUT[32]; /* alpha lookuptable, for oversampling */ - /* Its function has been superceded because */ - /* pixels are always integrated. This */ - /* performs the same normalization. */ -int osaNr; /* The oversample number. I keep it */ - /* separately here, because I treat no OSA */ - /* as if it were osa=1. */ - -/* ------------------------------------------------------------------------- */ - -/** -* Z buffer initializer, for new pipeline. - * <LI> - * <IT> AColourBuffer : colour buffer for one line - * <IT> APixbufExt : pixel data buffer for one line, depth RE_ZBUFLEN - * </LI> - */ -static void initRenderBuffers(int bwidth) -{ - /* bwidth+4, as in rendercore.c. I think it's too much, but yah (ton) */ - AColourBuffer0 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - AColourBuffer1 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - AColourBuffer2 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - AColourBuffer1a = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - AColourBuffer2a = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - AColourBuffer3 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow"); - - /* The +1 is needed because the fill-functions use a +1 offset when */ - /* filling in pixels. Mind that also the buffer-clearing function needs */ - /* this offset (done in calcZBufLine). */ - /* The offset is wrong: it shouldn't be there. I need to fix this still. */ - zBufferWidth = bwidth + 1; - initZbuffer(bwidth + 1); - - Aminy= -1000; /* indices of lines in the z buffer: no lines buffered */ - Amaxy= -1000; - - -} - -/* ------------------------------------------------------------------------- */ -/** - * Z buffer destructor, frees stuff from initZBuffers(). - */ - -static void freeRenderBuffers(void) { - if (AColourBuffer0) MEM_freeN(AColourBuffer0); - if (AColourBuffer1) MEM_freeN(AColourBuffer1); - if (AColourBuffer2) MEM_freeN(AColourBuffer2); - if (AColourBuffer1a) MEM_freeN(AColourBuffer1a); - if (AColourBuffer2a) MEM_freeN(AColourBuffer2a); - if (AColourBuffer3) MEM_freeN(AColourBuffer3); - freeZbuffer(); -} -/* ------------------------------------------------------------------------- */ - -/** - * New fill function for z buffer, for edge-only rendering. - */ -static void zBufferFillFace(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) -{ - /* Coordinates of the vertices are specified in ZCS */ - VlakRen *vlr; - int apteller, apoffsetteller; - double z0; /* used as temp var*/ - double xx1; - double zxd,zyd,zy0, tmp; - float *minv,*maxv,*midv; - register int zverg,zvlak,x; - int my0,my2,sn1,sn2,rectx,zd; - int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2, mask; - int obtype; - /* These used to be doubles. We may want to change them back if the */ - /* loss of accuracy proves to be a problem? There does not seem to be */ - /* any performance issues here, so I'll just keep the doubles. */ - /* float vec0[3], vec1[3], vec2[3]; */ - double vec0[3], vec1[3], vec2[3]; - - vlr= RE_findOrAddVlak( (zvlnr-1) & 0x7FFFFF); - if(vlr->mat->mode & MA_ZTRA) obtype= RE_POLY; - else obtype= RE_POLY|RE_SOLID; - - /* MIN MAX */ - /* sort vertices for min mid max y value */ - if(v1[1]<v2[1]) { - if(v2[1]<v3[1]) { minv=v1; midv=v2; maxv=v3;} - else if(v1[1]<v3[1]) { minv=v1; midv=v3; maxv=v2;} - else { minv=v3; midv=v1; maxv=v2;} - } - else { - if(v1[1]<v3[1]) { minv=v2; midv=v1; maxv=v3;} - else if(v2[1]<v3[1]) { minv=v2; midv=v3; maxv=v1;} - else { minv=v3; midv=v2; maxv=v1;} - } - - if(minv[1] == maxv[1]) return; /* security to remove 'zero' size faces */ - - my0 = ceil(minv[1]); - my2 = floor(maxv[1]); - omsl = floor(midv[1]); - - /* outside the current z buffer slice: clip whole face */ - if( (my2 < Aminy) || (my0 > Amaxy)) return; - - if(my0<Aminy) my0= Aminy; - - /* EDGES : THE LONGEST */ - xx1= maxv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx0= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-minv[1])+minv[0]); - xs0= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx0= 0; - xs0= 65536.0*(MIN2(minv[0],maxv[0])); - } - /* EDGES : THE TOP ONE */ - xx1= maxv[1]-midv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-midv[0])/xx1; - - tmp= (-65536.0*z0); - dx1= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-midv[1])+midv[0]); - xs1= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx1= 0; - xs1= 65536.0*(MIN2(midv[0],maxv[0])); - } - /* EDGES : THE BOTTOM ONE */ - xx1= midv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (midv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx2= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]); - xs2= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx2= 0; - xs2= 65536.0*(MIN2(minv[0],midv[0])); - } - - /* ZBUF DX DY */ - /* xyz_1 = v_1 - v_2 */ - MTC_diff3DFF(vec1, v1, v2); - /* xyz_2 = v_2 - v_3 */ - MTC_diff3DFF(vec2, v2, v3); - /* xyz_0 = xyz_1 cross xyz_2 */ - MTC_cross3Double(vec0, vec1, vec2); - - /* cross product of two of the sides is 0 => this face is too small */ - if(vec0[2]==0.0) return; - - if(midv[1] == maxv[1]) omsl= my2; - if(omsl < Aminy) omsl= Aminy-1; /* make sure it takes the first loop entirely */ - - while (my2 > Amaxy) { /* my2 can be larger */ - xs0+=dx0; - if (my2<=omsl) { - xs2+= dx2; - } - else{ - xs1+= dx1; - } - my2--; - } - - xx1= (vec0[0]*v1[0]+vec0[1]*v1[1])/vec0[2]+v1[2]; - - zxd= -vec0[0]/vec0[2]; - zyd= -vec0[1]/vec0[2]; - zy0= my2*zyd+xx1; - zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX); - - /* start-ofset in rect */ - /* rectx= R.rectx; */ - /* I suspect this var needs very careful setting... When edge rendering */ - /* is on, this is strange */ - rectx = zBufferWidth; - apoffsetteller = rectx*(my2-Aminy); - - mask= 1<<Zsample; - zvlak= zvlnr; - - xs3= 0; /* flag */ - if(dx0>dx1) { - MTC_swapInt(&xs0, &xs1); - MTC_swapInt(&dx0, &dx1); - xs3= 1; /* flag */ - - } - - for(y=my2;y>omsl;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs1>>16; - xs1+= dx1; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - apteller = apoffsetteller + sn1; - x= sn2-sn1; - - zverg-= Azvoordeel; - - while(x>=0) { - insertObject(apteller, zvlnr, obtype, zverg, mask); - zverg+= zd; - apteller++; - x--; - } - zy0-= zyd; - apoffsetteller -= rectx; - } - - if(xs3) { - xs0= xs1; - dx0= dx1; - } - if(xs0>xs2) { - xs3= xs0; - xs0= xs2; - xs2= xs3; - xs3= dx0; - dx0= dx2; - dx2= xs3; - } - - for(; y>=my0; y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs2>>16; - xs2+= dx2; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - apteller = apoffsetteller + sn1; - x= sn2-sn1; - - zverg-= Azvoordeel; - - while(x>=0) { - insertObject(apteller, zvlnr, obtype, zverg, mask); - zverg+= zd; - apteller++; - x--; - } - - zy0-=zyd; - apoffsetteller -= rectx; - } -} -/* ------------------------------------------------------------------------- */ - -static void zBufferFillEdge(int zvlnr, float *vec1, float *vec2) -{ - int apteller; - int start, end, x, y, oldx, oldy, ofs; - int dz, vergz, mask, maxtest=0; - float dx, dy; - float v1[3], v2[3]; - - dx= vec2[0]-vec1[0]; - dy= vec2[1]-vec1[1]; - - if(fabs(dx) > fabs(dy)) { - - /* all lines from left to right */ - if(vec1[0]<vec2[0]) { - VECCOPY(v1, vec1); - VECCOPY(v2, vec2); - } - else { - VECCOPY(v2, vec1); - VECCOPY(v1, vec2); - dx= -dx; dy= -dy; - } - - start= floor(v1[0]); - end= start+floor(dx); - if(end >= zBufferWidth) end = zBufferWidth - 1; - - oldy= floor(v1[1]); - dy/= dx; - - vergz= v1[2]; - vergz-= Azvoordeel; - dz= (v2[2]-v1[2])/dx; - if(vergz>0x70000000 && dz>0) maxtest= 1; // prevent overflow - - apteller = zBufferWidth*(oldy-Aminy) +start; - mask = 1<<Zsample; - - if(dy<0) ofs= -zBufferWidth; - else ofs= zBufferWidth; - - for(x= start; x<=end; x++, /* ap++, */ apteller++) { - - y= floor(v1[1]); - if(y!=oldy) { - oldy= y; - apteller += ofs; - } - - if(x>=0 && y>=Aminy && y<=Amaxy) { - insertObject(apteller, zvlnr, RE_POLY, vergz, mask); - } - - v1[1]+= dy; - vergz+= dz; - if(maxtest && vergz<0) vergz= 0x7FFFFFF0; - } - } - else { - - /* all lines from top to bottom */ - if(vec1[1]<vec2[1]) { - VECCOPY(v1, vec1); - VECCOPY(v2, vec2); - } - else { - VECCOPY(v2, vec1); - VECCOPY(v1, vec2); - dx= -dx; dy= -dy; - } - - start= floor(v1[1]); - end= start+floor(dy); - - if(start>Amaxy || end<Aminy) return; - - if(end>Amaxy) end= Amaxy; - - oldx= floor(v1[0]); - dx/= dy; - - vergz= v1[2]; - vergz-= Azvoordeel; - dz= (v2[2]-v1[2])/dy; - if(vergz>0x70000000 && dz>0) maxtest= 1; // prevent overflow - - apteller = zBufferWidth*(start-Aminy) +oldx; - - mask= 1<<Zsample; - - if(dx<0) ofs= -1; - else ofs= 1; - - for(y= start; y<=end; y++, apteller += zBufferWidth) { - - x= floor(v1[0]); - if(x!=oldx) { - oldx= x; - apteller += ofs; - } - - if(x>=0 && y>=Aminy && (x < zBufferWidth)) { - insertObject(apteller, zvlnr, RE_POLY, vergz, mask); - } - - v1[0]+= dx; - vergz+= dz; - if(maxtest && vergz<0) vergz= 0x7FFFFFF0; - } - } -} -/* ------------------------------------------------------------------------- */ - -/** - * Count and sort the list behind ap into buf. Sorts on min. distance. - * Low index <=> high z - */ -static int countAndSortPixelFaces(int zrow[][RE_PIXELFIELDSIZE], - RE_APixstrExt *ap) -{ - int totvlak; /* face counter */ - int i; /* generic counter */ - - totvlak= 0; - while(ap) { - for(i=0; i<4; i++) { - if(ap->t[i]) { - zrow[totvlak][0] = ap->zmin[i]; - zrow[totvlak][1] = ap->p[i]; - zrow[totvlak][2] = ap->mask[i]; - zrow[totvlak][3] = ap->t[i]; - zrow[totvlak][4] = ap->zmax[i]; - totvlak++; - if(totvlak > (RE_MAX_FACES_PER_PIXEL - 1)) - { - totvlak = (RE_MAX_FACES_PER_PIXEL - 1); - } - } else break; - }; - ap= ap->next; - } - - if(totvlak==2) { /* Sort faces ----------------------------- */ - if(zrow[0][0] < zrow[1][0]) { - i= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= i; - i= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= i; - i= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= i; - i= zrow[0][3]; zrow[0][3]= zrow[1][3]; zrow[1][3]= i; - i= zrow[0][4]; zrow[0][4]= zrow[1][4]; zrow[1][4]= i; - } /* else: two faces, and ordering is ok */ - } else if (totvlak != 1) qsort(zrow, totvlak, - sizeof(int)*RE_PIXELFIELDSIZE, vergzvlak); - return totvlak; -} - -/* ------------------------------------------------------------------------- */ -/* Oversampler v3 - check CVS for older versions */ -/* */ -/* In this version, I have split up the rendering into several parts, so I */ -/* can generate better profiles. */ -/* */ -/* - multiple blend functions ? */ -/* - x-rays? */ -/* - volumetric stuff ? */ -/* - maybe the oversampling should move to the shading part */ -/* */ -/* ------------------------------------------------------------------------- */ - -/* These variables describe the buffers needed for the oversampling. */ -/* 1. A bit vector with flags to indicate which pixels have received colour. */ -static int VR_covered = 0; -/* 2. The local vector collector, for resolving conflicts only. */ -static int VR_cbuf[RE_MAX_FACES_PER_PIXEL][2]; - -/** - * Analyze the z-buffer, and pre-sample the colours. - */ -static int composeStack(int zrow[][RE_PIXELFIELDSIZE], RE_COLBUFTYPE *collector, - struct RE_faceField* stack, int ptr, - int totvlak, float x, float y, int osaNr) -{ - VlakRen *vlr= NULL; - float xs = 0.0; - float ys = 0.0; /* coordinates for the render-spot */ - float alphathreshold[RE_MAX_OSA_COUNT]; - float colbuf[4]; - int inconflict = 0; - int saturationthreshold = 0; - int saturated = 0; - int i = 0; - int Ccount = 0; - int Cthresh = 0; - int save_totvlak = totvlak; - int fullsubpixelflags = 0; - int full_osa; - - VR_covered = 0; - for(i = 0; i < osaNr; i++) alphathreshold[i] = 0.0; - saturationthreshold = ( (1<<osaNr) - 1); - - while ( (!saturated || (saturated && inconflict) ) && (totvlak > 0) ) { - totvlak--; - - full_osa= 0; - if(R.osa && (zrow[totvlak][RE_TYPE] & RE_POLY)) { - vlr= RE_findOrAddVlak((zrow[totvlak][RE_INDEX]-1) & 0x7FFFFF); - if(vlr->flag & R_FULL_OSA) full_osa= 1; - } - - if(full_osa) { - float div=0.0, accol[4]={0.0, 0.0, 0.0, 0.0}; - int a, mask= zrow[totvlak][RE_MASK]; - - for(a=0; a<R.osa; a++) { - if(mask & (1<<a)) { - xs= (float)x + jit[a][0]; - ys= (float)y + jit[a][1]; - renderPixel(collector, xs, ys, zrow[totvlak], 1<<a); - accol[0] += collector[0]; accol[1] += collector[1]; accol[2] += collector[2]; accol[3] += collector[3]; - div+= 1.0; - } - } - if(div!=0.0) { - div= 1.0/div; - collector[0]= accol[0]*div; collector[1]= accol[1]*div; collector[2]= accol[2]*div; collector[3]= accol[3]*div; - } - stack[ptr].mask= mask; - stack[ptr].data= vlr; - } - else { - if(R.osa) { - i= centmask[ zrow[totvlak][RE_MASK] ]; /* recenter sample position - */ - xs= (float)x+centLut[i & 15]; - ys= (float)y+centLut[i >> 4]; - } - else { - xs= (float)x; - ys= (float)y; - } - - /* stack face ----------- */ - stack[ptr].mask = zrow[totvlak][RE_MASK]; - stack[ptr].data = renderPixel(collector, xs, ys, zrow[totvlak], stack[ptr].mask); - } - stack[ptr].faceType = zrow[totvlak][RE_TYPE]; - cpFloatColV(collector, stack[ptr].colour); - - /* This is done so that spothalos are properly overlayed on halos */ - /* maybe we need to check the colour here... */ - if(zrow[totvlak][RE_TYPE] & RE_POLY) VR_covered |= zrow[totvlak][RE_MASK]; - - /* calculate conflict parameters: ---------------------------------- */ - if( zrow[totvlak][RE_ZMIN] < Cthresh ) { - inconflict = 1; - /* Prevent from switching on bad data. This may be done more */ - /* efficiently later on. It is _quite_ important. */ - if (totvlak == save_totvlak - 1) Ccount = 0; - else if(Ccount == 0) Ccount = 2; - else Ccount++; - stack[ptr].conflictCount = Ccount; - if (zrow[totvlak][RE_ZMAX] > Cthresh) - Cthresh = zrow[totvlak][RE_ZMAX]; - } else { - Cthresh = zrow[totvlak][RE_ZMAX]; - Ccount = 0; - stack[ptr].conflictCount = 0; - if (totvlak > 0 ) - inconflict = (zrow[totvlak-1][RE_ZMIN] < Cthresh); - else inconflict = 0; - } - - ptr++; - - /* alpha threshold ------------------------------------------------- */ - /* There are currently two ways of blending: alpha-over, and add. */ - /* Add-blending does strange things, in the sense that alpha is */ - /* simply added, and colour is sort of alpha-over blended. Using the */ - /* same thresholding relation seems to work ok. For less than unity */ - /* add factor, the alpha threshold may rise faster, but currently we */ - /* do not check for this factor. */ - for(i = 0; i < osaNr; i++) { - if ( zrow[totvlak][RE_MASK] & (1<<i)) { - alphathreshold[i] += - ((1.0 - alphathreshold[i]) * collector[3]); - if (alphathreshold[i] > RE_FULL_ALPHA_FLOAT) - fullsubpixelflags |= (1<<i); - } - } - saturated = (fullsubpixelflags >= saturationthreshold); - - } /* done stacking ----------------------------------------------------- */ - - /* - STACK_SKY Sometimes, a sky pixel is needed. Since there are - some issues with mist/ ztra/ env, I always put the sky here. - */ -/* if (!saturated) { */ - totvlak--; - - xs= (float)x; - ys= (float)y; - - /* code identical for rendering empty sky pixel */ - renderSkyPixelFloat(collector, xs, ys, NULL); - cpFloatColV(collector, colbuf); - - if(R.flag & R_LAMPHALO) { - renderSpotHaloPixel(x, y, collector); - addAlphaOverFloat(colbuf, collector); - } - - stack[ptr].faceType = RE_SKY; - cpFloatColV(colbuf, stack[ptr].colour); - stack[ptr].data = NULL; - stack[ptr].mask = 0xFFFF; - stack[ptr].conflictCount = 0; - ptr++; -/* } */ - - /* Index of the top of the stack */ - return ptr; -} - -/* ------------------------------------------------------------------------- */ - -/** - * Calculate the view depth to this object on this location, with - * the current view parameters in R. - */ -static int calcDepth(float x, float y, void *data, int type) -{ - float view[3]; - - if (type & RE_POLY) { - VlakRen* vlr = (VlakRen*) data; - VertRen* v1; - float dface, div, zco, hoco_z, hoco_w; - int zbuf_co; - - v1 = vlr->v1; - - /* vertex dot face normal: WCS */ - dface= v1->co[0]*vlr->n[0]+v1->co[1]*vlr->n[1]+v1->co[2]*vlr->n[2]; - - /* jitter has been added to x, y ! */ - /* view vector view: screen coords */ - view[0]= (x+(R.xstart)+0.5); - - if(R.flag & R_SEC_FIELD) { - if(R.r.mode & R_ODDFIELD) view[1]= (y + R.ystart)*R.ycor; - else view[1]= (y + R.ystart + 1.0)*R.ycor; - } - else view[1]= (y + R.ystart + 0.5)*R.ycor; - - - /* for pano, another rotation in the xz plane is needed.... */ - - /* this is ok, in WCS */ - view[2]= -R.viewfac; /* distance to viewplane */ - - /* calculate zcoord */ - if(R.r.mode & R_ORTHO) { - /* x and y 3d coordinate can be derived from pixel coord and winmat */ - float fx= 2.0/(R.rectx*R.winmat[0][0]); - float fy= 2.0/(R.recty*R.winmat[1][1]); - - fx= (0.5 + x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0]; - fy= (0.5 + y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1]; - - /* using a*x + b*y + c*z = d equation, (a b c) is normal */ - zco= (dface - vlr->n[0]*fx - vlr->n[1]*fy)/vlr->n[2]; - - } - else { - /* face normal dot view vector: but how can this work? (nzc) */ - div = MTC_dot3Float(vlr->n, view); - if (div!=0.0) zco = (view[2]*dface)/div; - else zco = 0.0; - } - - /* same as in zbuf.c */ - hoco_z = zco*R.winmat[2][2] + R.winmat[3][2]; - hoco_w = zco*R.winmat[2][3] + R.winmat[3][3]; - - if(hoco_w!=0.0) zbuf_co = 0x7FFFFFFF*(hoco_z/hoco_w); - else zbuf_co= 0x7FFFFFFF; - - return zbuf_co; /* z component of R.co */ - } else if (type & RE_HALO) { - HaloRen* har = (HaloRen*) data; - return har->zBufDist; - } - return 0; -} - -/** - * Blend source over dest, and leave result in dest. 1 pixel. - */ -static void blendOverFloat(int type, float* dest, float* source, void* data) -{ - - if (type & RE_POLY) { - VlakRen *ver = (VlakRen*) data; - if ((ver->mat != NULL) && (ver->mat->add > RE_FACE_ADD_THRESHOLD)) { - char addf = (char) (ver->mat->add * 255.0); - addalphaAddfacFloat(dest, source, addf); - } - else - addAlphaOverFloat(dest, source); - } else if (type & RE_HALO) { - HaloRen *har= (HaloRen*) data; - addalphaAddfacFloat(dest, source, har->add); - } else if (type & RE_SKY) { - addAlphaOverFloat(dest, source); - } - -} - - -/** - * New approach: sample substacks. Each substack is first copied into - * a stack buffer, and then blended down. - * */ -static void integratePerSubStack(float *sampcol, struct RE_faceField* stack, - int ptr, float x, float y, int osaNr) -{ - int i = 0; - int j = 0; - int k = 0; - int l = 0; - int filterMask = 0; - /* next step would be to improve on the substack, I guess */ - int subStack[RE_MAX_FACES_PER_PIXEL + 1]; - float colSubStack[4 * (RE_MAX_FACES_PER_PIXEL + 1)]; - int subStackPtr = 0; - int subStackSize = 0; - float xs, ys; - - - while (i < osaNr) { - xs = x + jit[i][0]; - ys = y + jit[i][1]; - - /* - * 1. Copy all relevant faces. Mind that stack is built from - * low index = low z to high index =high z. The sub-stack is - * exactly the other way around! (low index = high z) - */ - filterMask = (1 << i); - subStackPtr = 0; - j = ptr - 1; /* the topmost valid face */ - while (j >= 0) { - if (stack[j].conflictCount) { - /* Conflict: we sort the faces for distance right - * away. We could adapt conflict count, and adjust the - * stack later on, but that's really doing too much, - * too complicated. This is just fine. - * */ - k = 0; - l = 0; - /* check whether the face intersects, and if so, - * stores depth */ - while (k < stack[j].conflictCount) { - if (stack[j - k].mask & filterMask) { - VR_cbuf[l][0] = calcDepth(xs, ys, - stack[j - k].data, - stack[j - k].faceType); - VR_cbuf[l][1] = j - k; - l++; - } - k++; - } - /* VR_cbuf now contains l pairs (distance, stackindex) */ - qsort(VR_cbuf, l, sizeof(int)*2, vergzvlak); - /* - * Now we put the sorted indices on the - * substack. qsort delivers low index = low z, which - * is the right wrong order for the substack */ - k = 0; - while (k < l) { - subStack[subStackPtr] = VR_cbuf[k][1]; - cpFloatColV(stack[VR_cbuf[k][1]].colour, &colSubStack[4*subStackPtr]); - subStackPtr++; - k++; - } - - j -= stack[j].conflictCount; - } else { - /* no conflict */ - if (stack[j].mask & filterMask) { - subStack[subStackPtr] = j; - cpFloatColV(stack[j].colour, &colSubStack[4*subStackPtr]); - subStackPtr++; - } - j--; - } - } - subStackSize = subStackPtr; - - /* 2. Operations on the faces can go here for now. I might - * want to mix this code with the blending. Currently, I only - * handle env/ztra faces. It's a dirty patch now...*/ - subStackPtr = subStackSize - 1; - while (subStackPtr >= 0) { - /* we can make a general meachanism here for operations */ - if (stack[subStack[subStackPtr]].faceType & RE_POLY){ - VlakRen* vlr = (VlakRen*) stack[subStack[subStackPtr]].data; - if (vlr->mat) { - /* ENV faces */ - if (vlr->mat->mode & MA_ENV) { - int m; - colSubStack[4*subStackPtr] = 0.0; - colSubStack[(4*subStackPtr) + 1] = 0.0; - colSubStack[(4*subStackPtr) + 2] = 0.0; - colSubStack[(4*subStackPtr) + 3] = 0.0; - m = subStackPtr - 1; - while (m >= 0) { - if (stack[subStack[m]].faceType != RE_SKY) { - colSubStack[4*m] = 0.0; - colSubStack[(4*m) + 1] = 0.0; - colSubStack[(4*m) + 2] = 0.0; - colSubStack[(4*m) + 3] = 0.0; - } - m--; - } - } - /* ZTRA faces */ - else if (!(vlr->mat->mode & MA_ZTRA)) { - int m; - m = subStackPtr - 1; - while (m >= 0) { - if (stack[subStack[m]].faceType != RE_SKY) { - colSubStack[4*m] = 0.0; - colSubStack[(4*m) + 1] = 0.0; - colSubStack[(4*m) + 2] = 0.0; - colSubStack[(4*m) + 3] = 0.0; - } - m--; - } - } - } - } - subStackPtr--; - } - - /* 3. blend down */ - subStackPtr = 0; - while( subStackPtr < subStackSize ) { - blendOverFloat(stack[subStack[subStackPtr]].faceType, /* type */ - sampcol + (4 * i), /* dest */ - &colSubStack[4 * subStackPtr], - stack[subStack[subStackPtr]].data); /* data */ - subStackPtr++; - } - - i++; - } -} - - - -/* ------------------------------------------------------------------------- */ -/* Rendering: per line */ -/* */ -/* For each pixel in this line, we render as follows: */ -/* a. Count the number of objects buffered for this pixel, and sort on z */ -/* ------- Result is left in zrow */ -/* b. Shade the pixel: */ -/* 1. From front to back: calculate the colour for this object */ -/* 2. Blend this colour in with the already calculated colour */ -/* Repeat 1. and 2. until no faces remain. */ -/* For each pixel, a face is only rendered once, even if it is */ -/* jittered. All subpixels get the colour of the weighted centre */ -/* of the jitter-positions this face covers. */ -/* ------- Result is left in sampcol[] */ -/* c. Copy the result to the colour buffer */ -/* d. Do gamma-corrected blending */ -/* */ -/* zrow may need some clarification: */ -/* 0 - min. distance */ -/* 1 - face/halo index */ -/* 2 - masks */ -/* 3 - type RE_POLY or RE_HALO */ -/* 4 - max. distance */ -/* It is used to store copies of RE_APixstrExt records. These are sorted for */ -/* distance, and then used for rendering pixels. zrow might be replaced by */ -/* an RE_APixstrExt* array */ -/* - redo the numbering to something more logical */ - - -/* threadsafe global arrays, too large for stack */ -typedef struct zbufline { - int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE]; - struct RE_faceField osastack[RE_MAX_FACES_PER_PIXEL + 1]; -} zbufline; - -static zbufline zb1, zb2; - -static void renderZBufLine(int y, RE_COLBUFTYPE *colbuf1, RE_COLBUFTYPE *colbuf2, RE_COLBUFTYPE *colbuf3) -{ - RE_APixstrExt *ap; /* iterator for the face-lists */ - RE_COLBUFTYPE collector[4]; - RE_COLBUFTYPE sampcol[RE_MAX_OSA_COUNT * 4]; - RE_COLBUFTYPE *j = NULL; /* generic pixel pointer */ - int apteller; - int x; /* pixel counter */ - int i; /* yet another counter */ - int stackDepth; /* faces-behind-this-pixel counter */ - int osastack_ptr; /* Points to the lowest empty field. The indexed */ - zbufline *zbl; - - /* thread safe row buffers */ - if(y & 1) zbl= &zb1; - else zbl= &zb2; - - /* Prepare iterators */ - ap = APixbufExt + (zBufferWidth * (y - Aminy)); - apteller = (zBufferWidth * (y - Aminy)); - - /* Rendering: give the right colour to this pixel (shade it) */ - for( x = 0; x < R.rectx; x++, ap++, colbuf1+=4, colbuf2+=4, colbuf3+=4) { - if(ap->t[0]) { - /* reset sample collector */ - j = sampcol; - for(i = 0; i < osaNr; i++, j+=4) { - j[0] = 0.0f; j[1] = 0.0f; - j[2] = 0.0f; j[3] = 0.0f; - }; - - /* a. count and sort number of faces */ - stackDepth = countAndSortPixelFaces( zbl->zrow, ap); - - /* b,c. oversample all subpixels, then integrate */ - osastack_ptr = 0; - osastack_ptr = composeStack(zbl->zrow, collector, zbl->osastack, osastack_ptr, - stackDepth, x, y, osaNr); - integratePerSubStack(sampcol, zbl->osastack, osastack_ptr, x, y, osaNr); - - /* d. Gamma corrected blending and Gaussian */ - sampleFloatColV2FloatColVFilter(sampcol, colbuf1, colbuf2, colbuf3, osaNr); - - } else { - /* Remember to do things back-to-front! */ - - /* This is a bit dirty. Depending on sky-mode, the pixel is */ - /* blended in differently. */ - renderSkyPixelFloat(collector, x, y, NULL); - - j = sampcol; - for(i = 0; i < osaNr; i++, j+=4) { - j[0]= collector[0]; j[1]= collector[1]; - j[2]= collector[2]; j[3]= collector[3]; - } - - /* Spothalos are part of the normal pixelshader, so for covered */ - /* pixels they are handled ok. They are 'normally' alpha blended */ - /* onto the existing colour in the collector. */ - if(R.flag & R_LAMPHALO) { - renderSpotHaloPixel(x, y, collector); - if(do_gamma) { - collector[0]= gammaCorrect(collector[0]); - collector[1]= gammaCorrect(collector[1]); - collector[2]= gammaCorrect(collector[2]); - } - - j = sampcol; - for(i = 0; i < osaNr; i++, j+=4) { - addAlphaOverFloat(j, collector); - } - } - - sampleFloatColV2FloatColVFilter(sampcol, colbuf1, colbuf2, colbuf3, osaNr); - - } - } -} - - -/** - * Fills in distances of faces in the z buffer. - * - * Halo z buffering ---------------------------------------------- - * - * A halo is treated here as a billboard: no z-extension, always - * oriented perpendicular to the viewer. The rest of the z-buffer - * stores face-numbers first, then calculates colours as the - * final image is rendered. We'll use the same approach here, - * which differs from the original method (which was add halos per - * scan line). This means that the z-buffer now also needs to - * store info about what sort of 'thing' the index refers to. - * - * Halo extension: - * h.maxy --------- - * | h.xs + h.rad - * | h.xs - * | h.xs - h.rad - * h.miny --------- - * - * These coordinates must be clipped to picture size. - * I'm not quite certain about halo numbering. - * - * Halos and jittering ------------------------------------------- - * - * Halos were not jittered previously. Now they are. I wonder - * whether this may have some adverse effects here. - - * @return 1 for succes, 0 if the operation was interrupted. - */ - -/* ------------------------------------------------------------------------- */ -/* Transparent faces and the 'Azvoordeel' */ -/* A transparent face can get a z-offset, which is a */ -/* way of pretending the face is a bit closer than it */ -/* actually is. This is used in animations, when faces */ -/* that are used to glue on animated characters, items, */ -/* et. need their shadows to be drawn on top of the */ -/* objects they stand on. The Azvoordeel is added to */ -/* the calculated z-coordinate in the buffer-fill */ -/* procedures. */ - -/* static int RE_treat_face_as_opaque; */ - -static int zBufferAllFaces(void) -{ - VlakRen *vlr=NULL; - unsigned int zvlnr; - int faceCounter; - int keepLooping = 1; - float vec[3], hoco[4], mul, zval, fval; - Material *ma=0; - - faceCounter = 0; - -/* printf("Going to buffer faces:\n"); */ -/* printf("\tfirst pass:\n"); */ - -/* RE_treat_face_as_opaque = 1; */ - - while ( (faceCounter < R.totvlak) && keepLooping) { - if((faceCounter & 255)==0) { vlr= R.blovl[faceCounter>>8]; } - else vlr++; - - ma= vlr->mat; - - /* VERY dangerous construction... zoffs is set by a slide in the ui */ - /* so it should be safe... */ - if((ma->mode & (MA_ZTRA)) && (ma->zoffs != 0.0)) { - mul= 0x7FFFFFFF; - zval= mul*(1.0+vlr->v1->ho[2]/vlr->v1->ho[3]); - - VECCOPY(vec, vlr->v1->co); - /* z is negatief, wordt anders geclipt */ - vec[2]-= ma->zoffs; - RE_projectverto(vec, hoco); /* vec onto hoco */ - fval= mul*(1.0+hoco[2]/hoco[3]); - - Azvoordeel= (int) fabs(zval - fval ); - } else { - Azvoordeel= 0; - } - /* face number is used in the fill functions */ - zvlnr = faceCounter + 1; - - if(vlr->flag & R_VISIBLE) { /* might test for this sooner... */ - - if(ma->mode & (MA_WIRE)) zbufclipwire(zvlnr, vlr); - else { - zbufclip(NULL, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, - vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); - if(vlr->v4) { - zvlnr+= 0x800000; /* in a sense, the 'adjoint' face */ - zbufclip(NULL, zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, - vlr->v1->clip, vlr->v3->clip, vlr->v4->clip); - } - } - } - if(RE_local_test_break()) keepLooping = 0; - faceCounter++; - } - - return keepLooping; -} - -/** - * Fills in distances of halos in the z buffer. - * @return 1 for succes, 0 if the operation was interrupted. - */ - -/* ------------------------------------------------------------------------- */ -/* We cheat a little here: we only fill the halo on the first pass, and we */ -/* set a full complement of mask flags. This can be done because we consider */ -/* halos to be flat (billboards), so we do not have to correct the z range */ -/* every time we insert a halo. Also, halos fall off to zero at the edges, */ -/* so we can safely render them in pixels where they do not exist. */ -static int zBufferAllHalos(void) -{ - HaloRen *har = NULL; - int haloCounter = 0; - int dist = 0; - int keepLooping = 1; - short miny = 0, maxy = 0, minx = 0, maxx = 0; - short ycount = 0, xcount = 0; - RE_APixstrExt *ap, *apoffset; - int mask; /* jitter mask */ - - if (!Zsample) - { - mask = (1 << osaNr) - 1 ; /* Fill all samples together */ - - while ( (haloCounter < R.tothalo) && keepLooping) { - if((haloCounter & 255)==0) har= R.bloha[haloCounter>>8]; - else har++; - - /* Halos are sometimes wrongly kicked out of the box they belong */ - /* in... */ - - /* Only buffer the current alpha buffer contents!!! The line */ - /* indices have already been clipped to picture size. */ - minx = floor(har->xs - har->rad) - 1; /* assume min =< max is true*/ - if (minx < 0 ) minx = 0; - maxx = ceil(har->xs + har->rad ) + 1; - /* Do the extra -1 because of the +1 later on. I guess halos might */ - /* have to start one pixel sooner? Or maybe the lower clip should */ - /* be adjusted */ - if (maxx >= zBufferWidth - 1) maxx = zBufferWidth - 2; - - miny = har->miny; - if (miny < Aminy) miny = Aminy; - maxy = har->maxy; - if (maxy > Amaxy) maxy = Amaxy; - - if ( (minx <= maxx) && (miny <= maxy)) { - /* distance to this halo? */ - dist = har->zBufDist /* * R.ycor */; - /* strange that the ycor influences the z coordinate ..*/ - ycount = miny; - while (ycount <= maxy) { - apoffset = APixbufExt + (zBufferWidth * (ycount - Aminy)); - ap = apoffset + minx; - xcount = minx; - while (xcount <= maxx) { - insertFlatObjectNoOsa(ap, haloCounter, RE_HALO, dist, mask); - xcount++; - ap++; - } - ycount++; - } - } - if(RE_local_test_break()) keepLooping = 0; - haloCounter++; - } - } - - return keepLooping; -} -/* ------------------------------------------------------------------------- */ - -/** -* Fills in distances of all faces in a z buffer, for given jitter settings. - */ -static int fillZBufDistances() -{ - int keepLooping = 1; - - keepLooping = zBufferAllFaces(); /* Solid and transparent faces*/ - keepLooping = zBufferAllHalos() && keepLooping; /* ...and halos*/ - return keepLooping; - -} - - - -#if 0 -/* ------------------------------------------------------------------------- */ -/** - * One more filler: fill in halo data in z buffer. - * Empty so far, but may receive content of halo loop. - */ -void zBufferFillHalo(void) -{ - /* so far, intentionally empty */ -} -#endif - -/* ------------------------------------------------------------------------- */ -/* Colour buffer related: */ -/* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value */ -/* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd. */ -/* This is the standard transformation, more elaborate tools are for later. */ -/* ------------------------------------------------------------------------- */ -void std_floatcol_to_charcol( float *buf, char *target) -{ - float col[3]; - - float dither_value; - - dither_value = ((BLI_frand()-0.5)*R.r.dither_intensity)/256.0; - - /* alpha */ - if((buf[3]+dither_value)<=0.0) target[3]= 0; - else if((buf[3]+dither_value)>1.0) target[3]= 255; - else target[3]= 255.0*(buf[3]+dither_value); - - if(R.r.postgamma==1.0) { - /* r */ - col[0]= R.r.postmul*buf[0] + R.r.postadd + dither_value; - /* g */ - col[1]= R.r.postmul*buf[1] + R.r.postadd + dither_value; - /* b */ - col[2]= R.r.postmul*buf[2] + R.r.postadd + dither_value; - } - else { - /* putting the postmul within the pow() gives an - * easier control for the user, values from 1.0-2.0 - * are relevant then - */ - - /* r */ - col[0]= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd + dither_value; - /* g */ - col[1]= pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd + dither_value; - /* b */ - col[2]= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd + dither_value; - } - - if(R.r.posthue!=0.0 || R.r.postsat!=1.0) { - float hsv[3]; - - rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2); - hsv[0]+= R.r.posthue; - if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; - hsv[1]*= R.r.postsat; - if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; - hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); - } - - if(col[0]<=0.0) target[0]= 0; - else if(col[0]>1.0) target[0]= 255; - else target[0]= 255.0*col[0]; - - if(col[1]<=0.0) target[1]= 0; - else if(col[1]>1.0) target[1]= 255; - else target[1]= 255.0*col[1]; - - if(col[2]<=0.0) target[2]= 0; - else if(col[2]>1.0) target[2]= 255; - else target[2]= 255.0*col[2]; -} - -/* ---------------------------------------------------------------------------- - - Colour buffer related: - - The colour buffer is a buffer of a single screen line. It contains - four fields of type RE_COLBUFTYPE per pixel. - - We can do several post-process steps. I would prefer to move them outside - the render module later on, but it's ok to leave it here for now. For the - time being, we have: - - post-process function - Does some operations with the colours. - - Multiply with some factor - - Add constant offset - - Apply extra gamma correction (seems weird...) - - key-alpha correction - Key alpha means 'un-applying' the alpha. For fully covered pixels, this - operation has no effect. - - - XXX WARNING! Added the inverse render gamma here, so this cannot be used external - without setting Osa or Gamme flags off (ton) - ----------------------------------------------------------------------------- */ -/* used external! */ -void transferColourBufferToOutput( float *buf, int y) -{ - /* Copy the contents of AColourBuffer3 to R.rectot + y * R.rectx */ - int x = 0; - char *target = (char*) (R.rectot + (y * R.rectx)); - - /* Copy the first <R.rectx> pixels. We can do some more clipping on */ - /* the z buffer, I think. */ - while (x < R.rectx) { - - - /* invert gamma corrected additions */ - if(do_gamma) { - buf[0] = invGammaCorrect(buf[0]); - buf[1] = invGammaCorrect(buf[1]); - buf[2] = invGammaCorrect(buf[2]); - } - - std_floatcol_to_charcol(buf, target); - - /* - Key-alpha mode: - Need to un-apply alpha if alpha is non-full. For full alpha, - the operation doesn't have effect. Do this after the post- - processing, so we can still use the benefits of that. - - */ - - if (getSkyBlendingMode() == RE_ALPHA_KEY) { - applyKeyAlphaCharCol(target); - } - - target+=4; - buf+=4; - x++; - } -} - -/* used for redisplay after render. assumes size globals to be set OK! */ -void RE_floatbuffer_to_output(void) -{ - float *buf= R.rectftot; - int pix= R.rectx*R.recty; - char *target = (char *)R.rectot; - - if(R.rectftot==NULL) return; - - while(pix--) { - std_floatcol_to_charcol(buf, target); - buf+= 4; - target+= 4; - } -} - -/* ------------------------------------------------------------------------- */ - -static void eraseColBuf(RE_COLBUFTYPE *buf) -{ - /* By definition, the buffer's length is 4 * R.rectx items */ - int i = 0; - - while (i < 4 * (R.rectx+3)) { - *buf = 0.0f; - buf++; i++; - } -} - -/* ------------------------------------------------------------------------- */ - - -/** - * Fill the accumulation buffer APixbufExt with face and halo indices. - * Note: Uses globals. - * @param y the line number to set - */ -static void calcZBufLine(int y) -{ - int part; - int keepLooping = 1; - - if(y<0) return; - - /* zbuffer fix: here? */ - Zmulx= ((float) R.rectx)/2.0; - Zmuly= ((float) R.recty)/2.0; - - - /* use these buffer fill functions */ - zbuffunc = zBufferFillFace; - zbuflinefunc = zBufferFillEdge; - - /* (FORALL y: Aminy =< y =< Amaxy: y is buffered) */ - if( (y < Aminy) || (y > Amaxy)) { - - /* prepare buffer */ - part = (y/RE_ZBUFLEN); /* These two lines are mystifying me... */ - Aminy = part * RE_ZBUFLEN; /* Possibly for rounding things? */ - Amaxy = Aminy + RE_ZBUFLEN - 1; - /* if(Amaxy >= R.recty) Amaxy = R.recty-1; */ - if(Amaxy >= R.recty) Amaxy = R.recty - 1; - resetZbuffer(); - - Zsample = 0; /* Zsample is used internally ! */ - while ( (Zsample < osaNr) && keepLooping ) { - /* Apply jitter to this pixel. The jitter offsets are globals. */ - /* They are added in zbufclip() */ - /* Negative: these offsets are added to the vertex coordinates */ - /* so it equals translating viewpoint over the positive vector. */ - Zjitx= -jit[Zsample][0]-0.5; - Zjity= -jit[Zsample][1]-0.5; - - keepLooping = fillZBufDistances(); - - if(RE_local_test_break()) keepLooping = 0; - Zsample++; - } - } - -} - - -/* ------------------------------------------------------------------------- */ - -struct renderline { - RE_COLBUFTYPE *buf1, *buf2, *buf3; - int y; -}; - -static int do_renderline(void *poin) -{ - struct renderline *rl= poin; - - renderZBufLine(rl->y, rl->buf1, rl->buf2, rl->buf3); - return 1; -} - -void zBufShadeAdvanced() -{ - RE_COLBUFTYPE *cycle; - struct renderline rl1, rl2; - int y, keepLooping = 1; - float xjit = 0.0, yjit = 0.0; - - Zjitx=Zjity= -0.5; /* jitter preset: -0.5 pixel */ - - /* Set osaNr. Treat 'no osa' as 'osa = 1' */ - if(R.r.mode & R_OSA) { - osaNr = R.osa; - if(osaNr > 16) { /* check was moved from calcZBufLine */ - printf("zBufShadeAdvanced> osa too large (internal error)\n"); - G.afbreek= 1; - return; - } - } else { - /* little hack */ - osaNr = 1; - xjit = jit[0][0]; - yjit = jit[0][1]; - jit[0][0] = 0.0; - jit[0][1] = 0.0; - } - - RE_setwindowclip(0, -1); /* just to be sure, reset the view matrix */ - - initRenderBuffers(R.rectx); - - y = 0; - while ( (y < R.recty) && keepLooping) { - - calcZBufLine(y); - - rl1.buf1= AColourBuffer1; - rl1.buf2= AColourBuffer2; - rl1.buf3= AColourBuffer3; - rl1.y= y; - - if(R.r.mode & R_THREADS) { - if((y & 1)==0) { - SDL_Thread *thread; - - thread = SDL_CreateThread(do_renderline, &rl1); - if ( thread == NULL ) { - fprintf(stderr, "Unable to create thread"); - G.afbreek= 1; - break; - } - - rl2.buf1= AColourBuffer0; - rl2.buf2= AColourBuffer1a; - rl2.buf3= AColourBuffer2a; - rl2.y= y+1; - - do_renderline(&rl2); - - SDL_WaitThread(thread, NULL); - - if(R.r.filtertype) { - float *rb1= AColourBuffer1, *rb2= AColourBuffer2, *rb1a= AColourBuffer1a, *rb2a= AColourBuffer2a; - int a= 4*(R.rectx + 4); - while(a--) { - *rb1 += *rb1a; - *rb2 += *rb2a; - *(rb1a++)= 0.0; rb1++; - *(rb2a++)= 0.0; rb2++; - } - } - else { - cycle= AColourBuffer1a; AColourBuffer1a= AColourBuffer1; AColourBuffer1= cycle; - } - } - } - else do_renderline(&rl1); - - if(y) { - transferColourBufferToOutput(AColourBuffer3+4, y-1); - - if((y & 1)==0) RE_local_render_display(y-2, y-1, R.rectx, R.recty, R.rectot); - } - - /* buffer cycling */ - eraseColBuf(AColourBuffer3); - cycle= AColourBuffer3; - AColourBuffer3= AColourBuffer2; - AColourBuffer2= AColourBuffer1; - AColourBuffer1= AColourBuffer0; - AColourBuffer0= cycle; - - if(RE_local_test_break()) keepLooping = 0; - y++; - } - if(keepLooping) transferColourBufferToOutput(AColourBuffer3+4, y-1); - - freeRenderBuffers(); - - /* Edge rendering is done purely as a post-effect */ - if(R.r.mode & R_EDGE) { - addEdges((char*)R.rectot, R.rectx, R.recty, - osaNr, - R.r.edgeint, R.r.same_mat_redux, - G.compat, G.notonlysolid, - R.r.edgeR, R.r.edgeG, R.r.edgeB); - } - - if (!(R.r.mode & R_OSA)) { - jit[0][0] = xjit; - jit[0][1] = yjit; - } - -} - -/* ------------------------------------------------------------------------- */ - - - - -/* eof vanillaRenderPipe.c */ diff --git a/source/blender/render/intern/source/zblur.c b/source/blender/render/intern/source/zblur.c deleted file mode 100644 index a1e8304ba75..00000000000 --- a/source/blender/render/intern/source/zblur.c +++ /dev/null @@ -1,818 +0,0 @@ -/** - * $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. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** - */ - -/* - * This file is largely based on the focal blur plugin by onk, 8.99 - * - */ - -#include <math.h> -#include <string.h> -#include <limits.h> -#include <stdio.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_camera_types.h" -#include "DNA_scene_types.h" - -#include "BKE_global.h" -#include "BKE_utildefines.h" - -#include "RE_callbacks.h" - -#include "render.h" -#include "pixelblending.h" - -#include "blendef.h" -#include "zblur.h" - -//#include "BIF_gl.h" - -/* ------------------------------------------------- - * defines, protos */ - -typedef enum { I_GRAY, I_FLOAT, I_FLOAT4 } IMGTYPE; - -typedef struct { - int x, y; - int size, el_size; - IMGTYPE type; - char *data; -} Image; - -typedef struct { /* blur mask struct */ - int size; - float fac; - float *val; -} Mask; - -typedef Mask* Maskarray; - -/* don't change these */ -#define NMASKS_SHIFT 2 -#define NMASKS 64 - - -static Image *alloc_img(int x, int y, IMGTYPE type) -{ - Image *ret; - int size, typesize; - - switch (type) { - case I_GRAY: - typesize = 1; - break; - case I_FLOAT: - typesize = sizeof(float); - break; - case I_FLOAT4: - typesize = 4 * sizeof(float); - break; - default: - return 0; - } - - size = x * y; - - ret = (Image *) MEM_mallocN(sizeof(Image) + size*typesize, "zblur_img"); - if (ret) { - ret->x = x; - ret->y = y; - ret->size = size; - ret->el_size = typesize; - ret->type = type; - ret->data = (char *) (ret + 1); - size *= typesize; - memset(ret->data, 0, size); - } - - return ret; -} - -static int free_img(Image *img) -{ - MEM_freeN(img); - return 1; -} - -/* 32 bits (int) rect to float buf */ -static void recti2imgf(unsigned int *src, Image *dest, int x, int y) -{ - char *from; - float *to; - int i, ix, iy; - - if(dest->type != I_FLOAT4) return; - - from = (char *) src; - to = (float *) dest->data; - - if (R.r.mode & R_FIELDS) { /* double each scanline */ - for (iy=0; iy<y; iy++) { - for (ix=0; ix<x; ix++) { - *to++ = ((float)from[0])/255.0; - *to++ = ((float)from[1])/255.0; - *to++ = ((float)from[2])/255.0; - *to++ = ((float)from[3])/255.0; - from += 4; - } - - memcpy(to, to-4*sizeof(float)*x, 4*sizeof(float)*x); - to+= 4*x; - - iy++; - } - } - else { - i = x * y; - while(i--) { - *to++ = ((float)from[0])/255.0; - *to++ = ((float)from[1])/255.0; - *to++ = ((float)from[2])/255.0; - *to++ = ((float)from[3])/255.0; - from += 4; - } - } -} - -/* float rect to float buf */ -static void rectf2imgf(float *src, Image *dest, int x, int y) -{ - float *from; - float *to; - int i, iy; - - if(dest->type != I_FLOAT4) return; - - from = src; - to = (float *) dest->data; - - if (R.r.mode & R_FIELDS) { /* double each scanline */ - for (iy=0; iy<y; iy++) { - - memcpy(to, from, 4*sizeof(float)*x); - to+= 4*x; - memcpy(to, from, 4*sizeof(float)*x); - to+= 4*x; - - iy++; - from += 4*x; - } - } - else { - i = y; - while(i--) { - memcpy(to, from, 4*sizeof(float)*x); - from += 4*x; - to += 4*x; - } - } -} - -/* floatbuf back to 32 bits rect */ -static void imgf2recti(Image *src, unsigned int *dest) -{ - float *from; - char *to; - int i, ix, iy; - - if(src->type != I_FLOAT4) return; - - from = (float *) src->data; - to = (char *) dest; - - if (R.r.mode & R_FIELDS) { - for (iy=0; iy<src->y; iy++) { - for (ix=0; ix<src->x; ix++) { - *to++ = (char)(from[0]*255.0); - *to++ = (char)(from[1]*255.0); - *to++ = (char)(from[2]*255.0); - *to++ = (char)(from[3]*255.0); - from += 4; - } - iy++; - from+= 4*src->x; - } - } - else { - i = src->x * src->y; - while(i--) { - *to++ = (char)(from[0]*255.0); - *to++ = (char)(from[1]*255.0); - *to++ = (char)(from[2]*255.0); - *to++ = (char)(from[3]*255.0); - from += 4; - } - } -} - -/* floatbuf back to float rect */ -static void imgf2rectf(Image *src, float *dest) -{ - float *from; - float *to; - int i, iy; - - if(src->type != I_FLOAT4) return; - - from = (float *) src->data; - to = dest; - - if (R.r.mode & R_FIELDS) { - for (iy=0; iy<src->y; iy++) { - - memcpy(to, from, 4*sizeof(float)*src->x); - - iy++; - to+= 4*src->x; - from+= 8*src->x; - } - } - else { - i = src->x * src->y; - memcpy(to, from, 4*sizeof(float)*i); - } -} - - -static void imgf_gamma(Image *src, float gamma) -{ - float *to; - int i; - - if(gamma==1.0) return; - - i = 4 * src->x * src->y; - to= (float *) src->data; - while(i--) { - *to = (float)pow(*to, gamma); - to++; - } -} - -#if 0 -/* create new image with alpha & color zero where mask is zero */ -static Image *imgf_apply_mask(Image *src, Image *zmask) -{ - Image *dest; - float *from, *to; - int i; - char *zptr; - - dest = alloc_img(src->x, src->y, I_FLOAT4); - - i= src->x * src->y; - from= (float *) src->data; - to= (float *) dest->data; - zptr= (char *)zmask->data; - - while(i--) { - if(*zptr) { - to[0]= from[0]; - to[1]= from[1]; - to[2]= from[2]; - to[3]= from[3]; - } - else { - to[0]= to[1]= to[2]= to[3]= 0.0f; - } - zptr++; - to+= 4; - from+= 4; - } - - return dest; -} - -static void imgf_alpha_over(Image *dest, Image *src) -{ - float *from, *to; - int i; - - i= src->x * src->y; - from= (float *) src->data; - to= (float *) dest->data; - - while(i--) { - addAlphaOverFloat(to, from); - to+= 4; - from+= 4; - } -} - -#endif - -/* --------------------------------------------------------------------- */ -/* mask routines */ - -static Mask *alloc_mask(int size) -{ - Mask *m; - int memsize; - - memsize = (sizeof(Mask) + (2 * size +1) * (2 * size +1) * sizeof(float)); - - m = (Mask*) MEM_mallocN(memsize, "zblur_mask"); - m->size = size; - m->val = (float *) (m + 1); - - return m; -} - -static void free_mask(Mask *m) -{ - int memsize; - - memsize = 2 * m->size + 1; - memsize *= memsize * sizeof(float); - memsize += sizeof(Mask); - - MEM_freeN(m); -} - -/* normalize mask to 1 */ - -static void norm_mask(Mask *m) -{ - float fac; - int size; - float *v; - - fac = m->fac; - size = (2 * m->size +1)*(2 * m->size +1); - - v = m->val; - while(size--) { - *v++ *= fac; - } - m->fac = 1.0; -} - -/* filters a grayvalue image with a gaussian IIR filter with blur radius "rad" - * For large blurs, it's more efficient to call the routine several times - * instead of using big blur radii. - * The original image is changed */ - - -static void gauss_blur(Image *img, float rad) -{ - Image *new; - register float sum, val; - float gval; - float *gausstab, *v; - int r, n, m; - int x, y; - int i; - int step, bigstep; - char *src, *dest; - - r = (1.5 * rad + 1.5); - n = 2 * r + 1; - - /* ugly : */ - if ((img->x <= n) || (img->y <= n)) { - return; - } - - gausstab = (float *) MEM_mallocN(n * sizeof(float), "zblur_gauss"); - if (!gausstab) { - return; - } - - sum = 0.0; - v = gausstab; - for (x = -r; x <= r; x++) { - - val = exp(-4*(float ) (x*x)/ (float) (r*r)); - sum += val; - *v++ = val; - } - - i = n; - v = gausstab; - while (i--) { - *v++ /= sum; - } - - new = alloc_img(img->x, img->y, I_GRAY); - if (!new) { - return; - } - - /* horizontal */ - - step = (n - 1); - - for (y = 0; y < img->y; y++) { - src = (char *)img->data + (y * img->x); - dest = (char *)new->data + (y * img->x); - - for (x = r; x > 0 ; x--) { - m = n - x; - gval = 0.0; - sum = 0.0; - v = gausstab + x; - for (i = 0; i < m; i++) { - val = *v++; - sum += val; - gval += val * (*src++); - } - *dest++ = gval / sum; - src -= m; - } - - for (x = 0; x <= (img->x - n); x++) { - gval = 0.0; - v = gausstab; - - for (i = 0; i < n; i++) { - val = *v++; - gval += val * (*src++); - } - *dest++ = gval; - src -= step; - } - - for (x = 1; x <= r ; x++) { - m = n - x; - gval = 0.0; - sum = 0.0; - v = gausstab; - for (i = 0; i < m; i++) { - val = *v++; - sum += val; - gval += val * (*src++); - } - *dest++ = gval / sum; - src -= (m - 1); - } - } - - /* vertical */ - - step = img->x; - bigstep = (n - 1) * step; - for (x = 0; x < step ; x++) { - src = new->data + x; - dest = img->data + x; - - for (y = r; y > 0; y--) { - m = n - y; - gval = 0.0; - sum = 0.0; - v = gausstab + y; - for (i = 0; i < m; i++) { - val = *v++; - sum += val; - gval += val * src[0]; - src += step; - } - dest[0] = gval / sum; - src -= m * step; - dest+= step; - } - for (y = 0; y <= (img->y - n); y++) { - gval = 0.0; - v = gausstab; - for (i = 0; i < n; i++) { - val = *v++; - gval += val * src[0]; - src += step; - } - dest[0] = gval; - dest += step; - src -= bigstep; - } - for (y = 1; y <= r ; y++) { - m = n - y; - gval = 0.0; - sum = 0.0; - v = gausstab; - for (i = 0; i < m; i++) { - val = *v++; - sum += val; - gval += val * src[0]; - src += step; - } - dest[0] = gval / sum; - dest += step; - src -= (m - 1) * step; - } - } - MEM_freeN(gausstab); - free_img(new); -} - -static float zigma(float x, float sigma, float sigma4) -{ - //return 1.0/(1.0+pow(x, sigma)); - - if(x < sigma) { - x*= sigma; - return 1.0/exp(x*x) - sigma4; - } - return 0.0; -} - - -static Mask *gauss_mask(float rad, float sigma) -{ - Mask *m; - float sum, val, *v, fac, radsq= rad*rad; - float sigma4; - int r; - int ix, iy; - - r = (1.0 * rad + 1.0); - m = alloc_mask(r); - v = m->val; - sum = 0.0; - - sigma4= 1.0/exp(sigma*sigma*sigma*sigma); - - for (iy = -r; iy <= r; iy++) { - for (ix = -r; ix <= r; ix++) { - - fac= ((float)(ix*ix + iy*iy))/(radsq); - val = zigma(fac, sigma, sigma4); - - // val = exp(-(float) (ix*ix + iy*iy)/(rad * rad)); - sum += val; - *v++ = val; - } - } - - m->fac = 1.0 / sum; - - norm_mask(m); - return m; -} - -/* generates #num masks with the maximal blur radius 'rad' - * */ -static Maskarray *init_masks(int num, float rad, float sigma) -{ - int i; - float r, step; - Maskarray *maskarray; - - maskarray = (Maskarray*) MEM_mallocN(num * sizeof (Maskarray), "zblur_masks"); - step = rad / num; - r = 0.1; - for (i = 0; i < num; i++) { - maskarray[i] = gauss_mask(r, sigma); - r += step; - } - return maskarray; -} - - -/* ********************* Do the blur ******************************** */ - -static Image *zblur(Image *src, Image *zbuf, float radius, float sigma) -{ - Image *dest; - Maskarray *mar; - Mask *m; - float *sptr, *dptr; - float *mval; /* mask value pointer */ - float rval, gval, bval, aval; - float norm, fac; - int tmp; - int zval; - int size; - int row; - int mrow; - int x, y; - int i; - int sx, sy, ex, ey; - int mx, my; - char *zptr; - - if(src->type != I_FLOAT4) return NULL; - - dest = alloc_img(src->x, src->y, I_FLOAT4); - row = src->x * 4; - - mar = init_masks(NMASKS, radius, sigma); - - for (y = 0; y < src->y ; y++) { - for (x = 0; x < src->x; x++) { - dptr = (float *) (dest->data + ((y * src->x + x) * src->el_size)); - zptr = zbuf->data + (y * src->x + x); - zval = *zptr; - sptr = (float *) (src->data + ((y *src->x + x )* src->el_size)); - - m = mar[zval >> NMASKS_SHIFT]; - - size = m->size; - - if(size==0 || zval==0) { - dptr[0] = sptr[0]; - dptr[1] = sptr[1]; - dptr[2] = sptr[2]; - dptr[3] = sptr[3]; - continue; - } - - ex = src->x - x; - ey = src->y - y; - - sx = (x < size) ? x : size; - sy = (y < size) ? y : size; - ex = (ex <= size) ? ex - 1: size; - ey = (ey <= size) ? ey - 1: size; - - sptr -= sy *src->x * 4; - zptr -= sy * src->x; - mrow = (size << 1) + 1; - mval = m->val + (size - sy) * mrow + size; - - norm = rval = gval = bval = aval= 0.0; - - for (my = -sy; my <= ey; my++) { - for (mx = -sx; mx <= ex; mx++) { - if( zptr[mx] ) { - tmp = 4 * mx; - fac = mval[mx] * (float) zptr[mx] /255.0 ; - - norm += fac; - rval += fac * sptr[tmp]; - gval += fac * sptr[tmp + 1]; - bval += fac * sptr[tmp + 2]; - aval += fac * sptr[tmp + 3]; - } - } - mval += mrow; - sptr += row; - zptr += src->x; - } - - dptr[0] = rval / norm; - dptr[1] = gval / norm; - dptr[2] = bval / norm; - dptr[3] = aval / norm; - } - if(!(y % 4) && RE_local_test_break()) break; - } - - for (i= 0; i < NMASKS; i++) { - free_mask(mar[i]); - } - - MEM_freeN(mar); - - return dest; -} - - -/* this splits the z-buffer into 2 gray-images (background, foreground) -* which are used for the weighted blur */ - -static void zsplit(int *zptr, Image *fg, Image *bg, int zfocus, int zmax, int zmin, int x, int y) -{ - char *p, *q; - int i, ix, iy; - float fdist; - float fgnorm, bgnorm; - - p = fg->data; - q = bg->data; - bgnorm = 255.0 / ((float) zmax - (float) zfocus); - fgnorm = 255.0 / ((float) zfocus - (float) zmin); - - if (R.r.mode & R_FIELDS) { - for (iy=0; iy<y; iy++) { - for (ix=0; ix<x; ix++) { - fdist = (float) (*zptr++); - if (fdist < zmin) fdist = zmin; - - fdist -= zfocus; - - if (fdist < 0) { - *p = (char) (-fdist * fgnorm); - *q = 0; - } - else { - *q = (char) (fdist * bgnorm); - *p = 0; - } - p++, q++; - } - iy++; - p+= x; - q+= x; - } - } - else { - i = x * y; - while(i--) { - fdist = (float) (*zptr++); - if (fdist < zmin) fdist = zmin; - - fdist -= zfocus; - - if (fdist < 0) { - *p = (char) (-fdist * fgnorm); - *q = 0; - } - else { - *q = (char) (fdist * bgnorm); - *p = 0; - } - p++, q++; - } - } -} - -void add_zblur(void) -{ - Image *orig, *zfront, *work, *zback; - float zblurr; - int zfocus; - int x, y, zmin; - - if (R.rectz == NULL) return; - - x= R.rectx; - y= R.recty; - - zblurr= (R.r.zblur*R.r.size)/100; - - if (R.r.mode & R_FIELDS) { - y *= 2; - zblurr *= 2; - } - - zmin= INT_MAX*( 2.0*R.r.zmin - 1.0); // R.r.zmin ranges 0 - 1 - zfocus = INT_MAX*( 2.0*R.r.focus - 1.0); - - if(zmin>zfocus) zmin= zfocus; - - zfront = alloc_img(x, y, I_GRAY); - zback = alloc_img(x, y, I_GRAY); - orig = alloc_img(x, y, I_FLOAT4); - - if(R.rectftot) rectf2imgf(R.rectftot, orig, x, y); - else recti2imgf(R.rectot, orig, x, y); - - imgf_gamma(orig, R.r.zgamma); // pregamma correct if required - - - /* split up z buffer into 2 gray images */ - zsplit(R.rectz, zfront, zback, zfocus, INT_MAX, zmin, x, y); - -// glDrawBuffer(GL_FRONT); -// glRasterPos2i(0, 0); -// glDrawPixels(x, y, GL_RED, GL_UNSIGNED_BYTE, zback->data); -// glFlush(); -// glDrawBuffer(GL_BACK); - - gauss_blur(zback, 1.0); - gauss_blur(zfront, zblurr); - - /* blur back part */ - work = zblur(orig, zback, zblurr, R.r.zsigma); - free_img(orig); - - /* blur front part */ - orig = zblur(work, zfront, zblurr, R.r.zsigma); - - imgf_gamma(orig, 1.0/R.r.zgamma); // pregamma correct if required - - if(R.rectftot) imgf2rectf(orig, R.rectftot); - else imgf2recti(orig, R.rectot); - - free_img(work); - free_img(orig); - free_img(zfront); - free_img(zback); - - /* make new display rect */ - if(R.rectftot) RE_floatbuffer_to_output(); -} - - diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 368acfe1a41..7790a4cff65 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL 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. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,21 +20,24 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. + * Contributors: Hos, RPW + * 2004-2006 Blender Foundation, full recode * - * Contributor(s): Hos, RPW. - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ + /*---------------------------------------------------------------------------*/ /* Common includes */ /*---------------------------------------------------------------------------*/ #include <math.h> +#include <float.h> #include <stdlib.h> #include <limits.h> #include <string.h> + +#include "BLI_blenlib.h" #include "MTC_matrixops.h" #include "MEM_guardedalloc.h" @@ -49,75 +49,57 @@ #include "BKE_utildefines.h" #include "radio_types.h" -#include "radio.h" /* needs RG, some root data for radiosity */ +#include "radio.h" /* needs RG, some root data for radiosity */ #include "SDL_thread.h" -#include "render.h" -#include "RE_callbacks.h" +#include "RE_render_ext.h" /* local includes */ -#include "rendercore.h" /* shade_pixel and count_mask */ +#include "render_types.h" +#include "renderpipeline.h" +#include "renderdatabase.h" +#include "rendercore.h" #include "pixelblending.h" -#include "jitter.h" /* own includes */ #include "zbuf.h" -#define FLT_EPSILON 1.19209290e-07F +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/*-----------------------------------------------------------*/ -/* Globals for this file */ -/* main reason for globals; unified zbuffunc() with simple args */ -/*-----------------------------------------------------------*/ - -float Zmulx; /* Half the screenwidth, in pixels. (used in render.c, */ - /* zbuf.c) */ -float Zmuly; /* Half the screenheight, in pixels. (used in render.c,*/ - /* zbuf.c) */ -float Zjitx; /* Jitter offset in x. When jitter is disabled, this */ - /* should be 0.5. (used in render.c, zbuf.c) */ -float Zjity; /* Jitter offset in y. When jitter is disabled, this */ - /* should be 0.5. (used in render.c, zbuf.c) */ - -int Zsample; -void (*zbuffunc)(ZSpan *, int, float *, float *, float *); -void (*zbuffunc4)(ZSpan *, int, float *, float *, float *, float *); -void (*zbuflinefunc)(int, float *, float *); - -static APixstr *APixbuf; /* Zbuffer: linked list of face indices */ -static int *Arectz; /* Zbuffer: distance buffer, almost obsolete */ -static int Aminy; /* y value of first line in the accu buffer */ -static int Amaxy; /* y value of last line in the accu buffer */ -static int Azvoordeel = 0; -static APixstrMain apsmfirst; -static short apsmteller = 0; /* ****************** Spans ******************************* */ -static void zbuf_alloc_span(ZSpan *zspan, int yres) +/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */ +void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty) { - zspan->yres= yres; + memset(zspan, 0, sizeof(ZSpan)); + + zspan->rectx= rectx; + zspan->recty= recty; - zspan->span1= MEM_callocN(yres*sizeof(float), "zspan"); - zspan->span2= MEM_callocN(yres*sizeof(float), "zspan"); + zspan->span1= RE_mallocN(recty*sizeof(float), "zspan"); + zspan->span2= RE_mallocN(recty*sizeof(float), "zspan"); } static void zbuf_free_span(ZSpan *zspan) { if(zspan) { - if(zspan->span1) MEM_freeN(zspan->span1); - if(zspan->span2) MEM_freeN(zspan->span2); + if(zspan->span1) RE_freeN(zspan->span1); + if(zspan->span2) RE_freeN(zspan->span2); zspan->span1= zspan->span2= NULL; } } -static void zbuf_init_span(ZSpan *zspan, int miny, int maxy) +/* reset range for clipping */ +static void zbuf_init_span(ZSpan *zspan) { - zspan->miny= miny; /* range for clipping */ - zspan->maxy= maxy; - zspan->miny1= zspan->miny2= maxy+1; - zspan->maxy1= zspan->maxy2= miny-1; + zspan->miny1= zspan->miny2= zspan->recty+1; + zspan->maxy1= zspan->maxy2= -1; zspan->minp1= zspan->maxp1= zspan->minp2= zspan->maxp2= NULL; } @@ -137,12 +119,12 @@ static void zbuf_add_to_span(ZSpan *zspan, float *v1, float *v2) my0= ceil(minv[1]); my2= floor(maxv[1]); - if(my2<zspan->miny || my0> zspan->maxy) return; + if(my2<0 || my0>= zspan->recty) return; /* clip top */ - if(my2>=zspan->maxy) my2= zspan->maxy-1; + if(my2>=zspan->recty) my2= zspan->recty-1; /* clip bottom */ - if(my0<zspan->miny) my0= zspan->miny; + if(my0<0) my0= 0; if(my0>my2) return; /* if(my0>my2) should still fill in, that way we get spans that skip nicely */ @@ -217,16 +199,7 @@ void fillrect(int *rect, int x, int y, int val) } } -/** -* Tests whether this coordinate is 'inside' or 'outside' of the view - * volume? By definition, this is in [0, 1]. - * @param p vertex z difference plus coordinate difference? - * @param q origin z plus r minus some coordinate? - * @param u1 [in/out] clip fraction for ? - * @param u2 [in/out] - * @return 0 if point is outside, or 1 if the point lies on the clip - * boundary - */ +/* based on Liang&Barsky, for clipping of pyramidical volume */ static short cliptestf(float p, float q, float *u1, float *u2) { float r; @@ -253,7 +226,7 @@ static short cliptestf(float p, float q, float *u1, float *u2) return 1; } -int RE_testclip(float *v) +int testclip(float *v) { float abs4; /* WATCH IT: this function should do the same as cliptestf, otherwise troubles in zbufclip()*/ short c=0; @@ -278,315 +251,42 @@ int RE_testclip(float *v) /* ************* ACCUMULATION ZBUF ************ */ -/*-APixstr---------------------(antialised pixel struct)------------------------------*/ -static APixstr *addpsmainA() +static APixstr *addpsmainA(ListBase *lb) { APixstrMain *psm; - psm= &apsmfirst; - - while(psm->next) { - psm= psm->next; - } - - psm->next= MEM_mallocN(sizeof(APixstrMain), "addpsmainA"); - - psm= psm->next; - psm->next=0; - psm->ps= MEM_callocN(4096*sizeof(APixstr),"pixstr"); - apsmteller= 0; + psm= RE_mallocN(sizeof(APixstrMain), "addpsmainA"); + BLI_addtail(lb, psm); + psm->ps= RE_mallocN(4096*sizeof(APixstr),"pixstr"); return psm->ps; } -static void freepsA() +static void freepsA(ListBase *lb) { - APixstrMain *psm, *next; - - psm= &apsmfirst; + APixstrMain *psm, *psmnext; - while(psm) { - next= psm->next; - if(psm->ps) { - MEM_freeN(psm->ps); - psm->ps= 0; - } - if(psm!= &apsmfirst) MEM_freeN(psm); - psm= next; + for(psm= lb->first; psm; psm= psmnext) { + psmnext= psm->next; + if(psm->ps) + RE_freeN(psm->ps); + RE_freeN(psm); } - - apsmfirst.next= 0; - apsmfirst.ps= 0; - apsmteller= 0; -} - -static APixstr *addpsA(void) -{ - static APixstr *prev; - - /* make first PS */ - if((apsmteller & 4095)==0) prev= addpsmainA(); - else prev++; - apsmteller++; - - return prev; } -/** - * Fill the z buffer for accumulation (transparency) - * - * This is one of the z buffer fill functions called in zbufclip() and - * zbufwireclip(). - * - * @param v1 [4 floats, world coordinates] first vertex - * @param v2 [4 floats, world coordinates] second vertex - * @param v3 [4 floats, world coordinates] third vertex - */ -static void zbufinvulAc(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) +static APixstr *addpsA(ZSpan *zspan) { - APixstr *ap, *apofs, *apn; - double x0,y0,z0,x1,y1,z1,x2,y2,z2,xx1; - double zxd,zyd,zy0, tmp; - float *minv,*maxv,*midv; - int *rz,zverg,x; - int my0,my2,sn1,sn2,rectx,zd,*rectzofs; - int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2, mask; - - /* MIN MAX */ - if(v1[1]<v2[1]) { - if(v2[1]<v3[1]) { - minv=v1; midv=v2; maxv=v3; - } - else if(v1[1]<v3[1]) { - minv=v1; midv=v3; maxv=v2; - } - else { - minv=v3; midv=v1; maxv=v2; - } - } - else { - if(v1[1]<v3[1]) { - minv=v2; midv=v1; maxv=v3; - } - else if(v2[1]<v3[1]) { - minv=v2; midv=v3; maxv=v1; - } - else { - minv=v3; midv=v2; maxv=v1; - } - } - - if(minv[1] == maxv[1]) return; /* prevent 'zero' size faces */ - - my0= ceil(minv[1]); - my2= floor(maxv[1]); - omsl= floor(midv[1]); - - if(my2<Aminy || my0> Amaxy) return; - - if(my0<Aminy) my0= Aminy; - - /* EDGES : LONGEST */ - xx1= maxv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx0= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-minv[1])+minv[0]); - xs0= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx0= 0; - xs0= 65536.0*(MIN2(minv[0],maxv[0])); - } - /* EDGES : THE TOP ONE */ - xx1= maxv[1]-midv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-midv[0])/xx1; - - tmp= (-65536.0*z0); - dx1= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-midv[1])+midv[0]); - xs1= CLAMPIS(tmp, INT_MIN, INT_MAX); + /* make new PS */ + if(zspan->apsmcounter==0) { + zspan->curpstr= addpsmainA(zspan->apsmbase); + zspan->apsmcounter= 4095; } else { - dx1= 0; - xs1= 65536.0*(MIN2(midv[0],maxv[0])); - } - /* EDGES : BOTTOM ONE */ - xx1= midv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (midv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx2= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]); - xs2= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx2= 0; - xs2= 65536.0*(MIN2(minv[0],midv[0])); - } - - /* ZBUF DX DY */ - x1= v1[0]- v2[0]; - x2= v2[0]- v3[0]; - y1= v1[1]- v2[1]; - y2= v2[1]- v3[1]; - z1= v1[2]- v2[2]; - z2= v2[2]- v3[2]; - x0= y1*z2-z1*y2; - y0= z1*x2-x1*z2; - z0= x1*y2-y1*x2; - if(z0==0.0) return; - - if(midv[1]==maxv[1]) omsl= my2; - if(omsl<Aminy) omsl= Aminy-1; /* to make sure it does the first loop completely */ - - while (my2 > Amaxy) { /* my2 can be larger */ - xs0+=dx0; - if (my2<=omsl) { - xs2+= dx2; - } - else{ - xs1+= dx1; - } - my2--; - } - - xx1= (x0*v1[0]+y0*v1[1])/z0+v1[2]; - - zxd= -x0/z0; - zyd= -y0/z0; - zy0= my2*zyd+xx1; - zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX); - - /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(Arectz+rectx*(my2-Aminy)); - apofs= (APixbuf+ rectx*(my2-Aminy)); - mask= 1<<Zsample; - - xs3= 0; /* flag */ - if(dx0>dx1) { - xs3= xs0; - xs0= xs1; - xs1= xs3; - xs3= dx0; - dx0= dx1; - dx1= xs3; - xs3= 1; /* flag */ - - } - - for(y=my2;y>omsl;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs1>>16; - xs1+= dx1; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - ap= apofs+sn1; - x= sn2-sn1; - - zverg-= Azvoordeel; - - while(x>=0) { - if(zverg< *rz) { - apn= ap; - while(apn) { /* loop unrolled */ - if(apn->p[0]==0) {apn->p[0]= zvlnr; apn->z[0]= zverg; apn->mask[0]= mask; break; } - if(apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; } - if(apn->p[1]==0) {apn->p[1]= zvlnr; apn->z[1]= zverg; apn->mask[1]= mask; break; } - if(apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; } - if(apn->p[2]==0) {apn->p[2]= zvlnr; apn->z[2]= zverg; apn->mask[2]= mask; break; } - if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; } - if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= zverg; apn->mask[3]= mask; break; } - if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; } - if(apn->next==0) apn->next= addpsA(); - apn= apn->next; - } - } - zverg+= zd; - rz++; - ap++; - x--; - } - zy0-= zyd; - rectzofs-= rectx; - apofs-= rectx; - } - - if(xs3) { - xs0= xs1; - dx0= dx1; - } - if(xs0>xs2) { - xs3= xs0; - xs0= xs2; - xs2= xs3; - xs3= dx0; - dx0= dx2; - dx2= xs3; - } - - for(; y>=my0; y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs2>>16; - xs2+= dx2; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - ap= apofs+sn1; - x= sn2-sn1; - - zverg-= Azvoordeel; - - while(x>=0) { - if(zverg< *rz) { - apn= ap; - while(apn) { /* loop unrolled */ - if(apn->p[0]==0) {apn->p[0]= zvlnr; apn->z[0]= zverg; apn->mask[0]= mask; break; } - if(apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; } - if(apn->p[1]==0) {apn->p[1]= zvlnr; apn->z[1]= zverg; apn->mask[1]= mask; break; } - if(apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; } - if(apn->p[2]==0) {apn->p[2]= zvlnr; apn->z[2]= zverg; apn->mask[2]= mask; break; } - if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; } - if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= zverg; apn->mask[3]= mask; break; } - if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; } - if(apn->next==0) apn->next= addpsA(); - apn= apn->next; - } - } - zverg+= zd; - rz++; - ap++; - x--; - } - - zy0-=zyd; - rectzofs-= rectx; - apofs-= rectx; + zspan->curpstr++; + zspan->apsmcounter--; } + return zspan->curpstr; } static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) @@ -600,13 +300,17 @@ static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v int sn1, sn2, rectx, *rectzofs, my0, my2, mask; /* init */ - zbuf_init_span(zspan, Aminy, Amaxy+1); + zbuf_init_span(zspan); /* set spans */ zbuf_add_to_span(zspan, v1, v2); zbuf_add_to_span(zspan, v2, v3); - zbuf_add_to_span(zspan, v3, v4); - zbuf_add_to_span(zspan, v4, v1); + if(v4) { + zbuf_add_to_span(zspan, v3, v4); + zbuf_add_to_span(zspan, v4, v1); + } + else + zbuf_add_to_span(zspan, v3, v1); /* clipped */ if(zspan->minp2==NULL || zspan->maxp2==NULL) return; @@ -636,11 +340,11 @@ static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v zy0= ((double)my2)*zyd + (double)xx1; /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(Arectz+rectx*(my2-Aminy)); - apofs= (APixbuf+ rectx*(my2-Aminy)); - mask= 1<<Zsample; - + rectx= zspan->rectx; + rectzofs= (int *)(zspan->arectz+rectx*(my2)); + apofs= (zspan->apixbuf+ rectx*(my2)); + mask= zspan->mask; + /* correct span */ sn1= (my0 + my2)/2; if(zspan->span1[sn1] < zspan->span2[sn1]) { @@ -667,7 +371,7 @@ static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v ap= apofs+sn1; x= sn2-sn1; - zverg-= Azvoordeel; + zverg-= zspan->polygon_offset; while(x>=0) { if( (int)zverg < *rz) { @@ -685,7 +389,7 @@ static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; } // if(apn->p[i]==0) {apn->p[i]= zvlnr; apn->z[i]= zverg; apn->mask[i]= mask; break; } // if(apn->p[i]==zvlnr) {apn->mask[i]|= mask; break; } - if(apn->next==NULL) apn->next= addpsA(); + if(apn->next==NULL) apn->next= addpsA(zspan); apn= apn->next; } } @@ -704,7 +408,7 @@ static void zbufinvulAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v -static void zbuflineAc(int zvlnr, float *vec1, float *vec2) +static void zbuflineAc(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) { APixstr *ap, *apn; int *rectz; @@ -716,6 +420,8 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) dx= vec2[0]-vec1[0]; dy= vec2[1]-vec1[1]; + mask= zspan->mask; + if(fabs(dx) > fabs(dy)) { /* all lines from left to right */ @@ -731,22 +437,21 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) start= floor(v1[0]); end= start+floor(dx); - if(end>=R.rectx) end= R.rectx-1; + if(end>=zspan->rectx) end= zspan->rectx-1; oldy= floor(v1[1]); dy/= dx; vergz= v1[2]; - vergz-= Azvoordeel; + vergz-= zspan->polygon_offset; dz= (v2[2]-v1[2])/dx; if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= (int *)(Arectz+R.rectx*(oldy-Aminy) +start); - ap= (APixbuf+ R.rectx*(oldy-Aminy) +start); - mask= 1<<Zsample; - - if(dy<0) ofs= -R.rectx; - else ofs= R.rectx; + rectz= (int *)(zspan->arectz+zspan->rectx*(oldy) +start); + ap= (zspan->apixbuf+ zspan->rectx*(oldy) +start); + + if(dy<0) ofs= -zspan->rectx; + else ofs= zspan->rectx; for(x= start; x<=end; x++, rectz++, ap++) { @@ -757,7 +462,7 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) ap+= ofs; } - if(x>=0 && y>=Aminy && y<=Amaxy) { + if(x>=0 && y>=0 && y<zspan->recty) { if(vergz<*rectz) { apn= ap; @@ -770,7 +475,7 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; } if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; } if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; } - if(apn->next==0) apn->next= addpsA(); + if(apn->next==0) apn->next= addpsA(zspan); apn= apn->next; } @@ -798,26 +503,25 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) start= floor(v1[1]); end= start+floor(dy); - if(start>Amaxy || end<Aminy) return; + if(start>=zspan->recty || end<0) return; - if(end>Amaxy) end= Amaxy; + if(end>=zspan->recty) end= zspan->recty-1; oldx= floor(v1[0]); dx/= dy; vergz= v1[2]; - vergz-= Azvoordeel; + vergz-= zspan->polygon_offset; dz= (v2[2]-v1[2])/dy; if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= (int *)( Arectz+ (start-Aminy)*R.rectx+ oldx ); - ap= (APixbuf+ R.rectx*(start-Aminy) +oldx); - mask= 1<<Zsample; + rectz= (int *)( zspan->arectz+ (start)*zspan->rectx+ oldx ); + ap= (zspan->apixbuf+ zspan->rectx*(start) +oldx); if(dx<0) ofs= -1; else ofs= 1; - for(y= start; y<=end; y++, rectz+=R.rectx, ap+=R.rectx) { + for(y= start; y<=end; y++, rectz+=zspan->rectx, ap+=zspan->rectx) { x= floor(v1[0]); if(x!=oldx) { @@ -826,7 +530,7 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) ap+= ofs; } - if(x>=0 && y>=Aminy && x<R.rectx) { + if(x>=0 && y>=0 && x<zspan->rectx) { if(vergz<*rectz) { apn= ap; @@ -839,7 +543,7 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; } if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; } if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; } - if(apn->next==0) apn->next= addpsA(); + if(apn->next==0) apn->next= addpsA(zspan); apn= apn->next; } @@ -853,30 +557,9 @@ static void zbuflineAc(int zvlnr, float *vec1, float *vec2) } } - - /* ************* NORMAL ZBUFFER ************ */ -/** - * Convert a homogenous coordinate to a z buffer coordinate. The - * function makes use of Zmulx, Zmuly, the x and y scale factors for - * the screen, and Zjitx, Zjity, the pixel offset. (These are declared - * in render.c) The normalised z coordinate must fall on [0, 1]. - * @param zco [3, 4 floats] pointer to the resulting z buffer coordinate - * @param hoco [4 floats] pointer to the homogenous coordinate of the - * vertex in world space. - */ -static void hoco_to_zco(float *zco, float *hoco) -{ - float deler; - - deler= hoco[3]; - zco[0]= Zmulx*(1.0+hoco[0]/deler)+ Zjitx; - zco[1]= Zmuly*(1.0+hoco[1]/deler)+ Zjity; - zco[2]= 0x7FFFFFFF *(hoco[2]/deler); -} - -static void zbufline(int zvlnr, float *vec1, float *vec2) +static void zbufline(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) { int *rectz, *rectp; int start, end, x, y, oldx, oldy, ofs; @@ -902,7 +585,7 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) start= floor(v1[0]); end= start+floor(dx); - if(end>=R.rectx) end= R.rectx-1; + if(end>=zspan->rectx) end= zspan->rectx-1; oldy= floor(v1[1]); dy/= dx; @@ -911,11 +594,11 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) dz= floor((v2[2]-v1[2])/dx); if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= R.rectz+ oldy*R.rectx+ start; - rectp= R.rectot+ oldy*R.rectx+ start; + rectz= zspan->rectz + oldy*zspan->rectx+ start; + rectp= zspan->rectp + oldy*zspan->rectx+ start; - if(dy<0) ofs= -R.rectx; - else ofs= R.rectx; + if(dy<0) ofs= -zspan->rectx; + else ofs= zspan->rectx; for(x= start; x<=end; x++, rectz++, rectp++) { @@ -926,7 +609,7 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) rectp+= ofs; } - if(x>=0 && y>=0 && y<R.recty) { + if(x>=0 && y>=0 && y<zspan->recty) { if(vergz<*rectz) { *rectz= vergz; *rectp= zvlnr; @@ -954,7 +637,7 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) start= floor(v1[1]); end= start+floor(dy); - if(end>=R.recty) end= R.recty-1; + if(end>=zspan->recty) end= zspan->recty-1; oldx= floor(v1[0]); dx/= dy; @@ -963,13 +646,13 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) dz= floor((v2[2]-v1[2])/dy); if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= R.rectz+ start*R.rectx+ oldx; - rectp= R.rectot+ start*R.rectx+ oldx; + rectz= zspan->rectz + start*zspan->rectx+ oldx; + rectp= zspan->rectp + start*zspan->rectx+ oldx; if(dx<0) ofs= -1; else ofs= 1; - for(y= start; y<=end; y++, rectz+=R.rectx, rectp+=R.rectx) { + for(y= start; y<=end; y++, rectz+=zspan->rectx, rectp+=zspan->rectx) { x= floor(v1[0]); if(x!=oldx) { @@ -978,7 +661,7 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) rectp+= ofs; } - if(x>=0 && y>=0 && x<R.rectx) { + if(x>=0 && y>=0 && x<zspan->rectx) { if(vergz<*rectz) { *rectz= vergz; *rectp= zvlnr; @@ -992,7 +675,7 @@ static void zbufline(int zvlnr, float *vec1, float *vec2) } } -static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) +static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) { int *rectz; int start, end, x, y, oldx, oldy, ofs; @@ -1018,7 +701,7 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) start= floor(v1[0]); end= start+floor(dx); - if(end>=R.rectx) end= R.rectx-1; + if(end>=zspan->rectx) end= zspan->rectx-1; oldy= floor(v1[1]); dy/= dx; @@ -1027,10 +710,10 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) dz= floor((v2[2]-v1[2])/dx); if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= R.rectz+ oldy*R.rectx+ start; + rectz= zspan->rectz + oldy*zspan->rectx+ start; - if(dy<0) ofs= -R.rectx; - else ofs= R.rectx; + if(dy<0) ofs= -zspan->rectx; + else ofs= zspan->rectx; for(x= start; x<=end; x++, rectz++) { @@ -1040,7 +723,7 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) rectz+= ofs; } - if(x>=0 && y>=0 && y<R.recty) { + if(x>=0 && y>=0 && y<zspan->recty) { if(vergz<*rectz) { *rectz= vergz; } @@ -1067,7 +750,7 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) start= floor(v1[1]); end= start+floor(dy); - if(end>=R.recty) end= R.recty-1; + if(end>=zspan->recty) end= zspan->recty-1; oldx= floor(v1[0]); dx/= dy; @@ -1076,12 +759,12 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) dz= floor((v2[2]-v1[2])/dy); if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow - rectz= R.rectz+ start*R.rectx+ oldx; + rectz= zspan->rectz + start*zspan->rectx+ oldx; if(dx<0) ofs= -1; else ofs= 1; - for(y= start; y<=end; y++, rectz+=R.rectx) { + for(y= start; y<=end; y++, rectz+=zspan->rectx) { x= floor(v1[0]); if(x!=oldx) { @@ -1089,7 +772,7 @@ static void zbufline_onlyZ(int zvlnr, float *vec1, float *vec2) rectz+= ofs; } - if(x>=0 && y>=0 && x<R.rectx) { + if(x>=0 && y>=0 && x<zspan->rectx) { if(vergz<*rectz) { *rectz= vergz; } @@ -1153,10 +836,19 @@ static int clipline(float *v1, float *v2) /* return 0: do not draw */ return 0; } +static void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco) +{ + float div; + + div= 1.0f/hoco[3]; + zco[0]= zspan->zmulx*(1.0+hoco[0]*div) + zspan->zofsx; + zco[1]= zspan->zmuly*(1.0+hoco[1]*div) + zspan->zofsy; + zco[2]= 0x7FFFFFFF *(hoco[2]*div); +} -void zbufclipwire(int zvlnr, VlakRen *vlr) +void zbufclipwire(ZSpan *zspan, int zvlnr, VlakRen *vlr) { - float vez[20], *f1, *f2, *f3, *f4= 0, deler; + float vez[20], *f1, *f2, *f3, *f4= 0; int c1, c2, c3, c4, ec, and, or; /* edgecode: 1= draw */ @@ -1192,18 +884,18 @@ void zbufclipwire(int zvlnr, VlakRen *vlr) QUATCOPY(vez, f1); QUATCOPY(vez+4, f2); if( clipline(vez, vez+4)) { - hoco_to_zco(vez, vez); - hoco_to_zco(vez+4, vez+4); - zbuflinefunc(zvlnr, vez, vez+4); + hoco_to_zco(zspan, vez, vez); + hoco_to_zco(zspan, vez+4, vez+4); + zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); } } if(ec & ME_V2V3) { QUATCOPY(vez, f2); QUATCOPY(vez+4, f3); if( clipline(vez, vez+4)) { - hoco_to_zco(vez, vez); - hoco_to_zco(vez+4, vez+4); - zbuflinefunc(zvlnr, vez, vez+4); + hoco_to_zco(zspan, vez, vez); + hoco_to_zco(zspan, vez+4, vez+4); + zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); } } if(vlr->v4) { @@ -1211,18 +903,18 @@ void zbufclipwire(int zvlnr, VlakRen *vlr) QUATCOPY(vez, f3); QUATCOPY(vez+4, f4); if( clipline(vez, vez+4)) { - hoco_to_zco(vez, vez); - hoco_to_zco(vez+4, vez+4); - zbuflinefunc(zvlnr, vez, vez+4); + hoco_to_zco(zspan, vez, vez); + hoco_to_zco(zspan, vez+4, vez+4); + zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); } } if(ec & ME_V4V1) { QUATCOPY(vez, f4); QUATCOPY(vez+4, f1); if( clipline(vez, vez+4)) { - hoco_to_zco(vez, vez); - hoco_to_zco(vez+4, vez+4); - zbuflinefunc(zvlnr, vez, vez+4); + hoco_to_zco(zspan, vez, vez); + hoco_to_zco(zspan, vez+4, vez+4); + zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); } } } @@ -1231,9 +923,9 @@ void zbufclipwire(int zvlnr, VlakRen *vlr) QUATCOPY(vez, f3); QUATCOPY(vez+4, f1); if( clipline(vez, vez+4)) { - hoco_to_zco(vez, vez); - hoco_to_zco(vez+4, vez+4); - zbuflinefunc(zvlnr, vez, vez+4); + hoco_to_zco(zspan, vez, vez); + hoco_to_zco(zspan, vez+4, vez+4); + zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); } } } @@ -1242,36 +934,21 @@ void zbufclipwire(int zvlnr, VlakRen *vlr) } } - deler= f1[3]; - vez[0]= Zmulx*(1.0+f1[0]/deler)+ Zjitx; - vez[1]= Zmuly*(1.0+f1[1]/deler)+ Zjity; - vez[2]= 0x7FFFFFFF *(f1[2]/deler); - - deler= f2[3]; - vez[4]= Zmulx*(1.0+f2[0]/deler)+ Zjitx; - vez[5]= Zmuly*(1.0+f2[1]/deler)+ Zjity; - vez[6]= 0x7FFFFFFF *(f2[2]/deler); - - deler= f3[3]; - vez[8]= Zmulx*(1.0+f3[0]/deler)+ Zjitx; - vez[9]= Zmuly*(1.0+f3[1]/deler)+ Zjity; - vez[10]= 0x7FFFFFFF *(f3[2]/deler); - + hoco_to_zco(zspan, vez, f1); + hoco_to_zco(zspan, vez+4, f2); + hoco_to_zco(zspan, vez+8, f3); if(vlr->v4) { - deler= f4[3]; - vez[12]= Zmulx*(1.0+f4[0]/deler)+ Zjitx; - vez[13]= Zmuly*(1.0+f4[1]/deler)+ Zjity; - vez[14]= 0x7FFFFFFF *(f4[2]/deler); + hoco_to_zco(zspan, vez+12, f4); - if(ec & ME_V3V4) zbuflinefunc(zvlnr, vez+8, vez+12); - if(ec & ME_V4V1) zbuflinefunc(zvlnr, vez+12, vez); + if(ec & ME_V3V4) zspan->zbuflinefunc(zspan, zvlnr, vez+8, vez+12); + if(ec & ME_V4V1) zspan->zbuflinefunc(zspan, zvlnr, vez+12, vez); } else { - if(ec & ME_V3V1) zbuflinefunc(zvlnr, vez+8, vez); + if(ec & ME_V3V1) zspan->zbuflinefunc(zspan, zvlnr, vez+8, vez); } - if(ec & ME_V1V2) zbuflinefunc(zvlnr, vez, vez+4); - if(ec & ME_V2V3) zbuflinefunc(zvlnr, vez+4, vez+8); + if(ec & ME_V1V2) zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4); + if(ec & ME_V2V3) zspan->zbuflinefunc(zspan, zvlnr, vez+4, vez+8); } @@ -1286,226 +963,7 @@ void zbufclipwire(int zvlnr, VlakRen *vlr) * @param v2 [4 floats, world coordinates] second vertex * @param v3 [4 floats, world coordinates] third vertex */ -static void zbufinvulGLinv(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) -{ - double x0,y0,z0,x1,y1,z1,x2,y2,z2,xx1; - double zxd,zyd,zy0,tmp; - float *minv,*maxv,*midv; - int *rectpofs,*rp; - int *rz,zverg,zvlak,x; - int my0,my2,sn1,sn2,rectx,zd,*rectzofs; - int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2; - - /* MIN MAX */ - if(v1[1]<v2[1]) { - if(v2[1]<v3[1]) { - minv=v1; midv=v2; maxv=v3; - } - else if(v1[1]<v3[1]) { - minv=v1; midv=v3; maxv=v2; - } - else { - minv=v3; midv=v1; maxv=v2; - } - } - else { - if(v1[1]<v3[1]) { - minv=v2; midv=v1; maxv=v3; - } - else if(v2[1]<v3[1]) { - minv=v2; midv=v3; maxv=v1; - } - else { - minv=v3; midv=v2; maxv=v1; - } - } - - my0= ceil(minv[1]); - my2= floor(maxv[1]); - omsl= floor(midv[1]); - - if(my2<0 || my0> R.recty) return; - - if(my0<0) my0=0; - - /* EDGES : LONGEST */ - xx1= maxv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx0= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-minv[1])+minv[0]); - xs0= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx0= 0; - xs0= 65536.0*(MIN2(minv[0],maxv[0])); - } - /* EDGES : THE TOP ONE */ - xx1= maxv[1]-midv[1]; - if(xx1>2.0/65536.0) { - z0= (maxv[0]-midv[0])/xx1; - - tmp= (-65536.0*z0); - dx1= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-midv[1])+midv[0]); - xs1= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx1= 0; - xs1= 65536.0*(MIN2(midv[0],maxv[0])); - } - /* EDGES : THE BOTTOM ONE */ - xx1= midv[1]-minv[1]; - if(xx1>2.0/65536.0) { - z0= (midv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx2= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]); - xs2= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx2= 0; - xs2= 65536.0*(MIN2(minv[0],midv[0])); - } - - /* ZBUF DX DY */ - x1= v1[0]- v2[0]; - x2= v2[0]- v3[0]; - y1= v1[1]- v2[1]; - y2= v2[1]- v3[1]; - z1= v1[2]- v2[2]; - z2= v2[2]- v3[2]; - x0= y1*z2-z1*y2; - y0= z1*x2-x1*z2; - z0= x1*y2-y1*x2; - - if(z0==0.0) return; - - if(midv[1]==maxv[1]) omsl= my2; - if(omsl<0) omsl= -1; /* then it does the first loop entirely */ - - while (my2 >= R.recty) { /* my2 can be larger */ - xs0+=dx0; - if (my2<=omsl) { - xs2+= dx2; - } - else{ - xs1+= dx1; - } - my2--; - } - - xx1= (x0*v1[0]+y0*v1[1])/z0+v1[2]; - - zxd= -x0/z0; - zyd= -y0/z0; - zy0= my2*zyd+xx1; - zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX); - - /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(R.rectz+rectx*my2); - rectpofs= (R.rectot+rectx*my2); - zvlak= zvlnr; - - xs3= 0; /* flag */ - if(dx0>dx1) { - xs3= xs0; - xs0= xs1; - xs1= xs3; - xs3= dx0; - dx0= dx1; - dx1= xs3; - xs3= 1; /* flag */ - - } - - for(y=my2;y>omsl;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs1>>16; - xs1+= dx1; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - rp= rectpofs+sn1; - x= sn2-sn1; - while(x>=0) { - if(zverg> *rz || *rz==0x7FFFFFFF) { - *rz= zverg; - *rp= zvlak; - } - zverg+= zd; - rz++; - rp++; - x--; - } - zy0-=zyd; - rectzofs-= rectx; - rectpofs-= rectx; - } - - if(xs3) { - xs0= xs1; - dx0= dx1; - } - if(xs0>xs2) { - xs3= xs0; - xs0= xs2; - xs2= xs3; - xs3= dx0; - dx0= dx2; - dx2= xs3; - } - - for(;y>=my0;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs2>>16; - xs2+= dx2; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - rp= rectpofs+sn1; - x= sn2-sn1; - while(x>=0) { - if(zverg> *rz || *rz==0x7FFFFFFF) { - *rz= zverg; - *rp= zvlak; - } - zverg+= zd; - rz++; - rp++; - x--; - } - - zy0-=zyd; - rectzofs-= rectx; - rectpofs-= rectx; - } -} - -/* uses spanbuffers */ - -static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) +static void zbufinvulGLinv4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) { double zxd, zyd, zy0, zverg; float x0,y0,z0; @@ -1516,13 +974,17 @@ static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v int sn1, sn2, rectx, *rectzofs, my0, my2; /* init */ - zbuf_init_span(zspan, 0, R.recty); + zbuf_init_span(zspan); /* set spans */ zbuf_add_to_span(zspan, v1, v2); zbuf_add_to_span(zspan, v2, v3); - zbuf_add_to_span(zspan, v3, v4); - zbuf_add_to_span(zspan, v4, v1); + if(v4) { + zbuf_add_to_span(zspan, v3, v4); + zbuf_add_to_span(zspan, v4, v1); + } + else + zbuf_add_to_span(zspan, v3, v1); /* clipped */ if(zspan->minp2==NULL || zspan->maxp2==NULL) return; @@ -1530,7 +992,7 @@ static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; -// printf("my %d %d\n", my0, my2); + // printf("my %d %d\n", my0, my2); if(my2<my0) return; @@ -1546,18 +1008,18 @@ static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v z0= x1*y2-y1*x2; if(z0==0.0) return; - + xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2]; - + zxd= -(double)x0/(double)z0; zyd= -(double)y0/(double)z0; zy0= ((double)my2)*zyd + (double)xx1; - + /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(R.rectz+rectx*my2); - rectpofs= (R.rectot+rectx*my2); - + rectx= zspan->rectx; + rectzofs= (zspan->rectz+rectx*my2); + rectpofs= (zspan->rectp+rectx*my2); + /* correct span */ sn1= (my0 + my2)/2; if(zspan->span1[sn1] < zspan->span2[sn1]) { @@ -1585,7 +1047,7 @@ static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v x= sn2-sn1; while(x>=0) { - if( (int)zverg < *rz) { + if( (int)zverg > *rz || *rz==0x7FFFFFFF) { *rz= (int)zverg; *rp= zvlnr; } @@ -1602,33 +1064,42 @@ static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v } } -static void zbufinvulGL(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) +/* uses spanbuffers */ + +static void zbufinvulGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) { - double x0,y0,z0; - double x1,y1,z1,x2,y2,z2,xx1; - double zxd, zyd, zy0, zverg, zd; + double zxd, zyd, zy0, zverg; + float x0,y0,z0; + float x1,y1,z1,x2,y2,z2,xx1; float *span1, *span2; int *rectpofs, *rp; - int *rz, zvlak, x, y, my0, my2; - int sn1,sn2, rectx, *rectzofs; + int *rz, x, y; + int sn1, sn2, rectx, *rectzofs, my0, my2; /* init */ - zbuf_init_span(zspan, 0, R.recty); + zbuf_init_span(zspan); /* set spans */ zbuf_add_to_span(zspan, v1, v2); zbuf_add_to_span(zspan, v2, v3); - zbuf_add_to_span(zspan, v3, v1); - + if(v4) { + zbuf_add_to_span(zspan, v3, v4); + zbuf_add_to_span(zspan, v4, v1); + } + else + zbuf_add_to_span(zspan, v3, v1); + /* clipped */ if(zspan->minp2==NULL || zspan->maxp2==NULL) return; if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; +// printf("my %d %d\n", my0, my2); if(my2<my0) return; - /* ZBUF DX DY */ + + /* ZBUF DX DY, in floats still */ x1= v1[0]- v2[0]; x2= v2[0]- v3[0]; y1= v1[1]- v2[1]; @@ -1640,21 +1111,19 @@ static void zbufinvulGL(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3 z0= x1*y2-y1*x2; if(z0==0.0) return; - - xx1= (x0*v1[0]+y0*v1[1])/z0+v1[2]; - - zxd= -x0/z0; - zyd= -y0/z0; - zy0= my2*zyd+xx1; - zd= zxd; - + + xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2]; + + zxd= -(double)x0/(double)z0; + zyd= -(double)y0/(double)z0; + zy0= ((double)my2)*zyd + (double)xx1; + /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(R.rectz+rectx*my2); - rectpofs= (R.rectot+rectx*my2); - zvlak= zvlnr; - - /* find correct span */ + rectx= zspan->rectx; + rectzofs= (zspan->rectz+rectx*my2); + rectpofs= (zspan->rectp+rectx*my2); + + /* correct span */ sn1= (my0 + my2)/2; if(zspan->span1[sn1] < zspan->span2[sn1]) { span1= zspan->span1+my2; @@ -1669,24 +1138,23 @@ static void zbufinvulGL(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3 sn1= floor(*span1); sn2= floor(*span2); - sn1++; if(sn2>=rectx) sn2= rectx-1; if(sn1<0) sn1= 0; if(sn2>=sn1) { - zverg= sn1*zxd+zy0; + zverg= (double)sn1*zxd + zy0; rz= rectzofs+sn1; rp= rectpofs+sn1; x= sn2-sn1; while(x>=0) { - if(zverg< *rz) { - *rz= floor(zverg); - *rp= zvlak; + if( (int)zverg < *rz) { + *rz= (int)zverg; + *rp= zvlnr; } - zverg+= zd; + zverg+= zxd; rz++; rp++; x--; @@ -1699,8 +1167,6 @@ static void zbufinvulGL(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3 } } - - /** * Fill the z buffer. The face buffer is not operated on! * @@ -1712,106 +1178,39 @@ static void zbufinvulGL(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3 * @param v3 [4 floats, world coordinates] third vertex */ -static void zbufinvulGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3) +static void zbufinvulGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) { - double x0,y0,z0,x1,y1,z1,x2,y2,z2,xx1; - double zxd,zyd,zy0,tmp; - float *minv,*maxv,*midv; - int *rz,zverg,x; - int my0,my2,sn1,sn2,rectx,zd,*rectzofs; - int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2; - - /* MIN MAX */ - if(v1[1]<v2[1]) { - if(v2[1]<v3[1]) { - minv=v1; - midv=v2; - maxv=v3; - } - else if(v1[1]<v3[1]) { - minv=v1; - midv=v3; - maxv=v2; - } - else { - minv=v3; - midv=v1; - maxv=v2; - } - } - else { - if(v1[1]<v3[1]) { - minv=v2; - midv=v1; - maxv=v3; - } - else if(v2[1]<v3[1]) { - minv=v2; - midv=v3; - maxv=v1; - } - else { - minv=v3; - midv=v2; - maxv=v1; - } - } - - my0= ceil(minv[1]); - my2= floor(maxv[1]); - omsl= floor(midv[1]); - - if(my2<0 || my0> R.recty) return; - - if(my0<0) my0=0; - - /* EDGES : LONGEST */ - xx1= maxv[1]-minv[1]; - if(xx1!=0.0) { - z0= (maxv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx0= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-minv[1])+minv[0]); - xs0= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx0= 0; - xs0= 65536.0*(MIN2(minv[0],maxv[0])); - } - /* EDGES : TOP */ - xx1= maxv[1]-midv[1]; - if(xx1!=0.0) { - z0= (maxv[0]-midv[0])/xx1; - - tmp= (-65536.0*z0); - dx1= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(my2-midv[1])+midv[0]); - xs1= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx1= 0; - xs1= 65536.0*(MIN2(midv[0],maxv[0])); - } - /* EDGES : BOTTOM */ - xx1= midv[1]-minv[1]; - if(xx1!=0.0) { - z0= (midv[0]-minv[0])/xx1; - - tmp= (-65536.0*z0); - dx2= CLAMPIS(tmp, INT_MIN, INT_MAX); - - tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]); - xs2= CLAMPIS(tmp, INT_MIN, INT_MAX); - } - else { - dx2= 0; - xs2= 65536.0*(MIN2(minv[0],midv[0])); + double zxd, zyd, zy0, zverg; + float x0,y0,z0; + float x1,y1,z1,x2,y2,z2,xx1; + float *span1, *span2; + int *rz, x, y; + int sn1, sn2, rectx, *rectzofs, my0, my2; + + /* init */ + zbuf_init_span(zspan); + + /* set spans */ + zbuf_add_to_span(zspan, v1, v2); + zbuf_add_to_span(zspan, v2, v3); + if(v4) { + zbuf_add_to_span(zspan, v3, v4); + zbuf_add_to_span(zspan, v4, v1); } - - /* ZBUF DX DY */ + else + zbuf_add_to_span(zspan, v3, v1); + + /* clipped */ + if(zspan->minp2==NULL || zspan->maxp2==NULL) return; + + if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; + if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + + // printf("my %d %d\n", my0, my2); + if(my2<my0) return; + + + /* ZBUF DX DY, in floats still */ x1= v1[0]- v2[0]; x2= v2[0]- v3[0]; y1= v1[1]- v2[1]; @@ -1821,112 +1220,54 @@ static void zbufinvulGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, flo x0= y1*z2-z1*y2; y0= z1*x2-x1*z2; z0= x1*y2-y1*x2; - + if(z0==0.0) return; - - if(midv[1]==maxv[1]) omsl= my2; - if(omsl<0) omsl= -1; /* then it takes first loop entirely */ - - while (my2 >= R.recty) { /* my2 can be larger */ - xs0+=dx0; - if (my2<=omsl) { - xs2+= dx2; - } - else{ - xs1+= dx1; - } - my2--; - } - - xx1= (x0*v1[0]+y0*v1[1])/z0+v1[2]; - - zxd= -x0/z0; - zyd= -y0/z0; - zy0= my2*zyd+xx1; - zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX); - + + xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2]; + + zxd= -(double)x0/(double)z0; + zyd= -(double)y0/(double)z0; + zy0= ((double)my2)*zyd + (double)xx1; + /* start-offset in rect */ - rectx= R.rectx; - rectzofs= (int *)(R.rectz+rectx*my2); - - xs3= 0; /* flag */ - if(dx0>dx1) { - xs3= xs0; - xs0= xs1; - xs1= xs3; - xs3= dx0; - dx0= dx1; - dx1= xs3; - xs3= 1; /* flag */ - - } - - for(y=my2;y>omsl;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs1>>16; - xs1+= dx1; - - sn1++; - - if(sn2>=rectx) sn2= rectx-1; - if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - - x= sn2-sn1; - while(x>=0) { - if(zverg< *rz) { - *rz= zverg; - } - zverg+= zd; - rz++; - x--; - } - zy0-=zyd; - rectzofs-= rectx; - } - - if(xs3) { - xs0= xs1; - dx0= dx1; + rectx= zspan->rectx; + rectzofs= (zspan->rectz+rectx*my2); + + /* correct span */ + sn1= (my0 + my2)/2; + if(zspan->span1[sn1] < zspan->span2[sn1]) { + span1= zspan->span1+my2; + span2= zspan->span2+my2; } - if(xs0>xs2) { - xs3= xs0; - xs0= xs2; - xs2= xs3; - xs3= dx0; - dx0= dx2; - dx2= xs3; + else { + span1= zspan->span2+my2; + span2= zspan->span1+my2; } - - for(;y>=my0;y--) { - - sn1= xs0>>16; - xs0+= dx0; - - sn2= xs2>>16; - xs2+= dx2; - - sn1++; - + + for(y=my2; y>=my0; y--, span1--, span2--) { + + sn1= floor(*span1); + sn2= floor(*span2); + sn1++; + if(sn2>=rectx) sn2= rectx-1; if(sn1<0) sn1= 0; - zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX); - rz= rectzofs+sn1; - - x= sn2-sn1; - while(x>=0) { - if(zverg< *rz) { - *rz= zverg; + + if(sn2>=sn1) { + zverg= (double)sn1*zxd + zy0; + rz= rectzofs+sn1; + x= sn2-sn1; + + while(x>=0) { + if( (int)zverg < *rz) { + *rz= (int)zverg; + } + zverg+= zxd; + rz++; + x--; } - zverg+= zd; - rz++; - x--; } - + zy0-=zyd; rectzofs-= rectx; } @@ -1958,7 +1299,7 @@ static void clippyra(float *labda, float *v1, float *v2, int *b2, int *b3, int a db= v2[3]-v1[3]; /* according the original article by Liang&Barsky, for clipping of - * homeginic coordinates with viewplane, the value of "0" is used instead of "-w" . + * homogenous coordinates with viewplane, the value of "0" is used instead of "-w" . * This differs from the other clipping cases (like left or top) and I considered * it to be not so 'homogenic'. But later it has proven to be an error, * who would have thought that of L&B! @@ -2032,7 +1373,7 @@ static void makevertpyra(float *vez, float *labda, float **trias, float *v1, flo /* ------------------------------------------------------------------------- */ -void RE_projectverto(float *v1, float *adr) +void projectverto(float *v1, float winmat[][4], float *adr) { /* calcs homogenic coord of vertex v1 */ float x,y,z; @@ -2040,17 +1381,17 @@ void RE_projectverto(float *v1, float *adr) x= v1[0]; y= v1[1]; z= v1[2]; - adr[0]= x*R.winmat[0][0] + z*R.winmat[2][0] + R.winmat[3][0]; - adr[1]= y*R.winmat[1][1] + z*R.winmat[2][1] + R.winmat[3][1]; - adr[2]= z*R.winmat[2][2] + R.winmat[3][2]; - adr[3]= z*R.winmat[2][3] + R.winmat[3][3]; + adr[0]= x*winmat[0][0] + z*winmat[2][0] + winmat[3][0]; + adr[1]= y*winmat[1][1] + z*winmat[2][1] + winmat[3][1]; + adr[2]= z*winmat[2][2] + winmat[3][2]; + adr[3]= z*winmat[2][3] + winmat[3][3]; //printf("hoco %f %f %f %f\n", adr[0], adr[1], adr[2], adr[3]); } /* ------------------------------------------------------------------------- */ -void projectvert(float *v1, float *adr) +void projectvert(float *v1, float winmat[][4], float *adr) { /* calcs homogenic coord of vertex v1 */ float x,y,z; @@ -2058,17 +1399,16 @@ void projectvert(float *v1, float *adr) x= v1[0]; y= v1[1]; z= v1[2]; - adr[0]= x*R.winmat[0][0]+ y*R.winmat[1][0]+ z*R.winmat[2][0]+ R.winmat[3][0]; - adr[1]= x*R.winmat[0][1]+ y*R.winmat[1][1]+ z*R.winmat[2][1]+ R.winmat[3][1]; - adr[2]= x*R.winmat[0][2]+ y*R.winmat[1][2]+ z*R.winmat[2][2]+ R.winmat[3][2]; - adr[3]= x*R.winmat[0][3]+ y*R.winmat[1][3]+ z*R.winmat[2][3]+ R.winmat[3][3]; + adr[0]= x*winmat[0][0]+ y*winmat[1][0]+ z*winmat[2][0]+ winmat[3][0]; + adr[1]= x*winmat[0][1]+ y*winmat[1][1]+ z*winmat[2][1]+ winmat[3][1]; + adr[2]= x*winmat[0][2]+ y*winmat[1][2]+ z*winmat[2][2]+ winmat[3][2]; + adr[3]= x*winmat[0][3]+ y*winmat[1][3]+ z*winmat[2][3]+ winmat[3][3]; } /* do zbuffering and clip, f1 f2 f3 are hocos, c1 c2 c3 are clipping flags */ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3) { - float deler; float *vlzp[32][3], labda[3][2]; float vez[400], *trias[40]; @@ -2127,7 +1467,7 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, clipflag[1]= clipflag[2]= 0; f1= vez; for(b3=0; b3<clve; b3++) { - c4= RE_testclip(f1); + c4= testclip(f1); clipflag[1] |= (c4 & 3); clipflag[2] |= (c4 & 12); f1+= 4; @@ -2155,15 +1495,12 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, /* perspective division */ f1=vez; for(c1=0;c1<clve;c1++) { - deler= f1[3]; - f1[0]= Zmulx*(1.0+f1[0]/deler)+ Zjitx; - f1[1]= Zmuly*(1.0+f1[1]/deler)+ Zjity; - f1[2]= 0x7FFFFFFF *(f1[2]/deler); + hoco_to_zco(zspan, f1, f1); f1+=4; } for(b=1;b<clvl;b++) { if(vlzp[b][0]) { - zbuffunc(zspan, zvlnr, vlzp[b][0],vlzp[b][1],vlzp[b][2]); + zspan->zbuffunc(zspan, zvlnr, vlzp[b][0],vlzp[b][1],vlzp[b][2], NULL); } } return; @@ -2171,28 +1508,15 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, } /* perspective division: HCS to ZCS */ - - deler= f1[3]; - vez[0]= Zmulx*(1.0+f1[0]/deler)+ Zjitx; - vez[1]= Zmuly*(1.0+f1[1]/deler)+ Zjity; - vez[2]= 0x7FFFFFFF *(f1[2]/deler); + hoco_to_zco(zspan, vez, f1); + hoco_to_zco(zspan, vez+4, f2); + hoco_to_zco(zspan, vez+8, f3); - deler= f2[3]; - vez[4]= Zmulx*(1.0+f2[0]/deler)+ Zjitx; - vez[5]= Zmuly*(1.0+f2[1]/deler)+ Zjity; - vez[6]= 0x7FFFFFFF *(f2[2]/deler); - - deler= f3[3]; - vez[8]= Zmulx*(1.0+f3[0]/deler)+ Zjitx; - vez[9]= Zmuly*(1.0+f3[1]/deler)+ Zjity; - vez[10]= 0x7FFFFFFF *(f3[2]/deler); - - zbuffunc(zspan, zvlnr, vez,vez+4,vez+8); + zspan->zbuffunc(zspan, zvlnr, vez,vez+4,vez+8, NULL); } static void zbufclip4(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, float *f4, int c1, int c2, int c3, int c4) { - float div; float vez[16]; if(c1 | c2 | c3 | c4) { /* not in middle */ @@ -2206,52 +1530,102 @@ static void zbufclip4(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, } /* perspective division: HCS to ZCS */ + hoco_to_zco(zspan, vez, f1); + hoco_to_zco(zspan, vez+4, f2); + hoco_to_zco(zspan, vez+8, f3); + hoco_to_zco(zspan, vez+12, f4); - div= 1.0f/f1[3]; - vez[0]= Zmulx*(1.0+f1[0]*div)+ Zjitx; - vez[1]= Zmuly*(1.0+f1[1]*div)+ Zjity; - vez[2]= 0x7FFFFFFF *(f1[2]*div); - - div= 1.0f/f2[3]; - vez[4]= Zmulx*(1.0+f2[0]*div)+ Zjitx; - vez[5]= Zmuly*(1.0+f2[1]*div)+ Zjity; - vez[6]= 0x7FFFFFFF *(f2[2]*div); - - div= 1.0f/f3[3]; - vez[8]= Zmulx*(1.0+f3[0]*div)+ Zjitx; - vez[9]= Zmuly*(1.0+f3[1]*div)+ Zjity; - vez[10]= 0x7FFFFFFF *(f3[2]*div); - - div= 1.0f/f4[3]; - vez[12]= Zmulx*(1.0+f4[0]*div)+ Zjitx; - vez[13]= Zmuly*(1.0+f4[1]*div)+ Zjity; - vez[14]= 0x7FFFFFFF *(f4[2]*div); - - zbuffunc4(zspan, zvlnr, vez, vez+4, vez+8, vez+12); + zspan->zbuffunc(zspan, zvlnr, vez, vez+4, vez+8, vez+12); } /* ***************** ZBUFFER MAIN ROUTINES **************** */ +void set_part_zbuf_clipflag(RenderPart *pa) +{ + VertRen *ver=NULL; + float minx, miny, maxx, maxy, wco; + unsigned short clipclear; + int v; -void zbufferall(void) + minx= (2*pa->disprect.xmin - R.winx-1)/(float)R.winx; + maxx= (2*pa->disprect.xmax - R.winx+1)/(float)R.winx; + miny= (2*pa->disprect.ymin - R.winy-1)/(float)R.winy; + maxy= (2*pa->disprect.ymax - R.winy+1)/(float)R.winy; + + /* supports up to 4 threads this way */ + clipclear= ~(15 << 4*(pa->thread & 3)); + + for(v=0; v<R.totvert; v++) { + if((v & 255)==0) ver= RE_findOrAddVert(&R, v); + else ver++; + + wco= ver->ho[3]; + ver->flag &= clipclear; + + switch(pa->thread & 3) { + case 0: + if( ver->ho[0] > maxx*wco) ver->flag |= 1; + else if( ver->ho[0]< minx*wco) ver->flag |= 2; + if( ver->ho[1] > maxy*wco) ver->flag |= 4; + else if( ver->ho[1]< miny*wco) ver->flag |= 8; + break; + case 1: + if( ver->ho[0] > maxx*wco) ver->flag |= 16; + else if( ver->ho[0]< minx*wco) ver->flag |= 32; + if( ver->ho[1] > maxy*wco) ver->flag |= 64; + else if( ver->ho[1]< miny*wco) ver->flag |= 128; + break; + case 2: + if( ver->ho[0] > maxx*wco) ver->flag |= 256; + else if( ver->ho[0]< minx*wco) ver->flag |= 512; + if( ver->ho[1] > maxy*wco) ver->flag |= 1024; + else if( ver->ho[1]< miny*wco) ver->flag |= 2048; + break; + case 3: + if( ver->ho[0] > maxx*wco) ver->flag |= 4096; + else if( ver->ho[0]< minx*wco) ver->flag |= 8192; + if( ver->ho[1] > maxy*wco) ver->flag |= 16384; + else if( ver->ho[1]< miny*wco) ver->flag |= 32768; + break; + } + } +} + +void zbuffer_solid(RenderPart *pa) { ZSpan zspan; VlakRen *vlr= NULL; Material *ma=0; int v, zvlnr; + unsigned short clipmask; short transp=0, env=0, wire=0; - Zmulx= ((float)R.rectx)/2.0; - Zmuly= ((float)R.recty)/2.0; - - fillrect(R.rectz, R.rectx, R.recty, 0x7FFFFFFF); - - zbuf_alloc_span(&zspan, R.recty); + zbuf_alloc_span(&zspan, pa->rectx, pa->recty); - zbuffunc= zbufinvulGL; - zbuffunc4= zbufinvulGL4; - zbuflinefunc= zbufline; + /* needed for transform from hoco to zbuffer co */ + zspan.zmulx= ((float)R.winx)/2.0; + zspan.zmuly= ((float)R.winy)/2.0; + zspan.zofsx= -pa->disprect.xmin -0.5f; + zspan.zofsy= -pa->disprect.ymin -0.5f; + + if(R.osa) { + zspan.zofsx-= R.jit[pa->sample][0]; + zspan.zofsy-= R.jit[pa->sample][1]; + } + + /* the buffers */ + zspan.rectz= pa->rectz; + zspan.rectp= pa->rectp; + fillrect(pa->rectp, pa->rectx, pa->recty, 0); + fillrect(pa->rectz, pa->rectx, pa->recty, 0x7FFFFFFF); + + /* filling methods */ + zspan.zbuffunc= zbufinvulGL4; + zspan.zbuflinefunc= zbufline; + + /* part clipflag, threaded */ + clipmask= (15 << 4*(pa->thread & 3)); for(v=0; v<R.totvlak; v++) { @@ -2265,24 +1639,34 @@ void zbufferall(void) env= (ma->mode & MA_ENV); wire= (ma->mode & MA_WIRE); - if(ma->mode & MA_ZINV) zbuffunc= zbufinvulGLinv; - else zbuffunc= zbufinvulGL; + if(ma->mode & MA_ZINV) zspan.zbuffunc= zbufinvulGLinv4; + else zspan.zbuffunc= zbufinvulGL4; } if(transp==0) { - if(env) zvlnr= 0; - else zvlnr= v+1; + unsigned short partclip; - if(wire) zbufclipwire(zvlnr, vlr); - else { - if(vlr->v4 && (vlr->flag & R_STRAND)) { - zbufclip4(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip, vlr->v4->clip); - } + /* partclipping doesn't need viewplane clipping */ + if(vlr->v4) partclip= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag & vlr->v4->flag; + else partclip= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag; + + if((partclip & clipmask)==0) { + + if(env) zvlnr= 0; + else zvlnr= v+1; + + if(wire) zbufclipwire(&zspan, zvlnr, vlr); else { - zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); - if(vlr->v4) { - if(zvlnr) zvlnr+= 0x800000; - zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v3->clip, vlr->v4->clip); + /* strands allow to be filled in as quad */ + if(vlr->v4 && (vlr->flag & R_STRAND)) { + zbufclip4(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip, vlr->v4->clip); + } + else { + zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); + if(vlr->v4) { + if(zvlnr) zvlnr+= 0x800000; + zbufclip(&zspan, zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v3->clip, vlr->v4->clip); + } } } } @@ -2293,11 +1677,19 @@ void zbufferall(void) zbuf_free_span(&zspan); } -static int hashlist_projectvert(float *v1, float *hoco) +typedef struct { + float *vert; + float hoco[4]; + int clip; +} VertBucket; + +/* warning, not threaded! */ +static int hashlist_projectvert(float *v1, float winmat[][4], float *hoco) { static VertBucket bucket[256], *buck; - if(v1==0) { + /* init static bucket */ + if(v1==NULL) { memset(bucket, 0, 256*sizeof(VertBucket)); return 0; } @@ -2308,49 +1700,42 @@ static int hashlist_projectvert(float *v1, float *hoco) return buck->clip; } - projectvert(v1, hoco); - buck->clip = RE_testclip(hoco); + projectvert(v1, winmat, hoco); + buck->clip = testclip(hoco); buck->vert= v1; QUATCOPY(buck->hoco, hoco); return buck->clip; } /* used for booth radio 'tool' as during render */ -void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem) +void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem, Render *re) { ZSpan zspan; - float hoco[4][4]; + float hoco[4][4], winmat[4][4]; int a, zvlnr; int c1, c2, c3, c4= 0; - int *rectoto, *rectzo; - int rectxo, rectyo; if(rg_totelem==0) return; - hashlist_projectvert(NULL, NULL); + hashlist_projectvert(NULL, winmat, NULL); - rectxo= R.rectx; - rectyo= R.recty; - rectoto= R.rectot; - rectzo= R.rectz; - - R.rectx= vw->rectx; - R.recty= vw->recty; - R.rectot= vw->rect; - R.rectz= vw->rectz; - - Zmulx= ((float)R.rectx)/2.0; - Zmuly= ((float)R.recty)/2.0; - /* needed for projectvert */ - MTC_Mat4MulMat4(R.winmat, vw->viewmat, vw->winmat); - - fillrect(R.rectz, R.rectx, R.recty, 0x7FFFFFFF); - fillrect(R.rectot, R.rectx, R.recty, 0xFFFFFF); + MTC_Mat4MulMat4(winmat, vw->viewmat, vw->winmat); - zbuf_alloc_span(&zspan, R.recty); + zbuf_alloc_span(&zspan, vw->rectx, vw->recty); + zspan.zmulx= ((float)vw->rectx)/2.0; + zspan.zmuly= ((float)vw->recty)/2.0; + zspan.zofsx= 0; + zspan.zofsy= 0; - zbuffunc= zbufinvulGL; + /* the buffers */ + zspan.rectz= vw->rectz; + zspan.rectp= vw->rect; + fillrect(zspan.rectz, vw->rectx, vw->recty, 0x7FFFFFFF); + fillrect(zspan.rectp, vw->rectx, vw->recty, 0xFFFFFF); + + /* filling methods */ + zspan.zbuffunc= zbufinvulGL4; if(rg_elem) { /* radio tool */ RNode **re, *rn; @@ -2365,18 +1750,18 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem) else if( rn->f & RAD_BACKFACE) zvlnr= 0xFFFFFF; else zvlnr= a; - c1= hashlist_projectvert(rn->v1, hoco[0]); - c2= hashlist_projectvert(rn->v2, hoco[1]); - c3= hashlist_projectvert(rn->v3, hoco[2]); + c1= hashlist_projectvert(rn->v1, winmat, hoco[0]); + c2= hashlist_projectvert(rn->v2, winmat, hoco[1]); + c3= hashlist_projectvert(rn->v3, winmat, hoco[2]); if(rn->v4) { - c4= hashlist_projectvert(rn->v4, hoco[3]); + c4= hashlist_projectvert(rn->v4, winmat, hoco[3]); } - zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3); - if(rn->v4) { - zbufclip(&zspan, zvlnr, hoco[0], hoco[2], hoco[3], c1, c3, c4); - } + if(rn->v4) + zbufclip4(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4); + else + zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3); } } } @@ -2385,8 +1770,8 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem) RadFace *rf; int totface=0; - for(a=0; a<R.totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; else vlr++; + for(a=0; a<re->totvlak; a++) { + if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++; if(vlr->radface) { rf= vlr->radface; @@ -2396,34 +1781,28 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem) else if( rf->flag & RAD_BACKFACE) zvlnr= 0xFFFFFF; /* receives no energy, but is zbuffered */ else zvlnr= totface; - c1= hashlist_projectvert(vlr->v1->co, hoco[0]); - c2= hashlist_projectvert(vlr->v2->co, hoco[1]); - c3= hashlist_projectvert(vlr->v3->co, hoco[2]); + c1= hashlist_projectvert(vlr->v1->co, winmat, hoco[0]); + c2= hashlist_projectvert(vlr->v2->co, winmat, hoco[1]); + c3= hashlist_projectvert(vlr->v3->co, winmat, hoco[2]); if(vlr->v4) { - c4= hashlist_projectvert(vlr->v4->co, hoco[3]); + c4= hashlist_projectvert(vlr->v4->co, winmat, hoco[3]); } - zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3); - if(vlr->v4) { - zbufclip(&zspan, zvlnr, hoco[0], hoco[2], hoco[3], c1, c3, c4); - } + if(vlr->v4) + zbufclip4(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4); + else + zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3); } totface++; } } } - - /* restore */ - R.rectx= rectxo; - R.recty= rectyo; - R.rectot= rectoto; - R.rectz= rectzo; zbuf_free_span(&zspan); } -void zbuffershad(LampRen *lar) +void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size) { ZSpan zspan; VlakRen *vlr= NULL; @@ -2432,20 +1811,23 @@ void zbuffershad(LampRen *lar) if(lar->mode & LA_LAYER) lay= lar->lay; - Zmulx= ((float)R.rectx)/2.0; - Zmuly= ((float)R.recty)/2.0; - Zjitx= Zjity= -0.5; - - fillrect(R.rectz,R.rectx,R.recty,0x7FFFFFFE); - - zbuf_alloc_span(&zspan, R.recty); + zbuf_alloc_span(&zspan, size, size); + zspan.zmulx= ((float)size)/2.0; + zspan.zmuly= ((float)size)/2.0; + zspan.zofsx= -0.5f; + zspan.zofsy= -0.5f; + + /* the buffers */ + zspan.rectz= rectz; + fillrect(rectz, size, size, 0x7FFFFFFE); - zbuflinefunc= zbufline_onlyZ; - zbuffunc= zbufinvulGL_onlyZ; + /* filling methods */ + zspan.zbuflinefunc= zbufline_onlyZ; + zspan.zbuffunc= zbufinvulGL_onlyZ; - for(a=0;a<R.totvlak;a++) { + for(a=0; a<re->totvlak; a++) { - if((a & 255)==0) vlr= R.blovl[a>>8]; + if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++; if(vlr->mat!= ma) { @@ -2455,11 +1837,13 @@ void zbuffershad(LampRen *lar) } if(ok && (vlr->flag & R_VISIBLE) && (vlr->lay & lay)) { - if(ma->mode & MA_WIRE) zbufclipwire(a+1, vlr); - else if(vlr->flag & R_STRAND) zbufclipwire(a+1, vlr); + if(ma->mode & MA_WIRE) zbufclipwire(&zspan, a+1, vlr); + else if(vlr->flag & R_STRAND) zbufclipwire(&zspan, a+1, vlr); else { - zbufclip(&zspan, 0, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); - if(vlr->v4) zbufclip(&zspan, 0, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v3->clip, vlr->v4->clip); + if(vlr->v4) + zbufclip4(&zspan, 0, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip, vlr->v4->clip); + else + zbufclip(&zspan, 0, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip); } } } @@ -2470,57 +1854,31 @@ void zbuffershad(LampRen *lar) /* ******************** ABUF ************************* */ - -void bgnaccumbuf(void) -{ - - Arectz= MEM_mallocN(sizeof(int)*ABUFPART*R.rectx, "Arectz"); - APixbuf= MEM_mallocN(ABUFPART*R.rectx*sizeof(APixstr), "APixbuf"); - - Aminy= -1000; - Amaxy= -1000; - - apsmteller= 0; - apsmfirst.next= 0; - apsmfirst.ps= 0; -} -/* ------------------------------------------------------------------------ */ - -void endaccumbuf(void) -{ - - MEM_freeN(Arectz); - MEM_freeN(APixbuf); - freepsA(); -} - -/* ------------------------------------------------------------------------ */ - /** * Copy results from the solid face z buffering to the transparent * buffer. */ -static void copyto_abufz(int sample) +static void copyto_abufz(RenderPart *pa, int *arectz, int sample) { PixStr *ps; int x, y, *rza; long *rd; /* now, in OSA the pixstructs contain all faces filled in */ - if(R.r.mode & R_OSA) fillrect(Arectz, R.rectx, Amaxy-Aminy+1, 0x7FFFFFFF); + if(R.r.mode & R_OSA) fillrect(arectz, pa->rectx, pa->recty, 0x7FFFFFFF); else { - memcpy(Arectz, R.rectz+ R.rectx*Aminy, 4*R.rectx*(Amaxy-Aminy+1)); + memcpy(arectz, pa->rectz, 4*pa->rectx*pa->recty); return; } - //if( (R.r.mode & R_OSA)==0 || sample==0) return; + if( (R.r.mode & R_OSA)==0 || sample==0) return; - rza= Arectz; - rd= (R.rectdaps+ R.rectx*Aminy); + rza= arectz; + rd= pa->rectdaps; sample= (1<<sample); - for(y=Aminy; y<=Amaxy; y++) { - for(x=0; x<R.rectx; x++) { + for(y=0; y<pa->recty; y++) { + for(x=0; x<pa->rectx; x++) { if(*rd) { ps= (PixStr *)(*rd); @@ -2547,93 +1905,60 @@ static void copyto_abufz(int sample) * Do accumulation z buffering. */ - -static void set_faces_raycountflag(void) -{ - VertRen *ver=NULL; - VlakRen *vlr=NULL; - float wco, miny, maxy; - int v, clipval; - - miny= (float)(2*Aminy-R.recty-1)/(float)R.recty; - maxy= (float)(2*Amaxy-R.recty+2)/(float)R.recty; - - for(v=0; v<R.totvert; v++) { - if((v & 255)==0) ver= RE_findOrAddVert(v); - else ver++; - - wco= ver->ho[3]; - ver->flag= 0; - if( ver->ho[1] > maxy*wco) ver->flag |= 64; - else if( ver->ho[1]< miny*wco) ver->flag |= 128; - } - - for(v=0; v<R.totvlak; v++) { - if((v & 255)==0) { - vlr= R.blovl[v>>8]; - } - else vlr++; - - if(vlr->v4) - clipval= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag & vlr->v4->flag; - else - clipval= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag; - - if(clipval==64 || clipval==128) - vlr->raycount= 0; - else - vlr->raycount= 1; - } -} - - -static void zbuffer_abuf() +static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase) { ZSpan zspan; Material *ma=0; VlakRen *vlr=NULL; float vec[3], hoco[4], mul, zval, fval; - int v, zvlnr; - int len; + int v, zvlnr, zsample; + unsigned short clipmask; - Zjitx= Zjity= -0.5; - Zmulx= ((float)R.rectx)/2.0; - Zmuly= ((float)R.recty)/2.0; - - /* clear APixstructs */ - len= sizeof(APixstr)*R.rectx*ABUFPART; - memset(APixbuf, 0, len); + zbuf_alloc_span(&zspan, pa->rectx, pa->recty); - zbuf_alloc_span(&zspan, R.recty); + /* needed for transform from hoco to zbuffer co */ + zspan.zmulx= ((float)R.winx)/2.0; + zspan.zmuly= ((float)R.winy)/2.0; + zspan.zofsx= -pa->disprect.xmin -0.5f; + zspan.zofsy= -pa->disprect.ymin -0.5f; - zbuffunc= zbufinvulAc; - zbuffunc4= zbufinvulAc4; - zbuflinefunc= zbuflineAc; - - set_faces_raycountflag(); + /* the buffers */ + zspan.arectz= RE_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectz"); + zspan.apixbuf= APixbuf; + zspan.apsmbase= apsmbase; + + /* filling methods */ + zspan.zbuffunc= zbufinvulAc4; + zspan.zbuflinefunc= zbuflineAc; + + /* part clipflag, 4 threads */ + clipmask= (15 << 4*(pa->thread & 3)); - for(Zsample=0; Zsample<R.osa || R.osa==0; Zsample++) { + for(zsample=0; zsample<R.osa || R.osa==0; zsample++) { + + copyto_abufz(pa, zspan.arectz, zsample); /* init zbuffer */ + zspan.mask= 1<<zsample; - copyto_abufz(Zsample); /* init zbuffer */ - if(R.r.mode & R_OSA) { - Zjitx= -jit[Zsample][0]-0.5; - Zjity= -jit[Zsample][1]-0.5; + zspan.zofsx= -pa->disprect.xmin-R.jit[zsample][0]-0.5; + zspan.zofsy= -pa->disprect.ymin-R.jit[zsample][1]-0.5; } for(v=0; v<R.totvlak; v++) { - if((v & 255)==0) { + if((v & 255)==0) vlr= R.blovl[v>>8]; - } else vlr++; - if(vlr->raycount) { - ma= vlr->mat; - - if(ma->mode & (MA_ZTRA)) { - - if(vlr->flag & R_VISIBLE) { - + ma= vlr->mat; + if(ma->mode & (MA_ZTRA)) { + if(vlr->flag & R_VISIBLE) { + unsigned short partclip; + + /* partclipping doesn't need viewplane clipping */ + if(vlr->v4) partclip= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag & vlr->v4->flag; + else partclip= vlr->v1->flag & vlr->v2->flag & vlr->v3->flag; + + if((partclip & clipmask)==0) { /* a little advantage for transp rendering (a z offset) */ if( ma->zoffs != 0.0) { mul= 0x7FFFFFFF; @@ -2642,16 +1967,16 @@ static void zbuffer_abuf() VECCOPY(vec, vlr->v1->co); /* z is negative, otherwise its being clipped */ vec[2]-= ma->zoffs; - RE_projectverto(vec, hoco); + projectverto(vec, R.winmat, hoco); fval= mul*(1.0+hoco[2]/hoco[3]); - Azvoordeel= (int) fabs(zval - fval ); + zspan.polygon_offset= (int) fabs(zval - fval ); } - else Azvoordeel= 0; + else zspan.polygon_offset= 0; zvlnr= v+1; - if(ma->mode & (MA_WIRE)) zbufclipwire(zvlnr, vlr); + if(ma->mode & (MA_WIRE)) zbufclipwire(&zspan, zvlnr, vlr); else { if(vlr->v4 && (vlr->flag & R_STRAND)) { zbufclip4(&zspan, zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip, vlr->v4->clip); @@ -2665,21 +1990,23 @@ static void zbuffer_abuf() } } } - if( (v & 255)==255) - if(RE_local_test_break()) - break; } + if( (v & 255)==255) + if(R.test_break()) + break; } } if((R.r.mode & R_OSA)==0) break; - if(RE_local_test_break()) break; + if(R.test_break()) break; } + RE_freeN(zspan.arectz); zbuf_free_span(&zspan); + } -int vergzvlak(const void *a1, const void *a2) +static int vergzvlak(const void *a1, const void *a2) { const int *x1=a1, *x2=a2; @@ -2691,7 +2018,7 @@ int vergzvlak(const void *a1, const void *a2) /** * Shade this face at this location in SCS. */ -static void shadetrapixel(float x, float y, int z, int facenr, int mask, float *fcol) +static void shadetrapixel(RenderPart *pa, float x, float y, int z, int facenr, int mask, float *fcol) { float rco[3]; @@ -2700,14 +2027,14 @@ static void shadetrapixel(float x, float y, int z, int facenr, int mask, float * return; } if(R.r.mode & R_OSA) { - VlakRen *vlr= RE_findOrAddVlak( (facenr-1) & 0x7FFFFF); + VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & 0x7FFFFF); float accumcol[4]={0,0,0,0}, tot=0.0; int a; if(vlr->flag & R_FULL_OSA) { for(a=0; a<R.osa; a++) { if(mask & (1<<a)) { - shadepixel(x+jit[a][0], y+jit[a][1], z, facenr, 1<<a, fcol, rco); + shadepixel(pa, x+R.jit[a][0], y+R.jit[a][1], z, facenr, 1<<a, fcol, rco); accumcol[0]+= fcol[0]; accumcol[1]+= fcol[1]; accumcol[2]+= fcol[2]; @@ -2722,17 +2049,14 @@ static void shadetrapixel(float x, float y, int z, int facenr, int mask, float * fcol[3]= accumcol[3]*tot; } else { - extern float centLut[16]; - extern char *centmask; - - int b= centmask[mask]; - x= x+centLut[b & 15]; - y= y+centLut[b>>4]; - shadepixel(x, y, z, facenr, mask, fcol, rco); + int b= R.samples->centmask[mask]; + x= x+R.samples->centLut[b & 15]; + y= y+R.samples->centLut[b>>4]; + shadepixel(pa, x, y, z, facenr, mask, fcol, rco); } } - else shadepixel(x, y, z, facenr, mask, fcol, rco); + else shadepixel(pa, x, y, z, facenr, mask, fcol, rco); } static int addtosampcol(float *sampcol, float *fcol, int mask) @@ -2747,29 +2071,31 @@ static int addtosampcol(float *sampcol, float *fcol, int mask) return retval; } -/* - * renders when needed the Abuffer with faces stored in pixels, returns 1 scanline rendered - */ - #define MAX_ZROW 1000 -void abufsetrow(float *acolrow, int y) +/* main render call to fill in pass the full transparent layer */ + +void zbuffer_transp_shade(RenderPart *pa, float *pass) { - extern SDL_mutex *render_abuf_lock; // initrender.c + APixstr *APixbuf; /* Zbuffer: linked list of face samples */ APixstr *ap, *apn; - float *col, fcol[4], tempcol[4], sampcol[16*4], *scol, accumcol[4]; - float ys, fac, alpha[32]; - int x, part, a, zrow[MAX_ZROW][3], totface, nr; + ListBase apsmbase={NULL, NULL}; + float col[4], fcol[4], tempcol[4], sampcol[16*4], *scol, accumcol[4]; + float fac, alpha[32]; + int x, y, a, zrow[MAX_ZROW][3], totface, nr; int sval; - if(y<0) return; + /* looks nicer for calling code */ + if(R.test_break()) + return; + + APixbuf= RE_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf"); + if(R.osa>16) { printf("abufsetrow: osa too large\n"); G.afbreek= 1; return; } - - //R.flag &= ~R_LAMPHALO; - + /* alpha LUT */ if(R.r.mode & R_OSA ) { fac= (1.0/(float)R.osa); @@ -2777,146 +2103,132 @@ void abufsetrow(float *acolrow, int y) alpha[a]= (float)a*fac; } } - - if(R.r.mode & R_THREADS) { - /* lock thread if... */ - if(y>Aminy+2 && y<Amaxy-2); - else { - if(render_abuf_lock) SDL_mutexP(render_abuf_lock); - } - } - /* does a pixbuf has to be created? */ - if(y<Aminy || y>Amaxy) { - part= (y/ABUFPART); - Aminy= part*ABUFPART; - Amaxy= Aminy+ABUFPART-1; - if(Amaxy>=R.recty) Amaxy= R.recty-1; - freepsA(); - zbuffer_abuf(); - } - - /* render row */ - col= acolrow; - memset(col, 0, 4*sizeof(float)*R.rectx); - ap= APixbuf + R.rectx*(y-Aminy); - ys= y; - - for(x=0; x<R.rectx; x++, col+=4, ap++) { - if(ap->p[0]) { - /* sort in z */ - totface= 0; - apn= ap; - while(apn) { - for(a=0; a<4; a++) { - if(apn->p[a]) { - zrow[totface][0]= apn->z[a]; - zrow[totface][1]= apn->p[a]; - zrow[totface][2]= apn->mask[a]; - totface++; - if(totface>=MAX_ZROW) totface= MAX_ZROW-1; + /* fill the Apixbuf */ + zbuffer_abuf(pa, APixbuf, &apsmbase); + + /* render tile */ + ap= APixbuf; + + for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { + for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ap++, pass+=4) { + + if(ap->p[0]) { + /* sort in z */ + totface= 0; + apn= ap; + while(apn) { + for(a=0; a<4; a++) { + if(apn->p[a]) { + zrow[totface][0]= apn->z[a]; + zrow[totface][1]= apn->p[a]; + zrow[totface][2]= apn->mask[a]; + totface++; + if(totface>=MAX_ZROW) totface= MAX_ZROW-1; + } + else break; } - else break; + apn= apn->next; } - apn= apn->next; - } - - if(totface==1) { - shadetrapixel((float)x, (float)y, zrow[0][0], zrow[0][1], zrow[0][2], fcol); - - nr= count_mask(zrow[0][2]); - if( (R.r.mode & R_OSA) && nr<R.osa) { - fac= alpha[ nr ]; - col[0]= (fcol[0]*fac); - col[1]= (fcol[1]*fac); - col[2]= (fcol[2]*fac); - col[3]= (fcol[3]*fac); + if(totface==1) { + + shadetrapixel(pa, (float)x, (float)y, zrow[0][0], zrow[0][1], zrow[0][2], fcol); + + nr= count_mask(zrow[0][2]); + if( (R.r.mode & R_OSA) && nr<R.osa) { + fac= alpha[ nr ]; + col[0]= (fcol[0]*fac); + col[1]= (fcol[1]*fac); + col[2]= (fcol[2]*fac); + col[3]= (fcol[3]*fac); + } + else { + col[0]= fcol[0]; + col[1]= fcol[1]; + col[2]= fcol[2]; + col[3]= fcol[3]; + } } else { - col[0]= fcol[0]; - col[1]= fcol[1]; - col[2]= fcol[2]; - col[3]= fcol[3]; - } - } - else { - - if(totface==2) { - if(zrow[0][0] < zrow[1][0]) { - a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a; - a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a; - a= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= a; + col[0]= col[1]= col[2]= col[3]= 0.0f; + + if(totface==2) { + if(zrow[0][0] < zrow[1][0]) { + a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a; + a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a; + a= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= a; + } + + } + else { /* totface>2 */ + qsort(zrow, totface, sizeof(int)*3, vergzvlak); } - - } - else { /* totface>2 */ - qsort(zrow, totface, sizeof(int)*3, vergzvlak); - } - - /* join when pixels are adjacent */ - - while(totface>0) { - totface--; - shadetrapixel((float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol); + /* join when pixels are adjacent */ - a= count_mask(zrow[totface][2]); - if( (R.r.mode & R_OSA ) && a<R.osa) { - if(totface>0) { - memset(sampcol, 0, 4*sizeof(float)*R.osa); - sval= addtosampcol(sampcol, fcol, zrow[totface][2]); - - /* sval==0: alpha completely full */ - while( (sval != 0) && (totface>0) ) { - a= count_mask(zrow[totface-1][2]); - if(a==R.osa) break; - totface--; - - shadetrapixel((float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol); + while(totface>0) { + totface--; + + shadetrapixel(pa, (float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol); + + a= count_mask(zrow[totface][2]); + if( (R.r.mode & R_OSA ) && a<R.osa) { + if(totface>0) { + memset(sampcol, 0, 4*sizeof(float)*R.osa); sval= addtosampcol(sampcol, fcol, zrow[totface][2]); + + /* sval==0: alpha completely full */ + while( (sval != 0) && (totface>0) ) { + a= count_mask(zrow[totface-1][2]); + if(a==R.osa) break; + totface--; + + shadetrapixel(pa, (float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol); + sval= addtosampcol(sampcol, fcol, zrow[totface][2]); + } + + scol= sampcol; + accumcol[0]= scol[0]; accumcol[1]= scol[1]; + accumcol[2]= scol[2]; accumcol[3]= scol[3]; + scol+= 4; + for(a=1; a<R.osa; a++, scol+=4) { + accumcol[0]+= scol[0]; accumcol[1]+= scol[1]; + accumcol[2]+= scol[2]; accumcol[3]+= scol[3]; + } + tempcol[0]= accumcol[0]/R.osa; + tempcol[1]= accumcol[1]/R.osa; + tempcol[2]= accumcol[2]/R.osa; + tempcol[3]= accumcol[3]/R.osa; + + addAlphaUnderFloat(col, tempcol); + } - scol= sampcol; - accumcol[0]= scol[0]; accumcol[1]= scol[1]; - accumcol[2]= scol[2]; accumcol[3]= scol[3]; - scol+= 4; - for(a=1; a<R.osa; a++, scol+=4) { - accumcol[0]+= scol[0]; accumcol[1]+= scol[1]; - accumcol[2]+= scol[2]; accumcol[3]+= scol[3]; + else { + fac= alpha[a]; + fcol[0]= (fcol[0]*fac); + fcol[1]= (fcol[1]*fac); + fcol[2]= (fcol[2]*fac); + fcol[3]= (fcol[3]*fac); + addAlphaUnderFloat(col, fcol); } - tempcol[0]= accumcol[0]/R.osa; - tempcol[1]= accumcol[1]/R.osa; - tempcol[2]= accumcol[2]/R.osa; - tempcol[3]= accumcol[3]/R.osa; - - addAlphaUnderFloat(col, tempcol); - - } - else { - fac= alpha[a]; - fcol[0]= (fcol[0]*fac); - fcol[1]= (fcol[1]*fac); - fcol[2]= (fcol[2]*fac); - fcol[3]= (fcol[3]*fac); - addAlphaUnderFloat(col, fcol); - } - } - else addAlphaUnderFloat(col, fcol); - - if(col[3]>=0.999) break; + } + else addAlphaUnderFloat(col, fcol); /* no osa or full pixel with same face? */ + + if(col[3]>=0.999) break; + } } + if(col[3]!=0.0) addAlphaOverFloat(pass, col); } } } - if(R.r.mode & R_THREADS) { - if(y>Aminy+2 && y<Amaxy-2); - else { - if(render_abuf_lock) SDL_mutexV(render_abuf_lock); - } - } + RE_freeN(APixbuf); + freepsA(&apsmbase); + } + /* end of zbuf.c */ diff --git a/source/blender/render/intern/source/zbufferdatastruct.c b/source/blender/render/intern/source/zbufferdatastruct.c deleted file mode 100644 index d237b7d64f4..00000000000 --- a/source/blender/render/intern/source/zbufferdatastruct.c +++ /dev/null @@ -1,310 +0,0 @@ -/** - * zbufferdatastruct.c - * - * $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 ***** - * - * The z buffer consists of an array of lists. Each list holds the objects - * behind a pixel. These can be sorted for closest distance. Per object, - * we store: - * - object type - * - object index - * - minimum distance - * - maximum distance - * - oversample flags - * - * The buffer was created to fit the new unified renderpipeline. We might - * turn it into an object later on. - * - * The z buffer has an unlimited depth. The oversampling code chops at a - * certain number of faces. This number is defined in - * vanillaRenderPipe_types.h - * - * Version 1 of the z buffer inserted objects by means of linear - * search: we walk along the list until we find the right object or - * until we have to insert a new one. This is terribly inefficient - * when we are dealing with large numbers of objects. Can we find a - * better solution here? - * - * Because we treat halos as billboards, we optimize halo - * insertion. For this purpose the fillFlatObject() functions have - * been implemented. */ - -#include <string.h> - -#include "MEM_guardedalloc.h" -#include "zbufferdatastruct.h" -#include "vanillaRenderPipe_types.h" -#include "render.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/* if defined: all jittersamples are stored individually. _very_ serious */ -/* performance hit ! also gives some buffer size problems in big scenes */ -#define RE_INDIVIDUAL_SUBPIXELS - -/* ------------------------------------------------------------------------- */ - -static RE_APixstrExtMain RE_apsemfirst; /* pixstr bookkeeping var */ -static short RE_apsemteller = 0; /* pixstr bookkeeping var */ -static int RE_zbufferwidth; /* width of the z-buffer (pixels) */ -RE_APixstrExt *APixbufExt; /* Zbuffer: linked list of face, halo indices */ - -/*-RE_APixstrExt------------------------------------------------------------ */ - -void initZbuffer(int width) -{ - APixbufExt = MEM_callocN(RE_ZBUFLEN * width * sizeof(RE_APixstrExt), - "APixbufExt"); - RE_zbufferwidth = width; - RE_apsemteller = 0; - RE_apsemfirst.next = NULL; - RE_apsemfirst.ps = NULL; -} /* end of RE_APixstrExt *initZbufferDataStruct() */ - -/* ------------------------------------------------------------------------- */ - -void freeZbuffer(void) -{ - if (APixbufExt) MEM_freeN(APixbufExt); - freepseA(); -} /* end of void freeZbuffer(void) */ - -/* ------------------------------------------------------------------------- */ - -void resetZbuffer(void) -{ - int len; - - freepseA(); - len = sizeof(RE_APixstrExt) * RE_zbufferwidth * RE_ZBUFLEN; - memset(APixbufExt, 0, len); -} /* end of void resetZbuffer(void) */ - -/* ------------------------------------------------------------------------- */ - -RE_APixstrExt *addpsemainA() -{ - RE_APixstrExtMain *psm; - - psm= &RE_apsemfirst; - - while(psm->next) { - psm= psm->next; - } - - psm->next= MEM_callocN(sizeof(RE_APixstrExtMain), "addpsemainA"); - - psm= psm->next; - - /* Initialise the new structure to safe values. Memory that is newly */ - /* allocated must be zero... Not sure if that happens everywhere now.*/ - psm->next=0; - psm->ps= MEM_callocN(4096*sizeof(RE_APixstrExt),"pixstrext"); - RE_apsemteller= 0; - - return psm->ps; -} /* End of RE_APixstrExt *addpsemainA() */ - -/* ------------------------------------------------------------------------- */ - -void freepseA() -{ - RE_APixstrExtMain *psm, *next; - - psm= &RE_apsemfirst; - - while(psm) { - next= psm->next; - if(psm->ps) { - MEM_freeN(psm->ps); - psm->ps= 0; - } - if(psm!= &RE_apsemfirst) MEM_freeN(psm); - psm= next; - } - - RE_apsemfirst.next= 0; - RE_apsemfirst.ps= 0; - RE_apsemteller= 0; -} /* End of void freepseA() */ - -/* ------------------------------------------------------------------------- */ - -RE_APixstrExt *addpseA(void) -{ - static RE_APixstrExt *prev; - - /* eerste PS maken */ - if((RE_apsemteller & 4095)==0) prev= addpsemainA(); - else prev++; - RE_apsemteller++; - - return prev; -} /* End of RE_APixstrExt *addpseA(void) */ - -/* ------------------------------------------------------------------------- */ - -void insertObject(int apteller, - int obindex, - int obtype, - int dist, - int mask) -{ - /* Guard the insertion if needed? */ - RE_APixstrExt* apn = &APixbufExt[apteller]; - int all_subpixels= 0; // not used now... (ton) - - while(apn) { - - if(apn->t[0] == RE_NONE) { - apn->p[0] = obindex; apn->t[0] = obtype; - apn->zmin[0] = dist; apn->zmax[0] = dist; - apn->mask[0] = mask; - break; - } - else if(all_subpixels==0) { - if((apn->p[0] == obindex) && (apn->t[0] & obtype)) { - if(dist < apn->zmin[0]) apn->zmin[0] = dist; - else if(dist > apn->zmax[0]) apn->zmax[0] = dist; - apn->mask[0]|= mask; - break; - } - } - - if(apn->t[1] == RE_NONE) { - apn->p[1] = obindex; apn->t[1] = obtype; - apn->zmin[1] = dist; apn->zmax[1] = dist; - apn->mask[1] = mask; - break; - } - else if(all_subpixels==0) { - if((apn->p[1] == obindex) && (apn->t[1] & obtype)) { - if(dist < apn->zmin[1]) apn->zmin[1] = dist; - else if(dist > apn->zmax[1]) apn->zmax[1] = dist; - apn->mask[1]|= mask; - break; - } - } - - if(apn->t[2] == RE_NONE) { - apn->p[2] = obindex; apn->t[2] = obtype; - apn->zmin[2] = dist; apn->zmax[2] = dist; - apn->mask[2] = mask; - break; - } - else if(all_subpixels==0) { - if((apn->p[2] == obindex) && (apn->t[2] & obtype)) { - if(dist < apn->zmin[2]) apn->zmin[2] = dist; - else if(dist > apn->zmax[2]) apn->zmax[2] = dist; - apn->mask[2]|= mask; - break; - } - } - - if(apn->t[3] == RE_NONE) { - apn->p[3] = obindex; apn->t[3] = obtype; - apn->zmin[3] = dist; apn->zmax[3] = dist; - apn->mask[3] = mask; - break; - } - else if(all_subpixels==0) { - if((apn->p[3] == obindex) && (apn->t[3] & obtype)) { - if(dist < apn->zmin[3]) apn->zmin[3] = dist; - else if(dist > apn->zmax[3]) apn->zmax[3] = dist; - apn->mask[3]|= mask; - break; - } - } - - if(apn->next==0) apn->next= addpseA(); - apn= apn->next; - } -} - -/* ------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------- */ - -/* This function might be helped by an end-of-list marker */ -void insertFlatObjectNoOsa(RE_APixstrExt *ap, - int obindex, - int obtype, - int dist, - int mask) -{ - int counter=0; - - while(ap) { - if(ap->t[0] == RE_NONE) { - ap->p[0] = obindex; ap->zmin[0] = dist; - ap->zmax[0] = dist; ap->mask[0] = mask; - ap->t[0] = obtype; - break; - } - else if(ap->t[0] & RE_SOLID) if( dist > ap->zmin[0] ) break; - - if(ap->t[1] == RE_NONE) { - ap->p[1] = obindex; ap->zmin[1] = dist; - ap->zmax[1] = dist; ap->mask[1] = mask; - ap->t[1] = obtype; - break; - } - else if(ap->t[1] & RE_SOLID) if( dist > ap->zmin[1] ) break; - - if(ap->t[2] == RE_NONE) { - ap->p[2] = obindex; ap->zmin[2] = dist; - ap->zmax[2] = dist; ap->mask[2] = mask; - ap->t[2] = obtype; - break; - } - else if(ap->t[2] & RE_SOLID) if( dist > ap->zmin[2] ) break; - - if(ap->t[3] == RE_NONE) { - ap->p[3] = obindex; ap->zmin[3] = dist; - ap->zmax[3] = dist; ap->mask[3] = mask; - ap->t[3] = obtype; - break; - } - else if(ap->t[3] & RE_SOLID) if( dist > ap->zmin[3] ) break; - - counter+= 4; - if(counter > RE_MAX_FACES_PER_PIXEL) break; - - if(ap->next==0) ap->next= addpseA(); - ap= ap->next; - }; -} - -/* ------------------------------------------------------------------------- */ - -/* EOF */ |