X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftags%2Fsynfig_0_61_07_rc2%2Fsrc%2Fsynfig%2Ftarget_scanline.cpp;fp=synfig-core%2Ftags%2Fsynfig_0_61_07_rc2%2Fsrc%2Fsynfig%2Ftarget_scanline.cpp;h=19f38f21a010eb401d57f861f17a3aa784809e27;hb=3078b7103aa069392b711486dbc1eaf6d4804acc;hp=0000000000000000000000000000000000000000;hpb=1d8dc189e3174b7e3c28c865828aecc6bee6d8a3;p=synfig.git diff --git a/synfig-core/tags/synfig_0_61_07_rc2/src/synfig/target_scanline.cpp b/synfig-core/tags/synfig_0_61_07_rc2/src/synfig/target_scanline.cpp new file mode 100644 index 0000000..19f38f2 --- /dev/null +++ b/synfig-core/tags/synfig_0_61_07_rc2/src/synfig/target_scanline.cpp @@ -0,0 +1,505 @@ +/* === S Y N F I G ========================================================= */ +/*! \file target_scanline.cpp +** \brief Template File +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** +** This package 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 package 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. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "target_scanline.h" +#include "string.h" +#include "surface.h" +#include "render.h" +#include "canvas.h" +#include "context.h" + +#endif + +/* === U S I N G =========================================================== */ + +using namespace std; +using namespace etl; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +#define SYNFIG_OPTIMIZE_LAYER_TREE 1 + +#define PIXEL_RENDERING_LIMIT 1500000 + +#define USE_PIXELRENDERING_LIMIT 1 + +/* === G L O B A L S ======================================================= */ + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +Target_Scanline::Target_Scanline(): + threads_(2) +{ + curr_frame_=0; +} + +int +Target_Scanline::next_frame(Time& time) +{ + int + total_frames(1), + frame_start(0), + frame_end(0); + Time + time_start(0), + time_end(0); + + // If the description's end frame is equal to + // the start frame, then it is assumed that we + // are rendering only one frame. Correct it. + if(desc.get_frame_end()==desc.get_frame_start()) + desc.set_frame_end(desc.get_frame_start()+1); + + frame_start=desc.get_frame_start(); + frame_end=desc.get_frame_end(); + time_start=desc.get_time_start(); + time_end=desc.get_time_end(); + + // Calculate the number of frames + total_frames=frame_end-frame_start; + if(total_frames<=0)total_frames=1; + + //RendDesc rend_desc=desc; + //rend_desc.set_gamma(1); + +// int total_tiles(total_tiles()); + time=(time_end-time_start)*curr_frame_/total_frames+time_start; + curr_frame_++; + +/* synfig::info("curr_frame_: %d",curr_frame_); + synfig::info("total_frames: %d",total_frames); + synfig::info("time_end: %s",time_end.get_string().c_str()); + synfig::info("time_start: %s",time_start.get_string().c_str()); +*/ +// synfig::info("time: %s",time.get_string().c_str()); + + return total_frames- curr_frame_+1; +} +bool +synfig::Target_Scanline::render(ProgressCallback *cb) +{ + SuperCallback super_cb; + int +// i=0, + total_frames, + quality=get_quality(), + frame_start, + frame_end; + Time + t=0, + time_start, + time_end; + + assert(canvas); + curr_frame_=0; + + if( !init() ){ + if(cb) cb->error(_("Target initialisation failure")); + return false; + } + + // If the description's end frame is equal to + // the start frame, then it is assumed that we + // are rendering only one frame. Correct it. + if(desc.get_frame_end()==desc.get_frame_start()) + desc.set_frame_end(desc.get_frame_start()+1); + + frame_start=desc.get_frame_start(); + frame_end=desc.get_frame_end(); + time_start=desc.get_time_start(); + time_end=desc.get_time_end(); + + // Calculate the number of frames + total_frames=frame_end-frame_start; + + + //RendDesc rend_desc=desc; + + try { + // Grab the time + int i=next_frame(t); + + //synfig::info("1time_set_to %s",t.get_string().c_str()); + + if(i>1) + do{ + + //if(total_frames>1) + //for(i=0,t=time_start;iamount_complete(total_frames-(i-1),total_frames)) + return false; + + // Set the time that we wish to render + if(!get_avoid_time_sync() || canvas->get_time()!=t) + canvas->set_time(t); + + Context context; + + #ifdef SYNFIG_OPTIMIZE_LAYER_TREE + Canvas::Handle op_canvas(Canvas::create()); + optimize_layers(canvas->get_context(), op_canvas); + context=op_canvas->get_context(); + #else + context=canvas->get_context(); + #endif + + // If the quality is set to zero, then we + // use the parametric scanline-renderer. + if(quality==0) + { + if(threads_<=0) + { + if(!synfig::render(context,this,desc,0)) + return false; + } + else + { + if(!synfig::render_threaded(context,this,desc,0,threads_)) + return false; + } + } + else // If quality is set otherwise, then we use the accelerated renderer + { + #if USE_PIXELRENDERING_LIMIT + if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT) + { + synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h()); + + Surface surface; + int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w(); + if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit? + int rows = desc.get_h()/rowheight; + int lastrowheight = desc.get_h() - rows*rowheight; + + rows++; + + synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows); + + // loop through all the full rows + if(!start_frame()) + { + throw(string("add_frame(): target panic on start_frame()")); + return false; + } + + for(int i=0; i < rows; ++i) + { + RendDesc blockrd = desc; + + //render the strip at the normal size unless it's the last one... + if(i == rows-1) + { + if(!lastrowheight) break; + blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight); + } + else + { + blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight); + } + + if(!context.accelerated_render(&surface,quality,blockrd,0)) + { + if(cb)cb->error(_("Accelerated Renderer Failure")); + return false; + }else + { + int y; + int rowspan=sizeof(Color)*surface.get_w(); + Surface::pen pen = surface.begin(); + + int yoff = i*rowheight; + + for(y = 0; y < blockrd.get_h(); y++, pen.inc_y()) + { + Color *colordata= start_scanline(y + yoff); + if(!colordata) + { + throw(string("add_frame(): call to start_scanline(y) returned NULL")); + return false; + } + + if(get_remove_alpha()) + { + for(int i = 0; i < surface.get_w(); i++) + colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f); + } + else + memcpy(colordata,surface[y],rowspan); + + if(!end_scanline()) + { + throw(string("add_frame(): target panic on end_scanline()")); + return false; + } + } + } + } + + end_frame(); + + }else //use normal rendering... + { + #endif + Surface surface; + + if(!context.accelerated_render(&surface,quality,desc,0)) + { + // For some reason, the accelerated renderer failed. + if(cb)cb->error(_("Accelerated Renderer Failure")); + return false; + } + else + { + // Put the surface we renderer + // onto the target. + if(!add_frame(&surface)) + { + if(cb)cb->error(_("Unable to put surface on target")); + return false; + } + } + #if USE_PIXELRENDERING_LIMIT + } + #endif + } + }while((i=next_frame(t))); + else + { + // Set the time that we wish to render + if(!get_avoid_time_sync() || canvas->get_time()!=t) + canvas->set_time(t); + Context context; + + #ifdef SYNFIG_OPTIMIZE_LAYER_TREE + Canvas::Handle op_canvas(Canvas::create()); + optimize_layers(canvas->get_context(), op_canvas); + context=op_canvas->get_context(); + #else + context=canvas->get_context(); + #endif + + // If the quality is set to zero, then we + // use the parametric scanline-renderer. + if(quality==0) + { + if(threads_<=0) + { + if(!synfig::render(context,this,desc,cb)) + return false; + } + else + { + if(!synfig::render_threaded(context,this,desc,cb,threads_)) + return false; + } + } + else // If quality is set otherwise, then we use the accelerated renderer + { + #if USE_PIXELRENDERING_LIMIT + if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT) + { + synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h()); + + Surface surface; + int totalheight = desc.get_h(); + int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w(); + if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit? + int rows = desc.get_h()/rowheight; + int lastrowheight = desc.get_h() - rows*rowheight; + + rows++; + + synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows); + + // loop through all the full rows + if(!start_frame()) + { + throw(string("add_frame(): target panic on start_frame()")); + return false; + } + + for(int i=0; i < rows; ++i) + { + RendDesc blockrd = desc; + + //render the strip at the normal size unless it's the last one... + if(i == rows-1) + { + if(!lastrowheight) break; + blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight); + } + else + { + blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight); + } + + SuperCallback sc(cb, i*rowheight, (i+1)*rowheight, totalheight); + + if(!context.accelerated_render(&surface,quality,blockrd,&sc)) + { + if(cb)cb->error(_("Accelerated Renderer Failure")); + return false; + }else + { + int y; + int rowspan=sizeof(Color)*surface.get_w(); + Surface::pen pen = surface.begin(); + + int yoff = i*rowheight; + + for(y = 0; y < blockrd.get_h(); y++, pen.inc_y()) + { + Color *colordata= start_scanline(y + yoff); + if(!colordata) + { + throw(string("add_frame(): call to start_scanline(y) returned NULL")); + return false; + } + + if(get_remove_alpha()) + { + for(int i = 0; i < surface.get_w(); i++) + colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f); + } + else + memcpy(colordata,surface[y],rowspan); + + if(!end_scanline()) + { + throw(string("add_frame(): target panic on end_scanline()")); + return false; + } + } + } + + //I'm done with this part + sc.amount_complete(100,100); + } + + end_frame(); + + }else + { + #endif + Surface surface; + + if(!context.accelerated_render(&surface,quality,desc,cb)) + { + if(cb)cb->error(_("Accelerated Renderer Failure")); + return false; + } + else + { + // Put the surface we renderer + // onto the target. + if(!add_frame(&surface)) + { + if(cb)cb->error(_("Unable to put surface on target")); + return false; + } + } + #if USE_PIXELRENDERING_LIMIT + } + #endif + } + } + + } + catch(String str) + { + if(cb)cb->error(_("Caught string :")+str); + return false; + } + catch(std::bad_alloc) + { + if(cb)cb->error(_("Ran out of memory (Probably a bug)")); + return false; + } + catch(...) + { + if(cb)cb->error(_("Caught unknown error, rethrowing...")); + throw; + } + return true; +} + +bool +Target_Scanline::add_frame(const Surface *surface) +{ + assert(surface); + + + int y; + int rowspan=sizeof(Color)*surface->get_w(); + Surface::const_pen pen=surface->begin(); + + if(!start_frame()) + { + throw(string("add_frame(): target panic on start_frame()")); + return false; + } + + for(y=0;yget_h();y++,pen.inc_y()) + { + Color *colordata= start_scanline(y); + if(!colordata) + { + throw(string("add_frame(): call to start_scanline(y) returned NULL")); + return false; + } + + if(get_remove_alpha()) + { + for(int i=0;iget_w();i++) + colordata[i]=Color::blend((*surface)[y][i],desc.get_bg_color(),1.0f); + } + else + memcpy(colordata,(*surface)[y],rowspan); + + if(!end_scanline()) + { + throw(string("add_frame(): target panic on end_scanline()")); + return false; + } + } + + end_frame(); + + return true; +}