// // Offscreen drawing test program for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2018 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this // file is missing or damaged, see the license at: // // https://www.fltk.org/COPYING.php // // Please see the following page on how to report bugs and issues: // // https://www.fltk.org/bugs.php // /* Standard headers */ #include #include // time() - used to seed rand() /* Fltk headers */ #include #include #include #include #include static Fl_Double_Window *main_window = 0; // constants to define the view etc. static const int offscreen_size = 1000; static const int win_size = 512; static const int first_useful_color = 56; static const int last_useful_color = 255; static const int num_iterations = 300; static const int max_line_width = 9; static const double delta_time = 0.1; /*****************************************************************************/ class oscr_box : public Fl_Box { public: oscr_box(int x, int y, int w, int h); void oscr_drawing(void); bool has_oscr() const { if (oscr) return true; return false; } private: void draw(); int handle(int event); // Generate "random" values for the line display double random_val(int v) const { double dr = (double)(rand()) / (double)(RAND_MAX); // 0.0 to 1.0 dr = dr * (double)(v); // 0 to v return dr; } // The offscreen surface Fl_Offscreen oscr; // variables used to handle "dragging" of the view within the box int x1, y1; // drag start positions int xoff, yoff; // drag offsets int drag_state; // non-zero if drag is in progress int page_x, page_y; // top left of view area // Width and height of the offscreen surface int offsc_w, offsc_h; int iters; // Must be set on first pass! float scale; // current screen scaling factor value }; /*****************************************************************************/ oscr_box::oscr_box(int x, int y, int w, int h) : Fl_Box(x, y, w, h), // base box oscr(0), // offscreen is not set at start x1(0), y1(0), drag_state(0), // not dragging view page_x((offscreen_size - win_size) / 2), // roughly centred in view page_y((offscreen_size - win_size) / 2), offsc_w(0), offsc_h(0), // offscreen size - initially none iters(num_iterations + 1) { } // Constructor /*****************************************************************************/ void oscr_box::draw() { int wd = w(); int ht = h(); int xo = x(); int yo = y(); fl_color(fl_gray_ramp(19)); // a light grey background shade fl_rectf(xo, yo, wd, ht); // fill the box with this colour // then add the offscreen on top of the grey background if (has_oscr()) // offscreen exists { if (scale != Fl_Graphics_Driver::default_driver().scale()) { // the screen scaling factor has changed fl_rescale_offscreen(oscr); scale = Fl_Graphics_Driver::default_driver().scale(); } fl_copy_offscreen(xo, yo, wd, ht, oscr, page_x, page_y); } else // create offscreen { // some hosts may need a valid window context to base the offscreen on... main_window->make_current(); offsc_w = offscreen_size; offsc_h = offscreen_size; oscr = fl_create_offscreen(offsc_w, offsc_h); scale = Fl_Graphics_Driver::default_driver().scale(); } } // draw method /*****************************************************************************/ int oscr_box::handle(int ev) { int ret = Fl_Box::handle(ev); // handle dragging of visible page area - if a valid context exists if (has_oscr()) { switch (ev) { case FL_ENTER: main_window->cursor(FL_CURSOR_MOVE); ret = 1; break; case FL_LEAVE: main_window->cursor(FL_CURSOR_DEFAULT); ret = 1; break; case FL_PUSH: x1 = Fl::event_x_root(); y1 = Fl::event_y_root(); drag_state = 1; // drag ret = 1; break; case FL_DRAG: if (drag_state == 1) // dragging page { int x2 = Fl::event_x_root(); int y2 = Fl::event_y_root(); xoff = x1 - x2; yoff = y1 - y2; x1 = x2; y1 = y2; page_x += xoff; page_y += yoff; // check the page bounds if (page_x < -w()) { page_x = -w(); } else if (page_x > offsc_w) { page_x = offsc_w; } if (page_y < -h()) { page_y = -h(); } else if (page_y > offsc_h) { page_y = offsc_h; } redraw(); } ret = 1; break; case FL_RELEASE: drag_state = 0; ret = 1; break; default: break; } } return ret; } // handle /*****************************************************************************/ void oscr_box::oscr_drawing(void) { Fl_Color col; static int icol = first_useful_color; static int ox = (offscreen_size / 2); static int oy = (offscreen_size / 2); if (!has_oscr()) { return; // no valid offscreen, nothing to do here } fl_begin_offscreen(oscr); /* Open the offscreen context for drawing */ { if (iters > num_iterations) // clear the offscreen and start afresh { fl_color(FL_WHITE); fl_rectf(0, 0, offsc_w, offsc_h); iters = 0; } iters++; icol++; if (icol > last_useful_color) { icol = first_useful_color; } col = static_cast(icol); fl_color(col); // set the colour double drx = random_val(offsc_w); double dry = random_val(offsc_h); double drt = random_val(max_line_width); int ex = static_cast(drx); int ey = static_cast(dry); fl_line_style(FL_SOLID, static_cast(drt)); fl_line(ox, oy, ex, ey); ox = ex; oy = ey; } fl_line_style(FL_SOLID, 0); fl_end_offscreen(); // close the offscreen context redraw(); } // oscr_drawing /*****************************************************************************/ static oscr_box *os_box = 0; // a widget to view the offscreen with /*****************************************************************************/ static void oscr_anim(void *) { os_box->oscr_drawing(); // if the offscreen exists, draw something Fl::repeat_timeout(delta_time, oscr_anim); } // oscr_anim /*****************************************************************************/ int main(int argc, char **argv) { int dim1 = win_size; main_window = new Fl_Double_Window(dim1, dim1, "Offscreen demo"); main_window->begin(); dim1 -= 10; os_box = new oscr_box(5, 5, dim1, dim1); main_window->end(); main_window->resizable(os_box); main_window->show(argc, argv); srand((unsigned int)time(NULL)); // seed the random sequence generator Fl::add_timeout(delta_time, oscr_anim); return Fl::run(); } // main