diff --git a/.gitignore b/.gitignore index e1d70755..65cc6f2e 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ examples/listview examples/checklist examples/treeview examples/mandelbrot +examples/rotozoomer examples/keyboard examples/mouse examples/timer diff --git a/ChangeLog b/ChangeLog index 25c46188..f91ad1f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2020-03-08 Markus Gans + * A rotozoomer example was added to demonstrate the drawing speed + of FINAL CUT + 2020-03-07 Markus Gans * Fixes keyboard input buffer problem when opening a modal dialog * Exit the move-resize-mode when the close confirmation dialog diff --git a/examples/Makefile.am b/examples/Makefile.am index a6358174..8de96be7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -22,6 +22,7 @@ noinst_PROGRAMS = \ termcap \ string-operations \ mandelbrot \ + rotozoomer \ calculator \ watch \ term-attributes \ @@ -48,6 +49,7 @@ treeview_SOURCES = treeview.cpp opti_move_SOURCES = opti-move.cpp string_operations_SOURCES = string-operations.cpp mandelbrot_SOURCES = mandelbrot.cpp +rotozoomer_SOURCES = rotozoomer.cpp calculator_SOURCES = calculator.cpp watch_SOURCES = watch.cpp term_attributes_SOURCES = term-attributes.cpp diff --git a/examples/rotozoomer.cpp b/examples/rotozoomer.cpp new file mode 100644 index 00000000..8b1f503b --- /dev/null +++ b/examples/rotozoomer.cpp @@ -0,0 +1,238 @@ +/*********************************************************************** +* rotozoomer.cpp - Rotozoomer effect demo * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include + +#include + +namespace fc = finalcut::fc; +using finalcut::FPoint; +using finalcut::FSize; + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// This rotozoomer demo is based on the code of Robert Dörfler +// http://bloerp.de/code/tempel/roto.c +// http://bloerp.de/code/tempel/tempel-des-codes.html +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//---------------------------------------------------------------------- +// class RotoZoomer +//---------------------------------------------------------------------- + +class RotoZoomer : public finalcut::FDialog +{ + public: + // Constructor + explicit RotoZoomer (finalcut::FWidget* = nullptr); + + // Destructor + ~RotoZoomer() override; + + // Event handlers + void onShow (finalcut::FShowEvent*) override; + void onTimer (finalcut::FTimerEvent*) override; + void onKeyPress (finalcut::FKeyEvent*) override; + void onClose (finalcut::FCloseEvent*) override; + + private: + // Methods + void draw() override; + void rotozoomer (double, double, double, double); + void adjustSize() override; + + // Data member + wchar_t data[256]{}; + int path{0}; +}; + + +//---------------------------------------------------------------------- +RotoZoomer::RotoZoomer (finalcut::FWidget* parent) + : finalcut::FDialog(parent) +{ + setText ("Rotozoomer effect"); + + int h{0}; + + for (int j{0}; j < 8; j++) + { + for (int i{0}; i < 8; i++) + { + data[h++] = L' '; + } + + for (int i{0}; i < 8; i++) + { + data[h++] = L'+'; + } + } + + for (int j{0}; j < 8; j++) + { + for (int i{0}; i < 8; i++) + { + data[h++] = L'x'; + } + + for (int i{0}; i < 8; i++) + { + data[h++] = L' '; + } + } +} + +//---------------------------------------------------------------------- +RotoZoomer::~RotoZoomer() +{ } + +//---------------------------------------------------------------------- +void RotoZoomer::draw() +{ + finalcut::FDialog::draw(); + double cx = double(80.0 / 2.0 + (80.0 / 2.0 * std::sin(double(path) / 50.0))); + double cy = double(23.0 + (23.0 * std::cos(double(path) / 50.0))); + double r = double(128.0 + 96.0 * std::cos(double(path) / 10.0)); + double a = double(path) / 50.0; + print() << finalcut::FColorPair(fc::White, fc::Black); + rotozoomer (cx, cy, r, a); +} + +//---------------------------------------------------------------------- +void RotoZoomer::rotozoomer (double cx, double cy, double r, double a) +{ + const int Cols = int(getClientWidth()); + const int Lines = int(getClientHeight()); + int Ax = int(4096.0 * (cx + r * std::cos(a))); + int Ay = int(4096.0 * (cy + r * std::sin(a))); + int Bx = int(4096.0 * (cx + r * std::cos(a + 2.02358))); + int By = int(4096.0 * (cy + r * std::sin(a + 2.02358))); + int Cx = int(4096.0 * (cx + r * std::cos(a - 1.11701))); + int Cy = int(4096.0 * (cy + r * std::sin(a - 1.11701))); + int dxdx = (Bx - Ax) / 80; + int dydx = (By - Ay) / 80; + int dxdy = (Cx - Ax) / 23; + int dydy = (Cy - Ay) / 23; + + for (int y = 0; y < Lines; y++) + { + Cx = Ax; + Cy = Ay; + print() << FPoint(2, 3 + y); + + for (int x = 0; x < Cols; x++) + { + wchar_t ch = data[((Cy >> 14) & 0xf) + ((Cx >> 10) & 0xf0)]; + + if ( ch == '+' ) + print() << finalcut::FColorPair(fc::Black, fc::Red); + else if ( ch == 'x' ) + print() << finalcut::FColorPair(fc::Black, fc::Cyan); + else + print() << finalcut::FColorPair(fc::Black, fc::White); + + print() << ch; + Cx += dxdx; + Cy += dydx; + } + + Ax += dxdy; + Ay += dydy; + } +} + +//---------------------------------------------------------------------- +void RotoZoomer::onShow (finalcut::FShowEvent*) +{ + addTimer(33); +} + +//---------------------------------------------------------------------- +void RotoZoomer::onTimer (finalcut::FTimerEvent*) +{ + if ( path >= 314 ) + path = 0; + else + path++; + + redraw(); + updateTerminal(); + flush(); +} + +//---------------------------------------------------------------------- +void RotoZoomer::onKeyPress (finalcut::FKeyEvent* ev) +{ + if ( ! ev ) + return; + + if ( ev->key() == 'q' ) + { + close(); + ev->accept(); + } + else + finalcut::FDialog::onKeyPress(ev); +} + +//---------------------------------------------------------------------- +void RotoZoomer::onClose (finalcut::FCloseEvent* ev) +{ + finalcut::FApplication::closeConfirmationDialog (this, ev); +} + +//---------------------------------------------------------------------- +void RotoZoomer::adjustSize() +{ + std::size_t h = getDesktopHeight(); + std::size_t w = getDesktopWidth(); + + if ( h > 1 ) + h--; + + if ( w > 8 ) + w -= 8; + + setGeometry(FPoint(5, 1), FSize(w, h), false); + finalcut::FDialog::adjustSize(); +} + +//---------------------------------------------------------------------- +// main part +//---------------------------------------------------------------------- +int main (int argc, char* argv[]) +{ + // Create the application object + finalcut::FApplication app(argc, argv); + app.setNonBlockingRead(); + + // Create a simple dialog box + RotoZoomer p(&app); + p.setGeometry (FPoint(5, 1), FSize(72, 23)); + p.setShadow(); + + // Set the RotoZoomer object as main widget + app.setMainWidget(&p); + + // Show and start the application + p.show(); + return app.exec(); +}