diff --git a/synfig-studio/configure.ac b/synfig-studio/configure.ac index 9ab77b4..38f7852 100644 --- a/synfig-studio/configure.ac +++ b/synfig-studio/configure.ac @@ -197,6 +197,8 @@ AC_CONFIG_FILES([ src/Makefile src/gui/Makefile src/synfigapp/Makefile + src/test/Makefile + src/test/visualization/Makefile images/Makefile pkg-info/macosx/synfig-studio.info plugins/Makefile diff --git a/synfig-studio/src/Makefile.am b/synfig-studio/src/Makefile.am index 96ae3f0..b814e4f 100644 --- a/synfig-studio/src/Makefile.am +++ b/synfig-studio/src/Makefile.am @@ -21,4 +21,6 @@ EXTRA_DIST = \ SUBDIRS = \ synfigapp \ - gui + gui \ + test + diff --git a/synfig-studio/src/test/Makefile.am b/synfig-studio/src/test/Makefile.am new file mode 100644 index 0000000..7da9258 --- /dev/null +++ b/synfig-studio/src/test/Makefile.am @@ -0,0 +1,7 @@ +# $Id$ + +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = \ + visualization + diff --git a/synfig-studio/src/test/visualization/Makefile.am b/synfig-studio/src/test/visualization/Makefile.am new file mode 100644 index 0000000..bfed203 --- /dev/null +++ b/synfig-studio/src/test/visualization/Makefile.am @@ -0,0 +1,33 @@ +# $Id$ + +MAINTAINERCLEANFILES = \ + Makefile.in + +VISUALIZATION_HH = \ + visualizationwindow.h + +VISUALIZATION_CC = \ + visualizationwindow.cpp \ + main.cpp + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src + +bin_PROGRAMS = vizualization + +vizualization_SOURCES = \ + $(VISUALIZATION_HH) \ + $(VISUALIZATION_CC) + +vizualization_LDADD = \ + @SYNFIG_LIBS@ \ + @GTKMM_LIBS@ + +vizualization_LDFLAGS = \ + -dlopen self + +vizualization_CXXFLAGS = \ + @SYNFIG_CFLAGS@ \ + @GTKMM_CFLAGS@ \ + -DPLUGIN_DIR=\"$(plugindir)\" \ + -DLOCALEDIR=\"${LOCALEDIR}\" diff --git a/synfig-studio/src/test/visualization/main.cpp b/synfig-studio/src/test/visualization/main.cpp new file mode 100644 index 0000000..a4930a3 --- /dev/null +++ b/synfig-studio/src/test/visualization/main.cpp @@ -0,0 +1,140 @@ + +#include +#include + +#ifdef _WIN32 +#include +#endif + +#include + +#include + +#include +#include +#include +#include + +#include "visualizationwindow.h" + + +using namespace synfig; + + +const char commandname[] = "visualization"; + + +class TestCallback: public ProgressCallback { +public: + virtual bool task(const String &task) + { synfig::info("%s", task.c_str()); return true; } + virtual bool error(const String &task) + { synfig::error("%s", task.c_str()); return true; } + virtual bool warning(const String &task) + { synfig::warning("%s", task.c_str()); return true; } +}; + + +int main(int argc, char **argv) +{ + + //// init + + +#ifdef _WIN32 + // Enable standard input/output on Windows + if (AttachConsole(ATTACH_PARENT_PROCESS)) { + freopen("CON", "r", stdin); + freopen("CON", "w", stdout); + freopen("CON", "w", stderr); + } +#endif + + Glib::init(); + + String binary_path = get_binary_path(argv[0]); + String base_dir = etl::dirname(binary_path); + TestCallback callback; + + Main main(base_dir, &callback); + + info("Visualization test"); + + // copy args + std::vector args(argv, argv + argc); + argv = &args.front(); + + + //// parse command line + + + typedef std::map RendererMap; + const RendererMap& renderers = rendering::Renderer::get_renderers(); + + if (argc < 3) { + std::cout << std::endl; + std::cout << "usage: " << std::endl; + std::cout << " " << commandname << " " << std::endl; + std::cout << std::endl; + std::cout << "available renderers: " << std::endl; + for(RendererMap::const_iterator i = renderers.begin(); i != renderers.end(); ++i) + if (i->second) + std::cout << " " << i->first << " - " << i->second->get_name() << std::endl; + return 0; + } + + const String filename = argv[1]; + info("filename: %s", filename.c_str()); + + const String renderer_name = argv[2]; + info("renderer_name: %s", renderer_name.c_str()); + + // remove processed args from argv + args.erase(args.begin() + 1); + args.erase(args.begin() + 1); + argc = (int)args.size(); + + + //// get renderer + + + RendererMap::const_iterator ri = renderers.find(renderer_name); + if (ri == renderers.end() || !ri->second) { + error("unknown renderer: %s", renderer_name.c_str()); + info("call %s with no arguments to take list of available renderers", commandname); + return 1; + } + rendering::Renderer::Handle renderer = ri->second; + + + //// get canvas + + + String errors, warnings; + Canvas::Handle canvas = open_canvas_as( + FileSystemNative::instance()->get_identifier(filename), + filename, + errors, + warnings ); + if (!canvas) + return 1; + + + //// run Gtk::Application + + + info("create Gtk::Application"); + + Glib::RefPtr application = Gtk::Application::create(argc, argv); + + info("create window"); + VisualizationWindow window(canvas, renderer); + + info("run"); + int result = application->run(window); + + if (result) error("Gtk::Application finished with errog code: %d", result); + info("end"); + return result; +} + diff --git a/synfig-studio/src/test/visualization/visualizationwindow.cpp b/synfig-studio/src/test/visualization/visualizationwindow.cpp new file mode 100644 index 0000000..6342143 --- /dev/null +++ b/synfig-studio/src/test/visualization/visualizationwindow.cpp @@ -0,0 +1,175 @@ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include "visualizationwindow.h" + + +using namespace synfig; + + +VisualizationWindow::VisualizationWindow( + const Canvas::Handle &canvas, + const rendering::Renderer::Handle &renderer +): + canvas(canvas), + renderer(renderer), + transform(false), + frame(0), + frames_count(1), + frame_duration(0), + pixel_format(0) +{ + // prepare rend desc + rend_desc = canvas->rend_desc(); + rend_desc.set_wh( + std::max(1, rend_desc.get_w()), + std::max(1, rend_desc.get_h()) ); + Vector p0 = rend_desc.get_tl(); + Vector p1 = rend_desc.get_br(); + if (p0[0] > p1[0] || p0[1] > p1[1]) { + if (p0[0] > p1[0]) { matrix.m00 = -1.0; matrix.m20 = p0[0] + p1[0]; std::swap(p0[0], p1[0]); } + if (p0[1] > p1[1]) { matrix.m11 = -1.0; matrix.m21 = p0[1] + p1[1]; std::swap(p0[1], p1[1]); } + rend_desc.set_tl_br(p0, p1); + transform = true; + } + + // prepare frames counter + frames_count = std::max( + frames_count, + rend_desc.get_frame_end() - rend_desc.get_frame_start() + 1 ); + Real fps = rend_desc.get_frame_rate(); + frame_duration = fps > real_precision() ? 1/fps : 0; + + // prepare cairo surface + cairo_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, rend_desc.get_w(), rend_desc.get_h()); + + // check endianness and prepare pixel format + union { int i; char c[4]; } checker = {0x01020304}; + bool big_endian = checker.c[0] == 1; + pixel_format = big_endian + ? (PF_A_START | PF_RGB | PF_A_PREMULT) + : (PF_BGR | PF_A | PF_A_PREMULT); + + // prepare surface resource + surface_resource = new rendering::SurfaceResource(); + surface_resource->create(rend_desc.get_w(), rend_desc.get_h()); + + // create widgets + Gtk::DrawingArea *drawing_area = manage(new Gtk::DrawingArea()); + drawing_area->signal_draw().connect(sigc::mem_fun(*this, &VisualizationWindow::on_content_draw)); + drawing_area->set_size_request( + rend_desc.get_w(), + rend_desc.get_h() ); + drawing_area->show(); + add(*drawing_area); + + // redraw forever + Glib::signal_idle().connect(sigc::mem_fun(*this, &VisualizationWindow::on_idle)); +} + +bool +VisualizationWindow::on_idle() { + queue_draw(); + return true; +} + + +bool +VisualizationWindow::convert(const rendering::SurfaceResource::Handle &surface) +{ + rendering::SurfaceResource::LockReadBase surface_lock(surface); + if (surface_lock.get_resource() && surface_lock.get_resource()->is_blank()) + return false; + + if (!surface_lock.convert(rendering::Surface::Token::Handle(), false, true)) { + synfig::error("convert: surface does not exists"); + return false; + } + + int w = cairo_surface->get_width(); + int h = cairo_surface->get_height(); + const rendering::Surface &s = *surface_lock.get_surface(); + if (w != s.get_width() || h != s.get_height()) { + synfig::error("convert: surface with wrong size"); + return false; + } + + const Color *pixels = s.get_pixels_pointer(); + std::vector pixels_copy; + if (!pixels) { + pixels_copy.resize(w*h); + if (s.get_pixels(&pixels_copy.front())) + pixels = &pixels_copy.front(); + } + if (!pixels) { + synfig::error("convert: cannot access surface pixels - that really strange"); + return false; + } + + // do conversion + color_to_pixelformat( + cairo_surface->get_data(), + pixels, + pixel_format, + 0, + cairo_surface->get_width(), + cairo_surface->get_height(), + cairo_surface->get_stride() ); + cairo_surface->mark_dirty(); + + return true; +} + + +bool +VisualizationWindow::on_content_draw(const Cairo::RefPtr &context) { + context->move_to(0, 0); + context->line_to(frame, 100); + context->stroke(); + + Time time = frame_duration*(frame + rend_desc.get_frame_start()); + canvas->set_time(time); + + canvas->load_resources(time); + + canvas->set_outline_grow(rend_desc.get_outline_grow()); + + bool surface_exists = false; + ContextParams context_params(rend_desc.get_render_excluded_contexts()); + rendering::Task::Handle task = canvas->build_rendering_task(context_params); + if (task) { + if (transform) { + rendering::TaskTransformationAffine::Handle t = new rendering::TaskTransformationAffine(); + t->transformation->matrix = matrix; + t->sub_task() = task; + task = t; + } + surface_resource->clear(); + task->target_surface = surface_resource; + task->target_rect = RectInt( VectorInt(), task->target_surface->get_size() ); + task->source_rect = Rect(rend_desc.get_tl(), rend_desc.get_br()); + } + + if (task) + renderer->run(task); + + if (task) + surface_exists = convert(task->target_surface); + + if (surface_exists) { + context->set_source(cairo_surface, 0, 0); + context->paint(); + } + + frame = (frame + 1) % frames_count; + return true; +} diff --git a/synfig-studio/src/test/visualization/visualizationwindow.h b/synfig-studio/src/test/visualization/visualizationwindow.h new file mode 100644 index 0000000..fc4dc93 --- /dev/null +++ b/synfig-studio/src/test/visualization/visualizationwindow.h @@ -0,0 +1,43 @@ +#ifndef __SYNFIG_TEST_VISULIZATION_WINDOW_H +#define __SYNFIG_TEST_VISULIZATION_WINDOW_H + + +#include + +#include +#include +#include +#include + + +class VisualizationWindow: public Gtk::Window { +private: + synfig::Canvas::Handle canvas; + synfig::rendering::Renderer::Handle renderer; + + synfig::RendDesc rend_desc; + bool transform; + synfig::Matrix matrix; + int frame; + int frames_count; + synfig::Time frame_duration; + + synfig::PixelFormat pixel_format; + Cairo::RefPtr cairo_surface; + synfig::rendering::SurfaceResource::Handle surface_resource; + +public: + VisualizationWindow( + const synfig::Canvas::Handle &canvas, + const synfig::rendering::Renderer::Handle &renderer ); + + bool convert(const synfig::rendering::SurfaceResource::Handle &surface); + + bool on_content_draw(const Cairo::RefPtr &context); + + bool on_idle(); +}; + +#endif + +