So! Finally time to work on finishing render pipeline project.
This commit brings back: - Field Render - MBlur Render (old style) - Border render with or without cropping Note: Field Render is not supported in Compositor yet. Blurring or filter will destroy field information. Both MotionBlur as Field render are done before Compositing happens. Fixes: - The "Save Buffers" option only worked on single frame renders, not for Anim render. - Found an un-initalized variable in Render initialize... this might have caused the unknown random crashes with render. Code restructure: Cleaned up names and calls throughout the pipeline, more clearly telling what goes on in functions. This is visible in the updated first image of the Wiki doc: http://mediawiki.blender.org/index.php/BlenderDev/RenderPipeline
This commit is contained in:
@@ -74,6 +74,7 @@ struct Object *copy_object(struct Object *ob);
|
|||||||
void expand_local_object(struct Object *ob);
|
void expand_local_object(struct Object *ob);
|
||||||
void make_local_object(struct Object *ob);
|
void make_local_object(struct Object *ob);
|
||||||
void set_mblur_offs(float blur);
|
void set_mblur_offs(float blur);
|
||||||
|
void set_field_offs(float field);
|
||||||
void disable_speed_curve(int val);
|
void disable_speed_curve(int val);
|
||||||
|
|
||||||
float bsystem_time(struct Object *ob, struct Object *par, float cfra, float ofs);
|
float bsystem_time(struct Object *ob, struct Object *par, float cfra, float ofs);
|
||||||
|
|||||||
@@ -752,15 +752,11 @@ float get_action_frame_inv(Object *ob, float cframe)
|
|||||||
static float nla_time(float cfra, float unit)
|
static float nla_time(float cfra, float unit)
|
||||||
{
|
{
|
||||||
extern float bluroffs; // bad construct, borrowed from object.c for now
|
extern float bluroffs; // bad construct, borrowed from object.c for now
|
||||||
|
extern float fieldoffs;
|
||||||
|
|
||||||
/* 2nd field */
|
/* motion blur & fields */
|
||||||
// if(R.flag & R_SEC_FIELD) {
|
cfra+= unit*(bluroffs+fieldoffs);
|
||||||
// if(R.r.mode & R_FIELDSTILL); else cfra+= 0.5f*unit;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* motion blur */
|
|
||||||
cfra+= unit*bluroffs;
|
|
||||||
|
|
||||||
/* global time */
|
/* global time */
|
||||||
cfra*= G.scene->r.framelen;
|
cfra*= G.scene->r.framelen;
|
||||||
|
|
||||||
|
|||||||
@@ -183,14 +183,12 @@ int fluidsim_ar[FLUIDSIM_TOTIPO]= {
|
|||||||
|
|
||||||
float frame_to_float(int cfra) /* see also bsystem_time in object.c */
|
float frame_to_float(int cfra) /* see also bsystem_time in object.c */
|
||||||
{
|
{
|
||||||
extern float bluroffs; /* object.c */
|
extern float bluroffs; /* bad stuff borrowed from object.c */
|
||||||
|
extern float fieldoffs;
|
||||||
float ctime;
|
float ctime;
|
||||||
|
|
||||||
ctime= (float)cfra;
|
ctime= (float)cfra;
|
||||||
// if(R.flag & R_SEC_FIELD) {
|
ctime+= bluroffs+fieldoffs;
|
||||||
// if((R.r.mode & R_FIELDSTILL)==0) ctime+= 0.5;
|
|
||||||
// }
|
|
||||||
ctime+= bluroffs;
|
|
||||||
ctime*= G.scene->r.framelen;
|
ctime*= G.scene->r.framelen;
|
||||||
|
|
||||||
return ctime;
|
return ctime;
|
||||||
|
|||||||
@@ -938,6 +938,9 @@ static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in,
|
|||||||
stackbuf->rect= rl->rectf;
|
stackbuf->rect= rl->rectf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stackbuf->xof= rr->xof;
|
||||||
|
stackbuf->yof= rr->yof;
|
||||||
|
|
||||||
/* put on stack */
|
/* put on stack */
|
||||||
out[RRES_OUT_IMAGE]->data= stackbuf;
|
out[RRES_OUT_IMAGE]->data= stackbuf;
|
||||||
|
|
||||||
|
|||||||
@@ -997,15 +997,20 @@ void make_local_object(Object *ob)
|
|||||||
|
|
||||||
/* there is also a timing calculation in drawobject() */
|
/* there is also a timing calculation in drawobject() */
|
||||||
|
|
||||||
float bluroffs= 0.0;
|
float bluroffs= 0.0f, fieldoffs= 0.0f;
|
||||||
int no_speed_curve= 0;
|
int no_speed_curve= 0;
|
||||||
|
|
||||||
/* ugly call from render */
|
/* ugly calls from render */
|
||||||
void set_mblur_offs(float blur)
|
void set_mblur_offs(float blur)
|
||||||
{
|
{
|
||||||
bluroffs= blur;
|
bluroffs= blur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_field_offs(float field)
|
||||||
|
{
|
||||||
|
fieldoffs= field;
|
||||||
|
}
|
||||||
|
|
||||||
void disable_speed_curve(int val)
|
void disable_speed_curve(int val)
|
||||||
{
|
{
|
||||||
no_speed_curve= val;
|
no_speed_curve= val;
|
||||||
@@ -1016,12 +1021,7 @@ float bsystem_time(Object *ob, Object *par, float cfra, float ofs)
|
|||||||
{
|
{
|
||||||
/* returns float ( see frame_to_float in ipo.c) */
|
/* returns float ( see frame_to_float in ipo.c) */
|
||||||
|
|
||||||
/* 2nd field */
|
cfra+= bluroffs+fieldoffs;
|
||||||
// if(R.flag & R_SEC_FIELD) {
|
|
||||||
// if(R.r.mode & R_FIELDSTILL); else cfra+= .5;
|
|
||||||
// }
|
|
||||||
|
|
||||||
cfra+= bluroffs;
|
|
||||||
|
|
||||||
/* global time */
|
/* global time */
|
||||||
cfra*= G.scene->r.framelen;
|
cfra*= G.scene->r.framelen;
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ typedef struct Scene {
|
|||||||
#define R_RADIO 0x0100
|
#define R_RADIO 0x0100
|
||||||
#define R_BORDER 0x0200
|
#define R_BORDER 0x0200
|
||||||
#define R_PANORAMA 0x0400
|
#define R_PANORAMA 0x0400
|
||||||
/* was moviecrop 0x0800 */
|
#define R_CROP 0x0800
|
||||||
#define R_COSMO 0x1000
|
#define R_COSMO 0x1000
|
||||||
#define R_ODDFIELD 0x2000
|
#define R_ODDFIELD 0x2000
|
||||||
#define R_MBLUR 0x4000
|
#define R_MBLUR 0x4000
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ typedef struct RenderResult {
|
|||||||
|
|
||||||
/* coordinates within final image (after cropping) */
|
/* coordinates within final image (after cropping) */
|
||||||
rcti tilerect;
|
rcti tilerect;
|
||||||
|
/* offset to apply to get a border render in full image */
|
||||||
|
int xof, yof;
|
||||||
|
|
||||||
/* the main buffers */
|
/* the main buffers */
|
||||||
ListBase layers;
|
ListBase layers;
|
||||||
|
|||||||
@@ -347,7 +347,6 @@ typedef struct LampRen
|
|||||||
#define R_HALO 2
|
#define R_HALO 2
|
||||||
#define R_SEC_FIELD 4
|
#define R_SEC_FIELD 4
|
||||||
#define R_LAMPHALO 8
|
#define R_LAMPHALO 8
|
||||||
#define R_FILEBUFFER 16
|
|
||||||
|
|
||||||
/* vlakren->flag (vlak = face in dutch) char!!! */
|
/* vlakren->flag (vlak = face in dutch) char!!! */
|
||||||
#define R_SMOOTH 1
|
#define R_SMOOTH 1
|
||||||
|
|||||||
@@ -464,6 +464,8 @@ void RE_SetCamera(Render *re, Object *camera)
|
|||||||
|
|
||||||
/* question mark */
|
/* question mark */
|
||||||
re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp);
|
re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp);
|
||||||
|
if(re->r.mode & R_FIELDS)
|
||||||
|
re->ycor *= 2.0f;
|
||||||
|
|
||||||
if(camera->type==OB_CAMERA) {
|
if(camera->type==OB_CAMERA) {
|
||||||
cam= camera->data;
|
cam= camera->data;
|
||||||
@@ -603,17 +605,19 @@ void initparts(Render *re)
|
|||||||
xparts= re->r.xparts;
|
xparts= re->r.xparts;
|
||||||
yparts= re->r.yparts;
|
yparts= re->r.yparts;
|
||||||
|
|
||||||
/* mininum part size */
|
/* mininum part size, but for exr tile saving it was checked already */
|
||||||
if(re->r.mode & R_PANORAMA) {
|
if(!(re->r.scemode & R_EXR_TILE_FILE)) {
|
||||||
if(re->rectx/xparts < 8)
|
if(re->r.mode & R_PANORAMA) {
|
||||||
xparts= 1 + re->rectx/8;
|
if(re->rectx/xparts < 8)
|
||||||
|
xparts= 1 + re->rectx/8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(re->rectx/xparts < 64)
|
||||||
|
xparts= 1 + re->rectx/64;
|
||||||
|
|
||||||
|
if(re->recty/yparts < 64)
|
||||||
|
yparts= 1 + re->recty/64;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if(re->rectx/xparts < 64)
|
|
||||||
xparts= 1 + re->rectx/64;
|
|
||||||
|
|
||||||
if(re->recty/yparts < 64)
|
|
||||||
yparts= 1 + re->recty/64;
|
|
||||||
|
|
||||||
/* part size */
|
/* part size */
|
||||||
partx= re->rectx/xparts;
|
partx= re->rectx/xparts;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
|
#include "BKE_object.h"
|
||||||
#include "BKE_scene.h"
|
#include "BKE_scene.h"
|
||||||
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
|
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
|
||||||
|
|
||||||
@@ -286,8 +287,6 @@ static void render_unique_exr_name(Render *re, char *str)
|
|||||||
else
|
else
|
||||||
BLI_make_file_string("/", str, U.tempdir, name);
|
BLI_make_file_string("/", str, U.tempdir, name);
|
||||||
|
|
||||||
printf("exr file %s\n", str);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
|
static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
|
||||||
@@ -342,11 +341,12 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RR_USEMEM 0
|
||||||
/* called by main render as well for parts */
|
/* called by main render as well for parts */
|
||||||
/* will read info from Render *re to define layers */
|
/* will read info from Render *re to define layers */
|
||||||
/* called in threads */
|
/* called in threads */
|
||||||
/* re->winx,winy is coordinate space of entire image, partrct the part within */
|
/* re->winx,winy is coordinate space of entire image, partrct the part within */
|
||||||
static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
|
static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int savebuffers)
|
||||||
{
|
{
|
||||||
RenderResult *rr;
|
RenderResult *rr;
|
||||||
RenderLayer *rl;
|
RenderLayer *rl;
|
||||||
@@ -371,8 +371,7 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
|
|||||||
rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
|
rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
|
||||||
rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
|
rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
|
||||||
|
|
||||||
/* this flag needs cleared immediate after result was made */
|
if(savebuffers) {
|
||||||
if(re->flag & R_FILEBUFFER) {
|
|
||||||
rr->exrhandle= IMB_exr_get_handle();
|
rr->exrhandle= IMB_exr_get_handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,16 +433,20 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
|
|||||||
re->r.actlay= 0;
|
re->r.actlay= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* border render; calculate offset for use in compositor. compo is centralized coords */
|
||||||
|
rr->xof= re->disprect.xmin + (re->disprect.xmax - re->disprect.xmin)/2 - re->winx/2;
|
||||||
|
rr->yof= re->disprect.ymin + (re->disprect.ymax - re->disprect.ymin)/2 - re->winy/2;
|
||||||
|
|
||||||
return rr;
|
return rr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int render_result_needs_vector(Render *re)
|
static int render_scene_needs_vector(Render *re)
|
||||||
{
|
{
|
||||||
if(re->r.scemode & R_DOCOMP) {
|
if(re->r.scemode & R_DOCOMP) {
|
||||||
RenderLayer *rl;
|
SceneRenderLayer *srl;
|
||||||
|
|
||||||
for(rl= re->result->layers.first; rl; rl= rl->next)
|
for(srl= re->scene->r.layers.first; srl; srl= srl->next)
|
||||||
if(rl->passflag & SCE_PASS_VECTOR)
|
if(srl->passflag & SCE_PASS_VECTOR)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -541,7 +544,6 @@ static void save_render_result_tile(Render *re, RenderPart *pa)
|
|||||||
|
|
||||||
party= rrpart->tilerect.ymin + rrpart->crop;
|
party= rrpart->tilerect.ymin + rrpart->crop;
|
||||||
partx= rrpart->tilerect.xmin + rrpart->crop;
|
partx= rrpart->tilerect.xmin + rrpart->crop;
|
||||||
|
|
||||||
IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
|
IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
|
||||||
|
|
||||||
BLI_unlock_thread(LOCK_CUSTOM1);
|
BLI_unlock_thread(LOCK_CUSTOM1);
|
||||||
@@ -557,7 +559,7 @@ static void read_render_result(Render *re)
|
|||||||
char str[FILE_MAXDIR+FILE_MAXFILE];
|
char str[FILE_MAXDIR+FILE_MAXFILE];
|
||||||
|
|
||||||
free_render_result(re->result);
|
free_render_result(re->result);
|
||||||
re->result= new_render_result(re, &re->disprect, 0);
|
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
|
|
||||||
render_unique_exr_name(re, str);
|
render_unique_exr_name(re, str);
|
||||||
if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
|
if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
|
||||||
@@ -762,7 +764,7 @@ void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect
|
|||||||
re->recty= disprect->ymax-disprect->ymin;
|
re->recty= disprect->ymax-disprect->ymin;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
re->disprect.xmin= re->disprect.xmax= 0;
|
re->disprect.xmin= re->disprect.ymin= 0;
|
||||||
re->disprect.xmax= winx;
|
re->disprect.xmax= winx;
|
||||||
re->disprect.ymax= winy;
|
re->disprect.ymax= winy;
|
||||||
re->rectx= winx;
|
re->rectx= winx;
|
||||||
@@ -784,8 +786,11 @@ void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect
|
|||||||
/* always call, checks for gamma, gamma tables and jitter too */
|
/* always call, checks for gamma, gamma tables and jitter too */
|
||||||
make_sample_tables(re);
|
make_sample_tables(re);
|
||||||
|
|
||||||
|
/* make empty render result, so display callbacks can initialize */
|
||||||
free_render_result(re->result);
|
free_render_result(re->result);
|
||||||
re->result= new_render_result(re, &re->disprect, 0);
|
re->result= MEM_callocN(sizeof(RenderResult), "new render result");
|
||||||
|
re->result->rectx= re->rectx;
|
||||||
|
re->result->recty= re->recty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,7 +802,7 @@ void RE_SetDispRect (struct Render *re, rcti *disprect)
|
|||||||
|
|
||||||
/* initialize render result */
|
/* initialize render result */
|
||||||
free_render_result(re->result);
|
free_render_result(re->result);
|
||||||
re->result= new_render_result(re, &re->disprect, 0);
|
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
|
void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
|
||||||
@@ -885,7 +890,7 @@ static void *do_part_thread(void *pa_v)
|
|||||||
/* need to return nicely all parts on esc */
|
/* need to return nicely all parts on esc */
|
||||||
if(R.test_break()==0) {
|
if(R.test_break()==0) {
|
||||||
|
|
||||||
pa->result= new_render_result(&R, &pa->disprect, pa->crop);
|
pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM);
|
||||||
|
|
||||||
if(R.osa)
|
if(R.osa)
|
||||||
zbufshadeDA_tile(pa);
|
zbufshadeDA_tile(pa);
|
||||||
@@ -904,13 +909,17 @@ static void *do_part_thread(void *pa_v)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns with render result filled, not threaded */
|
/* returns with render result filled, not threaded, used for preview now only */
|
||||||
static void render_tile_processor(Render *re, int firsttile)
|
static void render_tile_processor(Render *re, int firsttile)
|
||||||
{
|
{
|
||||||
RenderPart *pa;
|
RenderPart *pa;
|
||||||
|
|
||||||
if(re->test_break())
|
if(re->test_break())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* first step; the entire render result, no exr saving here */
|
||||||
|
free_render_result(re->result);
|
||||||
|
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
|
|
||||||
re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
|
re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
|
||||||
re->stats_draw(&re->i);
|
re->stats_draw(&re->i);
|
||||||
@@ -1068,10 +1077,14 @@ static void threaded_tile_processor(Render *re)
|
|||||||
{
|
{
|
||||||
ListBase threads;
|
ListBase threads;
|
||||||
RenderPart *pa, *nextpa;
|
RenderPart *pa, *nextpa;
|
||||||
RenderResult *rr= re->result;
|
RenderResult *rr;
|
||||||
rctf viewplane= re->viewplane;
|
rctf viewplane= re->viewplane;
|
||||||
int maxthreads, rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
|
int maxthreads, rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
|
||||||
|
|
||||||
|
/* first step; the entire render result, or prepare exr buffer saving */
|
||||||
|
free_render_result(re->result);
|
||||||
|
rr= re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
|
||||||
|
|
||||||
if(rr==NULL)
|
if(rr==NULL)
|
||||||
return;
|
return;
|
||||||
if(re->test_break())
|
if(re->test_break())
|
||||||
@@ -1082,6 +1095,8 @@ static void threaded_tile_processor(Render *re)
|
|||||||
if(rr->exrhandle) {
|
if(rr->exrhandle) {
|
||||||
char str[FILE_MAXDIR+FILE_MAXFILE];
|
char str[FILE_MAXDIR+FILE_MAXFILE];
|
||||||
render_unique_exr_name(re, str);
|
render_unique_exr_name(re, str);
|
||||||
|
printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
|
||||||
|
|
||||||
IMB_exrtile_begin_write(rr->exrhandle, str, rr->rectx, rr->recty, rr->rectx/re->xparts, rr->recty/re->yparts);
|
IMB_exrtile_begin_write(rr->exrhandle, str, rr->rectx, rr->recty, rr->rectx/re->xparts, rr->recty/re->yparts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,13 +1206,13 @@ void RE_TileProcessor(Render *re, int firsttile)
|
|||||||
|
|
||||||
/* ************ This part uses API, for rendering Blender scenes ********** */
|
/* ************ This part uses API, for rendering Blender scenes ********** */
|
||||||
|
|
||||||
void render_one_frame(Render *re)
|
static void do_render_3d(Render *re)
|
||||||
{
|
{
|
||||||
|
|
||||||
// re->cfra= cfra; /* <- unused! */
|
// re->cfra= cfra; /* <- unused! */
|
||||||
|
|
||||||
/* make render verts/faces/halos/lamps */
|
/* make render verts/faces/halos/lamps */
|
||||||
if(render_result_needs_vector(re))
|
if(render_scene_needs_vector(re))
|
||||||
RE_Database_FromScene_Vectors(re, re->scene);
|
RE_Database_FromScene_Vectors(re, re->scene);
|
||||||
else
|
else
|
||||||
RE_Database_FromScene(re, re->scene, 1);
|
RE_Database_FromScene(re, re->scene, 1);
|
||||||
@@ -1208,19 +1223,221 @@ void render_one_frame(Render *re)
|
|||||||
RE_Database_Free(re);
|
RE_Database_Free(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
/* called by blur loop, accumulate renderlayers */
|
||||||
/* accumulates osa frames */
|
static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
|
||||||
static void do_render_blurred(Render *re, float frame)
|
|
||||||
{
|
{
|
||||||
|
float mfac= 1.0f - blurfac;
|
||||||
|
int a, b, stride= channels*rr->rectx;
|
||||||
|
int len= stride*sizeof(float);
|
||||||
|
|
||||||
|
for(a=0; a<rr->recty; a++) {
|
||||||
|
if(blurfac==1.0f) {
|
||||||
|
memcpy(rectf, rectf1, len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float *rf= rectf, *rf1= rectf1;
|
||||||
|
|
||||||
|
for( b= rr->rectx*channels; b>0; b--, rf++, rf1++) {
|
||||||
|
rf[0]= mfac*rf[0] + blurfac*rf1[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rectf+= stride;
|
||||||
|
rectf1+= stride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* interleaves 2 frames */
|
/* called by blur loop, accumulate renderlayers */
|
||||||
static void do_render_fields(Render *re)
|
static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac)
|
||||||
{
|
{
|
||||||
|
RenderLayer *rl, *rl1;
|
||||||
|
RenderPass *rpass, *rpass1;
|
||||||
|
|
||||||
|
rl1= brr->layers.first;
|
||||||
|
for(rl= rr->layers.first; rl && rl1; rl= rl->next, rl1= rl1->next) {
|
||||||
|
|
||||||
|
/* combined */
|
||||||
|
if(rl->rectf && rl1->rectf)
|
||||||
|
addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
|
||||||
|
|
||||||
|
/* passes are allocated in sync */
|
||||||
|
rpass1= rl1->passes.first;
|
||||||
|
for(rpass= rl->passes.first; rpass && rpass1; rpass= rpass->next, rpass1= rpass1->next) {
|
||||||
|
addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
/* main blur loop, can be called by fields too */
|
||||||
|
static void do_render_blur_3d(Render *re)
|
||||||
|
{
|
||||||
|
RenderResult *rres;
|
||||||
|
float blurfac;
|
||||||
|
int blur= re->r.osa;
|
||||||
|
|
||||||
|
/* create accumulation render result */
|
||||||
|
rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
|
|
||||||
|
/* do the blur steps */
|
||||||
|
while(blur--) {
|
||||||
|
set_mblur_offs( re->r.blurfac*((float)(re->r.osa-blur))/(float)re->r.osa );
|
||||||
|
|
||||||
|
do_render_3d(re);
|
||||||
|
|
||||||
|
blurfac= 1.0f/(float)(re->r.osa-blur);
|
||||||
|
|
||||||
|
merge_renderresult_blur(rres, re->result, blurfac);
|
||||||
|
if(re->test_break()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* swap results */
|
||||||
|
free_render_result(re->result);
|
||||||
|
re->result= rres;
|
||||||
|
|
||||||
|
set_mblur_offs(0.0f);
|
||||||
|
|
||||||
|
/* weak... the display callback wants an active renderlayer pointer... */
|
||||||
|
re->result->renlay= render_get_active_layer(re, re->result);
|
||||||
|
re->display_draw(re->result, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* function assumes rectf1 and rectf2 to be half size of rectf */
|
||||||
|
static void interleave_rect(RenderResult *rr, float *rectf, float *rectf1, float *rectf2, int channels)
|
||||||
|
{
|
||||||
|
int a, stride= channels*rr->rectx;
|
||||||
|
int len= stride*sizeof(float);
|
||||||
|
|
||||||
|
for(a=0; a<rr->recty; a+=2) {
|
||||||
|
memcpy(rectf, rectf1, len);
|
||||||
|
rectf+= stride;
|
||||||
|
rectf1+= stride;
|
||||||
|
memcpy(rectf, rectf2, len);
|
||||||
|
rectf+= stride;
|
||||||
|
rectf2+= stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* merge render results of 2 fields */
|
||||||
|
static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, RenderResult *rr2)
|
||||||
|
{
|
||||||
|
RenderLayer *rl, *rl1, *rl2;
|
||||||
|
RenderPass *rpass, *rpass1, *rpass2;
|
||||||
|
|
||||||
|
rl1= rr1->layers.first;
|
||||||
|
rl2= rr2->layers.first;
|
||||||
|
for(rl= rr->layers.first; rl && rl1 && rl2; rl= rl->next, rl1= rl1->next, rl2= rl2->next) {
|
||||||
|
|
||||||
|
/* combined */
|
||||||
|
if(rl->rectf && rl1->rectf && rl2->rectf)
|
||||||
|
interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4);
|
||||||
|
|
||||||
|
/* passes are allocated in sync */
|
||||||
|
rpass1= rl1->passes.first;
|
||||||
|
rpass2= rl2->passes.first;
|
||||||
|
for(rpass= rl->passes.first; rpass && rpass1 && rpass2; rpass= rpass->next, rpass1= rpass1->next, rpass2= rpass2->next) {
|
||||||
|
interleave_rect(rr, rpass->rect, rpass1->rect, rpass2->rect, rpass->channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* interleaves 2 frames */
|
||||||
|
static void do_render_fields_3d(Render *re)
|
||||||
|
{
|
||||||
|
RenderResult *rr1, *rr2= NULL;
|
||||||
|
|
||||||
|
/* no render result was created, we can safely halve render y */
|
||||||
|
re->winy /= 2;
|
||||||
|
re->recty /= 2;
|
||||||
|
re->disprect.ymin /= 2;
|
||||||
|
re->disprect.ymax /= 2;
|
||||||
|
|
||||||
|
/* first field, we have to call camera routine for correct aspect and subpixel offset */
|
||||||
|
RE_SetCamera(re, re->scene->camera);
|
||||||
|
if(re->r.mode & R_MBLUR)
|
||||||
|
do_render_blur_3d(re);
|
||||||
|
else
|
||||||
|
do_render_3d(re);
|
||||||
|
rr1= re->result;
|
||||||
|
re->result= NULL;
|
||||||
|
|
||||||
|
/* second field */
|
||||||
|
if(!re->test_break()) {
|
||||||
|
re->flag |= R_SEC_FIELD;
|
||||||
|
if((re->r.mode & R_FIELDSTILL)==0)
|
||||||
|
set_field_offs(0.5f);
|
||||||
|
RE_SetCamera(re, re->scene->camera);
|
||||||
|
if(re->r.mode & R_MBLUR)
|
||||||
|
do_render_blur_3d(re);
|
||||||
|
else
|
||||||
|
do_render_3d(re);
|
||||||
|
re->flag &= ~R_SEC_FIELD;
|
||||||
|
set_field_offs(0.0f);
|
||||||
|
|
||||||
|
rr2= re->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate original height new buffers */
|
||||||
|
re->winy *= 2;
|
||||||
|
re->recty *= 2;
|
||||||
|
re->disprect.ymin *= 2;
|
||||||
|
re->disprect.ymax *= 2;
|
||||||
|
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
|
|
||||||
|
if(rr2) {
|
||||||
|
if(re->r.mode & R_ODDFIELD)
|
||||||
|
merge_renderresult_fields(re->result, rr2, rr1);
|
||||||
|
else
|
||||||
|
merge_renderresult_fields(re->result, rr1, rr2);
|
||||||
|
|
||||||
|
free_render_result(rr2);
|
||||||
|
}
|
||||||
|
free_render_result(rr1);
|
||||||
|
|
||||||
|
/* weak... the display callback wants an active renderlayer pointer... */
|
||||||
|
re->result->renlay= render_get_active_layer(re, re->result);
|
||||||
|
re->display_draw(re->result, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main render routine, no compositing */
|
||||||
|
static void do_render_fields_blur_3d(Render *re)
|
||||||
|
{
|
||||||
|
if(re->r.mode & R_FIELDS)
|
||||||
|
do_render_fields_3d(re);
|
||||||
|
else if(re->r.mode & R_MBLUR)
|
||||||
|
do_render_blur_3d(re);
|
||||||
|
else
|
||||||
|
do_render_3d(re);
|
||||||
|
|
||||||
|
/* when border render, check if we have to insert it in black */
|
||||||
|
if(re->result) {
|
||||||
|
if(re->r.mode & R_BORDER) {
|
||||||
|
if((re->r.mode & R_CROP)==0) {
|
||||||
|
RenderResult *rres;
|
||||||
|
|
||||||
|
/* sub-rect for merge call later on */
|
||||||
|
re->result->tilerect= re->disprect;
|
||||||
|
|
||||||
|
/* this copying sequence could become function? */
|
||||||
|
re->disprect.xmin= re->disprect.ymin= 0;
|
||||||
|
re->disprect.xmax= re->winx;
|
||||||
|
re->disprect.ymax= re->winy;
|
||||||
|
re->rectx= re->winx;
|
||||||
|
re->recty= re->winy;
|
||||||
|
|
||||||
|
rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
|
||||||
|
|
||||||
|
merge_render_result(rres, re->result);
|
||||||
|
free_render_result(re->result);
|
||||||
|
re->result= rres;
|
||||||
|
|
||||||
|
re->display_init(re->result);
|
||||||
|
re->display_draw(re->result, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* within context of current Render *re, render another scene.
|
/* within context of current Render *re, render another scene.
|
||||||
it uses current render image size and disprect, but doesn't execute composite
|
it uses current render image size and disprect, but doesn't execute composite
|
||||||
@@ -1230,13 +1447,9 @@ static void render_scene(Render *re, Scene *sce, int cfra)
|
|||||||
Render *resc= RE_NewRender(sce->id.name);
|
Render *resc= RE_NewRender(sce->id.name);
|
||||||
|
|
||||||
sce->r.cfra= cfra;
|
sce->r.cfra= cfra;
|
||||||
|
|
||||||
if(re->scene->r.scemode & R_EXR_TILE_FILE)
|
/* initial setup */
|
||||||
resc->flag |= R_FILEBUFFER;
|
|
||||||
|
|
||||||
/* makes render result etc */
|
|
||||||
RE_InitState(resc, &sce->r, re->winx, re->winy, &re->disprect);
|
RE_InitState(resc, &sce->r, re->winx, re->winy, &re->disprect);
|
||||||
resc->flag &= ~R_FILEBUFFER;
|
|
||||||
|
|
||||||
/* this to enable this scene to create speed vectors */
|
/* this to enable this scene to create speed vectors */
|
||||||
resc->r.scemode |= R_DOCOMP;
|
resc->r.scemode |= R_DOCOMP;
|
||||||
@@ -1256,13 +1469,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
|
|||||||
resc->test_break= re->test_break;
|
resc->test_break= re->test_break;
|
||||||
resc->stats_draw= re->stats_draw;
|
resc->stats_draw= re->stats_draw;
|
||||||
|
|
||||||
if(resc->r.mode & R_FIELDS)
|
do_render_fields_blur_3d(resc);
|
||||||
printf("No field render yet...\n"); //do_render_fields(resc);
|
|
||||||
else if(resc->r.mode & R_MBLUR)
|
|
||||||
printf("No mblur render yet...\n"); //do_render_blurred(resc, resc->r.cfra);
|
|
||||||
//else
|
|
||||||
render_one_frame(resc);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ntree_render_scenes(Render *re)
|
static void ntree_render_scenes(Render *re)
|
||||||
@@ -1304,7 +1511,7 @@ static void ntree_render_scenes(Render *re)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* helper call to detect if theres a composite with render-result node */
|
/* helper call to detect if theres a composite with render-result node */
|
||||||
int composite_needs_render(Scene *sce)
|
static int composite_needs_render(Scene *sce)
|
||||||
{
|
{
|
||||||
bNodeTree *ntree= sce->nodetree;
|
bNodeTree *ntree= sce->nodetree;
|
||||||
bNode *node;
|
bNode *node;
|
||||||
@@ -1329,60 +1536,49 @@ static void render_composit_stats(char *str)
|
|||||||
R.i.infostr= NULL;
|
R.i.infostr= NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_render_final(Render *re)
|
/* returns fully composited render-result on given time step (in RenderData) */
|
||||||
|
static void do_render_composite_fields_blur_3d(Render *re)
|
||||||
{
|
{
|
||||||
|
bNodeTree *ntree= re->scene->nodetree;
|
||||||
|
|
||||||
/* we set start time here, for main Blender loops */
|
/* we set start time here, for main Blender loops */
|
||||||
re->i.starttime= PIL_check_seconds_timer();
|
re->i.starttime= PIL_check_seconds_timer();
|
||||||
|
|
||||||
if(re->r.scemode & R_DOSEQ) {
|
if(composite_needs_render(re->scene)) {
|
||||||
if(!re->test_break())
|
/* save memory... free all cached images */
|
||||||
do_render_seq(re->result, re->r.cfra);
|
ntreeFreeCache(ntree);
|
||||||
|
|
||||||
|
/* now use renderdata and camera to set viewplane */
|
||||||
|
RE_SetCamera(re, re->scene->camera);
|
||||||
|
|
||||||
|
do_render_fields_blur_3d(re);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
bNodeTree *ntree= re->scene->nodetree;
|
/* swap render result */
|
||||||
|
if(re->r.scemode & R_SINGLE_LAYER)
|
||||||
|
pop_render_result(re);
|
||||||
|
|
||||||
|
if(!re->test_break() && ntree) {
|
||||||
|
ntreeCompositTagRender(ntree);
|
||||||
|
ntreeCompositTagAnimated(ntree);
|
||||||
|
|
||||||
if(composite_needs_render(re->scene)) {
|
if(re->r.scemode & R_DOCOMP) {
|
||||||
/* save memory... free all cached images */
|
/* checks if there are render-result nodes that need scene */
|
||||||
ntreeFreeCache(ntree);
|
if((re->r.scemode & R_SINGLE_LAYER)==0)
|
||||||
|
ntree_render_scenes(re);
|
||||||
|
|
||||||
/* now use renderdata and camera to set viewplane */
|
if(!re->test_break()) {
|
||||||
RE_SetCamera(re, re->scene->camera);
|
ntree->stats_draw= render_composit_stats;
|
||||||
|
ntree->test_break= re->test_break;
|
||||||
if(re->r.mode & R_FIELDS)
|
/* in case it was never initialized */
|
||||||
printf("No field render yet...\n"); //do_render_fields(resc);
|
R.stats_draw= re->stats_draw;
|
||||||
else if(re->r.mode & R_MBLUR)
|
|
||||||
printf("No mblur render yet...\n"); //do_render_blurred(resc, resc->r.cfra);
|
|
||||||
//else
|
|
||||||
render_one_frame(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* swap render result */
|
|
||||||
if(re->r.scemode & R_SINGLE_LAYER)
|
|
||||||
pop_render_result(re);
|
|
||||||
|
|
||||||
if(!re->test_break() && ntree) {
|
|
||||||
ntreeCompositTagRender(ntree);
|
|
||||||
ntreeCompositTagAnimated(ntree);
|
|
||||||
|
|
||||||
if(re->r.scemode & R_DOCOMP) {
|
|
||||||
/* checks if there are render-result nodes that need scene */
|
|
||||||
if((re->r.scemode & R_SINGLE_LAYER)==0)
|
|
||||||
ntree_render_scenes(re);
|
|
||||||
|
|
||||||
if(!re->test_break()) {
|
ntreeCompositExecTree(ntree, &re->r, G.background==0);
|
||||||
ntree->stats_draw= render_composit_stats;
|
ntree->stats_draw= NULL;
|
||||||
ntree->test_break= re->test_break;
|
ntree->test_break= NULL;
|
||||||
/* in case it was never initialized */
|
|
||||||
R.stats_draw= re->stats_draw;
|
|
||||||
|
|
||||||
ntreeCompositExecTree(ntree, &re->r, G.background==0);
|
|
||||||
ntree->stats_draw= NULL;
|
|
||||||
ntree->test_break= NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
|
re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
|
||||||
re->stats_draw(&re->i);
|
re->stats_draw(&re->i);
|
||||||
@@ -1390,6 +1586,17 @@ static void do_render_final(Render *re)
|
|||||||
re->display_draw(re->result, NULL);
|
re->display_draw(re->result, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* main loop: doing sequence + fields + blur + 3d render + compositing */
|
||||||
|
static void do_render_all_options(Render *re)
|
||||||
|
{
|
||||||
|
if(re->r.scemode & R_DOSEQ) {
|
||||||
|
if(!re->test_break())
|
||||||
|
do_render_seq(re->result, re->r.cfra);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
do_render_composite_fields_blur_3d(re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int is_rendering_allowed(Render *re)
|
static int is_rendering_allowed(Render *re)
|
||||||
{
|
{
|
||||||
@@ -1460,7 +1667,7 @@ static int render_initialize_from_scene(Render *re, Scene *scene)
|
|||||||
winx= (scene->r.size*scene->r.xsch)/100;
|
winx= (scene->r.size*scene->r.xsch)/100;
|
||||||
winy= (scene->r.size*scene->r.ysch)/100;
|
winy= (scene->r.size*scene->r.ysch)/100;
|
||||||
|
|
||||||
/* only in movie case we render smaller part */
|
/* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */
|
||||||
if(scene->r.mode & R_BORDER) {
|
if(scene->r.mode & R_BORDER) {
|
||||||
disprect.xmin= scene->r.border.xmin*winx;
|
disprect.xmin= scene->r.border.xmin*winx;
|
||||||
disprect.xmax= scene->r.border.xmax*winx;
|
disprect.xmax= scene->r.border.xmax*winx;
|
||||||
@@ -1476,19 +1683,22 @@ static int render_initialize_from_scene(Render *re, Scene *scene)
|
|||||||
|
|
||||||
if(scene->r.scemode & R_EXR_TILE_FILE) {
|
if(scene->r.scemode & R_EXR_TILE_FILE) {
|
||||||
int partx= winx/scene->r.xparts, party= winy/scene->r.yparts;
|
int partx= winx/scene->r.xparts, party= winy/scene->r.yparts;
|
||||||
|
|
||||||
/* stupid exr tiles dont like different sizes */
|
/* stupid exr tiles dont like different sizes */
|
||||||
if(winx != partx*scene->r.xparts || winy != party*scene->r.yparts) {
|
if(winx != partx*scene->r.xparts || winy != party*scene->r.yparts) {
|
||||||
re->error("Sorry... exr tile saving only allowed with equally sized parts");
|
re->error("Sorry... exr tile saving only allowed with equally sized parts");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
re->flag |= R_FILEBUFFER;
|
if((scene->r.mode & R_FIELDS) && (party & 1)) {
|
||||||
|
re->error("Sorry... exr tile saving only allowed with equally sized parts");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scene->r.scemode & R_SINGLE_LAYER)
|
if(scene->r.scemode & R_SINGLE_LAYER)
|
||||||
push_render_result(re);
|
push_render_result(re);
|
||||||
|
|
||||||
RE_InitState(re, &scene->r, winx, winy, &disprect);
|
RE_InitState(re, &scene->r, winx, winy, &disprect);
|
||||||
re->flag &= ~R_FILEBUFFER;
|
|
||||||
|
|
||||||
re->scene= scene;
|
re->scene= scene;
|
||||||
if(!is_rendering_allowed(re))
|
if(!is_rendering_allowed(re))
|
||||||
@@ -1510,7 +1720,7 @@ void RE_BlenderFrame(Render *re, Scene *scene, int frame)
|
|||||||
scene->r.cfra= frame;
|
scene->r.cfra= frame;
|
||||||
|
|
||||||
if(render_initialize_from_scene(re, scene)) {
|
if(render_initialize_from_scene(re, scene)) {
|
||||||
do_render_final(re);
|
do_render_all_options(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UGLY WARNING */
|
/* UGLY WARNING */
|
||||||
@@ -1604,7 +1814,7 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
|
|||||||
scene->r.cfra = nf;
|
scene->r.cfra = nf;
|
||||||
re->r.cfra= scene->r.cfra; /* weak.... */
|
re->r.cfra= scene->r.cfra; /* weak.... */
|
||||||
|
|
||||||
do_render_final(re);
|
do_render_all_options(re);
|
||||||
|
|
||||||
if(re->test_break() == 0) {
|
if(re->test_break() == 0) {
|
||||||
do_write_image_or_movie(re, scene, mh);
|
do_write_image_or_movie(re, scene, mh);
|
||||||
@@ -1616,7 +1826,7 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
|
|||||||
scene->r.cfra<=efra; scene->r.cfra++) {
|
scene->r.cfra<=efra; scene->r.cfra++) {
|
||||||
re->r.cfra= scene->r.cfra; /* weak.... */
|
re->r.cfra= scene->r.cfra; /* weak.... */
|
||||||
|
|
||||||
do_render_final(re);
|
do_render_all_options(re);
|
||||||
|
|
||||||
if(re->test_break() == 0) {
|
if(re->test_break() == 0) {
|
||||||
do_write_image_or_movie(re, scene, mh);
|
do_write_image_or_movie(re, scene, mh);
|
||||||
|
|||||||
@@ -1506,7 +1506,8 @@ static void render_panel_format(void)
|
|||||||
uiDefButBitI(block, TOG, R_COSMO, 0,"Cosmo", 1059,32,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Attempt to save SGI movies using Cosmo hardware");
|
uiDefButBitI(block, TOG, R_COSMO, 0,"Cosmo", 1059,32,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Attempt to save SGI movies using Cosmo hardware");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uiDefButS(block, MENU,B_FILETYPEMENU,imagetype_pup(), 892,yofs,225,20, &G.scene->r.imtype, 0, 0, 0, 0, "Images are saved in this file format");
|
uiDefButS(block, MENU,B_FILETYPEMENU,imagetype_pup(), 892,yofs,174,20, &G.scene->r.imtype, 0, 0, 0, 0, "Images are saved in this file format");
|
||||||
|
uiDefButBitI(block, TOG, R_CROP, B_DIFF, "Crop", 1068,yofs,51,20, &G.scene->r.mode, 0, 0, 0, 0, "When Border render, the resulting image gets cropped");
|
||||||
|
|
||||||
yofs -= 22;
|
yofs -= 22;
|
||||||
|
|
||||||
|
|||||||
@@ -218,9 +218,11 @@ void save_image_filesel_str(char *str)
|
|||||||
/* calls fileselect if zbuf is set we are rendering the zbuffer */
|
/* calls fileselect if zbuf is set we are rendering the zbuffer */
|
||||||
void BIF_save_rendered_image_fs(int zbuf)
|
void BIF_save_rendered_image_fs(int zbuf)
|
||||||
{
|
{
|
||||||
RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
|
RenderResult rres;
|
||||||
|
|
||||||
if(!rr) {
|
RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
|
||||||
|
|
||||||
|
if(!rres.rectf) {
|
||||||
error("No image rendered");
|
error("No image rendered");
|
||||||
} else {
|
} else {
|
||||||
char dir[FILE_MAXDIR * 2], str[FILE_MAXFILE * 2];
|
char dir[FILE_MAXDIR * 2], str[FILE_MAXFILE * 2];
|
||||||
|
|||||||
Reference in New Issue
Block a user