diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2018-03-22 15:27:02 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2018-03-22 15:27:02 +0000 |
| commit | 0b8116ff72145816c3e1d4909038c126327e7bf2 (patch) | |
| tree | 6559a0aca4e1047fe4906fa474ab463fc3229778 | |
| parent | 3a20682764807173ec6b0e354ede9b57930ff6a7 (diff) | |
Android: Implemented vector drawing and polygons.
Started to implement arc and pie drawing
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12783 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | FL/android.H | 17 | ||||
| -rw-r--r-- | ide/AndroidStudio3/app/src/main/cpp/HelloAndroid.cxx | 254 | ||||
| -rw-r--r-- | src/drivers/Android/Fl_Android_Application.H | 16 | ||||
| -rw-r--r-- | src/drivers/Android/Fl_Android_Application.cxx | 1 | ||||
| -rw-r--r-- | src/drivers/Android/Fl_Android_Graphics_Driver.H | 47 | ||||
| -rw-r--r-- | src/drivers/Android/Fl_Android_Graphics_Driver.cxx | 447 | ||||
| -rw-r--r-- | src/drivers/Android/Fl_Android_Graphics_Font.cxx | 6 |
7 files changed, 750 insertions, 38 deletions
diff --git a/FL/android.H b/FL/android.H index 262ab82b7..573664984 100644 --- a/FL/android.H +++ b/FL/android.H @@ -25,6 +25,23 @@ # error "Never use <FL/android.H> directly; include <FL/platform.H> instead." #endif // !FL_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This is the function that application code must implement, representing + * the main entry to the app. + */ +extern int main(int argc, char **argv); + +#ifdef __cplusplus +} +#endif + + + typedef void *Window; // used by fl_find(), fl_xid() and class Fl_X /* Reference to the current device context diff --git a/ide/AndroidStudio3/app/src/main/cpp/HelloAndroid.cxx b/ide/AndroidStudio3/app/src/main/cpp/HelloAndroid.cxx index 882d4189f..d68dcd4e2 100644 --- a/ide/AndroidStudio3/app/src/main/cpp/HelloAndroid.cxx +++ b/ide/AndroidStudio3/app/src/main/cpp/HelloAndroid.cxx @@ -15,11 +15,182 @@ * */ + +#include <stdlib.h> +#include <stdio.h> +#include <FL/Fl.H> +#include <FL/Fl_Double_Window.H> +#include <FL/Fl_Box.H> +#include <FL/fl_draw.H> + +int N = 0; +#define W 200 +#define H 50 +#define ROWS 14 + +// Note: Run the program with command line '-s abc' to view boxtypes +// with scheme 'abc'. + +// class BoxGroup - minimal class to enable visible box size debugging +// +// Set the following static variables to 0 (default) to disable +// or 1 to enable the given feature. +// +// If you enable the 'outline' variable, then a red frame should be drawn +// around each box, and it should ideally be fully visible. +// +// The white background is optional (otherwise you see the window background). +// +// Set BOTH variables = 0 to show the default image for the FLTK manual. +// +// Note: As of FLTK 1.3.3 (probably since FLTK 1.0/1.1) there are some +// shadows 'leaking' outside their widget bounding boxes (x,y,w,h). +// Is this intentional? + +static const int outline = 0; // draw 1-px red frame around all boxes +static const int box_bg = 0; // draw white background inside all boxes +static const int inactive = 0; // deactivate boxes and use green background +class BoxGroup : public Fl_Group { +public: + BoxGroup(int x, int y, int w, int h) : Fl_Group(x,y,w,h) {}; + void draw() { + draw_box(); + if (outline + box_bg) { // outline or box_bg or both + Fl_Widget*const* a = array(); + for (int i=children(); i--;) { + Fl_Widget& o = **a++; + if (outline) { + fl_color(FL_RED); + fl_rect(o.x()-1,o.y()-1,o.w()+2,o.h()+2); + } + if (box_bg) { + fl_color(FL_WHITE); + fl_rectf(o.x(),o.y(),o.w(),o.h()); + } + fl_color(FL_BLACK); + } + } // outline or box_bg or both + Fl_Group::draw_children(); + } // draw() +}; // class BoxGroup + +Fl_Double_Window *window; + +void bt(const char *name, Fl_Boxtype type, int square=0) { + int x = N%4; + int y = N/4; + N++; + x = x*W+10; + y = y*H+10; + Fl_Box *b = new Fl_Box(type,x,y,square ? H-20 : W-20,H-20,name); + b->labelsize(11); + if (inactive) { + b->color(FL_GREEN); + b->deactivate(); + } + if (square) b->align(FL_ALIGN_RIGHT); +} + +int main(int argc, char ** argv) { + window = new Fl_Double_Window(4*W,ROWS*H); + window->box(FL_FLAT_BOX); +#if 0 // this code uses the command line arguments to set arbitrary color schemes + Fl::args(argc, argv); + Fl::get_system_colors(); +#elif 0 // this code uses a single color to define a scheme + Fl::args(argc, argv); + Fl::get_system_colors(); + Fl::background(113,113,198); +#else // this code uses the nice bright blue background to show box vs. frame types + Fl::args(argc, argv); + Fl::get_system_colors(); + window->color(12);// light blue +#endif + + // set window title to show active scheme + Fl::scheme(Fl::scheme()); // init scheme + char title[100]; + sprintf(title,"FLTK boxtypes: scheme = '%s'",Fl::scheme()?Fl::scheme():"none"); + window->label(title); + + // create special container group for box size debugging + BoxGroup *bg = new BoxGroup(0,0,window->w(),window->h()); + bg->box(FL_NO_BOX); + + // create demo boxes + bt("FL_NO_BOX",FL_NO_BOX); + bt("FL_FLAT_BOX",FL_FLAT_BOX); + N += 2; // go to start of next row to line up boxes & frames + bt("FL_UP_BOX",FL_UP_BOX); + bt("FL_DOWN_BOX",FL_DOWN_BOX); + bt("FL_UP_FRAME",FL_UP_FRAME); + bt("FL_DOWN_FRAME",FL_DOWN_FRAME); + bt("FL_THIN_UP_BOX",FL_THIN_UP_BOX); + bt("FL_THIN_DOWN_BOX",FL_THIN_DOWN_BOX); + bt("FL_THIN_UP_FRAME",FL_THIN_UP_FRAME); + bt("FL_THIN_DOWN_FRAME",FL_THIN_DOWN_FRAME); + bt("FL_ENGRAVED_BOX",FL_ENGRAVED_BOX); + bt("FL_EMBOSSED_BOX",FL_EMBOSSED_BOX); + bt("FL_ENGRAVED_FRAME",FL_ENGRAVED_FRAME); + bt("FL_EMBOSSED_FRAME",FL_EMBOSSED_FRAME); + bt("FL_BORDER_BOX",FL_BORDER_BOX); + bt("FL_SHADOW_BOX",FL_SHADOW_BOX); + bt("FL_BORDER_FRAME",FL_BORDER_FRAME); + bt("FL_SHADOW_FRAME",FL_SHADOW_FRAME); + bt("FL_ROUNDED_BOX",FL_ROUNDED_BOX); + bt("FL_RSHADOW_BOX",FL_RSHADOW_BOX); + bt("FL_ROUNDED_FRAME",FL_ROUNDED_FRAME); + bt("FL_RFLAT_BOX",FL_RFLAT_BOX); + bt("FL_OVAL_BOX",FL_OVAL_BOX); + bt("FL_OSHADOW_BOX",FL_OSHADOW_BOX); + bt("FL_OVAL_FRAME",FL_OVAL_FRAME); + bt("FL_OFLAT_BOX",FL_OFLAT_BOX); + bt("FL_ROUND_UP_BOX",FL_ROUND_UP_BOX); + bt("FL_ROUND_DOWN_BOX",FL_ROUND_DOWN_BOX); + bt("FL_DIAMOND_UP_BOX",FL_DIAMOND_UP_BOX); + bt("FL_DIAMOND_DOWN_BOX",FL_DIAMOND_DOWN_BOX); + + bt("FL_PLASTIC_UP_BOX",FL_PLASTIC_UP_BOX); + bt("FL_PLASTIC_DOWN_BOX",FL_PLASTIC_DOWN_BOX); + bt("FL_PLASTIC_UP_FRAME",FL_PLASTIC_UP_FRAME); + bt("FL_PLASTIC_DOWN_FRAME",FL_PLASTIC_DOWN_FRAME); + bt("FL_PLASTIC_THIN_UP_BOX",FL_PLASTIC_THIN_UP_BOX); + bt("FL_PLASTIC_THIN_DOWN_BOX",FL_PLASTIC_THIN_DOWN_BOX); + N += 2; + bt("FL_PLASTIC_ROUND_UP_BOX",FL_PLASTIC_ROUND_UP_BOX); + bt("FL_PLASTIC_ROUND_DOWN_BOX",FL_PLASTIC_ROUND_DOWN_BOX); + N += 2; + + bt("FL_GTK_UP_BOX",FL_GTK_UP_BOX); + bt("FL_GTK_DOWN_BOX",FL_GTK_DOWN_BOX); + bt("FL_GTK_UP_FRAME",FL_GTK_UP_FRAME); + bt("FL_GTK_DOWN_FRAME",FL_GTK_DOWN_FRAME); + bt("FL_GTK_THIN_UP_BOX",FL_GTK_THIN_UP_BOX); + bt("FL_GTK_THIN_DOWN_BOX",FL_GTK_THIN_DOWN_BOX); + bt("FL_GTK_THIN_UP_FRAME",FL_GTK_THIN_UP_FRAME); + bt("FL_GTK_THIN_DOWN_FRAME",FL_GTK_THIN_DOWN_FRAME); + bt("FL_GTK_ROUND_UP_BOX",FL_GTK_ROUND_UP_BOX); + bt("FL_GTK_ROUND_DOWN_BOX",FL_GTK_ROUND_DOWN_BOX); + bg->end(); + window->resizable(window); + window->end(); + window->show(); + return Fl::run(); +} + + + + + + +#if 0 + #include <src/drivers/Android/Fl_Android_Application.H> #include <FL/Fl_Window.H> #include <FL/Fl_Button.H> #include <FL/Enumerations.H> #include <FL/fl_draw.H> +#include <FL/fl_ask.H> Fl_Window *win, *win1, *win2; @@ -31,9 +202,16 @@ class MyButton : public Fl_Button public: MyButton(int x, int y, int w, int h, const char *l) : Fl_Button(x, y, w, h, l) { } void draw() { - //fl_push_clip(x(), y(), w()*2/3, h()*2/3); Fl_Button::draw(); - //fl_pop_clip(); + fl_push_clip(x(), y(), w(), h()); + fl_color(FL_BLUE); + for (int i=0; i<h(); i+=5) { + fl_line(x(), y()+h()/2, x()+w(), y()+i); + } + for (int i=0; i<w(); i+=5) { + fl_line(x()+w()/2, y()-50, x()+i, y()+h()+50); + } + fl_pop_clip(); } }; @@ -53,7 +231,7 @@ void hello_cb(void*) } -int main(int argc, char **argv) +int xmain(int argc, char **argv) { // Fl::scheme("gleam"); win1 = new Fl_Window(20+50, 10, 200, 200, "back"); @@ -88,6 +266,9 @@ int main(int argc, char **argv) btn->labelsize(30); btn->callback( [](Fl_Widget *w, void*) { +// FIXME: we can't seem to re-enter the event loop without locking +// the entire app! +// fl_alert("This will change\nthe font for the entir\napplication"); Fl::set_font(FL_COURIER_BOLD_ITALIC, "$DancingScript-Regular.ttf"); w->redraw(); } @@ -102,9 +283,9 @@ int main(int argc, char **argv) win->show(argc, argv); win2 = new Fl_Window(380-50, 10, 200, 200, "front"); - win2->color(FL_BLUE); + win2->color(FL_LIGHT3); win2->box(FL_UP_BOX); - Fl_Button *b2 = new Fl_Button(10, 10, 180, 180, "front"); + Fl_Button *b2 = new MyButton(10, 10, 180, 180, "front"); b2->color(FL_DARK_BLUE); win2->end(); win2->show(); @@ -114,3 +295,66 @@ int main(int argc, char **argv) return 0; } +#endif + +/* + + Missing: + - screen scale and size: most desktop apps expect to be in a draggable window + on a larger desktop surface. For Android, there is usually no desktop, and + screen resolution is often very high, so that a regular FLTK window would + hide as a tiny gray spot in the top left corner + * windows should probably be centered by default + ? the screen resolution should adapt to the first opened window + ? we should be able to hint at a prefered screen resolution + * drawing call must scale at some point (line width!) + * rotating the screen must call the app handler and(?) window resize + * proportions: pixels should be square + +test/CubeMain.cxx test/line_style.cxx +test/CubeView.cxx test/list_visuals.cxx +test/adjuster.cxx test/mandelbrot.cxx +test/animated.cxx test/menubar.cxx + * test/arc.cxx : + 'arc' works as expected + test/message.cxx +test/ask.cxx test/minimum.cxx +test/bitmap.cxx test/native-filechooser.cxx +test/blocks.cxx test/navigation.cxx + * test/boxtype.cxx : !! testing + test/offscreen.cxx +test/browser.cxx test/output.cxx +test/button.cxx test/overlay.cxx +test/buttons.cxx test/pack.cxx +test/cairo_test.cxx test/pixmap.cxx +test/checkers.cxx test/pixmap_browser.cxx +test/clock.cxx test/resizebox.cxx +test/colbrowser.cxx test/rotated_text.cxx +test/color_chooser.cxx test/scroll.cxx +test/connect.cxx test/shape.cxx +test/cube.cxx test/subwindow.cxx +test/cursor.cxx test/sudoku.cxx +test/curve.cxx test/symbols.cxx +test/demo.cxx test/table.cxx +test/device.cxx test/threads.cxx +test/doublebuffer.cxx test/tile.cxx +test/editor.cxx test/tiled_image.cxx +test/file_chooser.cxx test/twowin.cxx +test/fonts.cxx test/unittest_about.cxx +test/forms.cxx test/unittest_circles.cxx +test/fractals.cxx test/unittest_images.cxx +test/fracviewer.cxx test/unittest_lines.cxx +test/fullscreen.cxx test/unittest_points.cxx +test/gl_overlay.cxx test/unittest_rects.cxx +test/glpuzzle.cxx test/unittest_schemes.cxx +test/hello.cxx : + 'hello' works fine, italics, shadow, etc. + test/unittest_scrollbarsize.cxx +test/help_dialog.cxx test/unittest_simple_terminal.cxx +test/icon.cxx test/unittest_symbol.cxx +test/iconize.cxx test/unittest_text.cxx +test/image.cxx test/unittest_viewport.cxx +test/input.cxx test/unittests.cxx +test/input_choice.cxx test/utf8.cxx +test/keyboard.cxx test/windowfocus.cxx +test/label.cxx + + */
\ No newline at end of file diff --git a/src/drivers/Android/Fl_Android_Application.H b/src/drivers/Android/Fl_Android_Application.H index dc5838525..20862ab46 100644 --- a/src/drivers/Android/Fl_Android_Application.H +++ b/src/drivers/Android/Fl_Android_Application.H @@ -245,22 +245,6 @@ private: }; -#ifdef __cplusplus -extern "C" { -#endif - -/** - * This is the function that application code must implement, representing - * the main entry to the app. - */ -extern int main(int argc, char **argv); - -#ifdef __cplusplus -} -#endif - - - #endif // FL_ANDROID_APPLICATION_H // diff --git a/src/drivers/Android/Fl_Android_Application.cxx b/src/drivers/Android/Fl_Android_Application.cxx index c1d69b9f8..97b692199 100644 --- a/src/drivers/Android/Fl_Android_Application.cxx +++ b/src/drivers/Android/Fl_Android_Application.cxx @@ -25,6 +25,7 @@ #include "Fl_Android_Application.H" #include "Fl_Android_Window_Driver.H" +#include <FL/platform.H> #include <FL/fl_draw.H> #include <jni.h> diff --git a/src/drivers/Android/Fl_Android_Graphics_Driver.H b/src/drivers/Android/Fl_Android_Graphics_Driver.H index dcfd27446..95d97880a 100644 --- a/src/drivers/Android/Fl_Android_Graphics_Driver.H +++ b/src/drivers/Android/Fl_Android_Graphics_Driver.H @@ -41,6 +41,13 @@ class Fl_Android_Bytemap; */ class FL_EXPORT Fl_Android_Graphics_Driver : public Fl_Scalable_Graphics_Driver { + class Vertex { + public: + void set(float x, float y, bool gap = false) { pX = x; pY = y; pIsGap = gap; } + float pX, pY; + bool pIsGap; + }; + public: Fl_Android_Graphics_Driver(); virtual ~Fl_Android_Graphics_Driver() override; @@ -62,15 +69,34 @@ public: virtual Fl_Font set_fonts(const char *name) override; virtual void font_name(int num, const char *name) override; - // --- line drawinf stuff + // --- line drawing stuff virtual void rectf_unscaled(float x, float y, float w, float h) override; void rectf_unclipped(float x, float y, float w, float h); virtual void point_unscaled(float x, float y) override; - void rect_unscaled(float x, float y, float w, float h); + virtual void rect_unscaled(float x, float y, float w, float h) override; virtual void xyline_unscaled(float x, float y, float x1) override; void xyline_unclipped(float x, float y, float x1); virtual void yxline_unscaled(float x, float y, float y1) override; void yxline_unclipped(float x, float y, float y1); + virtual void line_unscaled(float x, float y, float x1, float y1) override; + + // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx + virtual void begin_points() override; + virtual void begin_line() override; + virtual void begin_loop() override; + virtual void begin_polygon() override; + virtual void begin_complex_polygon() override; + virtual void end_points() override; + virtual void end_line() override; + virtual void end_loop() override; + virtual void end_polygon() override; + void end_polygon(int begin, int end); + virtual void end_complex_polygon() override; + virtual void gap() override; + virtual void transformed_vertex0(float x, float y) override; + + virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2); + virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2); // --- clipping virtual void push_clip(int x, int y, int w, int h) override; @@ -118,30 +144,18 @@ public: static HRGN scale_region(HRGN r, float f, Fl_GDI_Graphics_Driver *dr); virtual void scale(float f); protected: - void transformed_vertex0(float x, float y); void fixloop(); // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/gdi_rect.cxx - virtual void line_unscaled(float x, float y, float x1, float y1); virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2); virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); virtual Fl_Region scale_clip(float f); - // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx - void begin_complex_polygon(); - void end_points(); - void end_line(); - void end_loop(); - void end_polygon(); - void end_complex_polygon(); - void gap(); virtual void ellipse_unscaled(double xt, double yt, double rx, double ry); // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end); // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx - virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2); - virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2); // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx virtual void line_style_unscaled(int style, float width, char* dashes); // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx @@ -176,6 +190,11 @@ protected: // Final clipping region for all graphics calls to this class. Fl_Complex_Region pClippingRegion; + + void begin_vertices(); + void add_vertex(float x, float y, bool gap=false); + int pnVertex = 0, pNVertex = 0, pVertexGapStart = 0; + Vertex *pVertex = nullptr; }; diff --git a/src/drivers/Android/Fl_Android_Graphics_Driver.cxx b/src/drivers/Android/Fl_Android_Graphics_Driver.cxx index 71ffa6224..fbd85fc34 100644 --- a/src/drivers/Android/Fl_Android_Graphics_Driver.cxx +++ b/src/drivers/Android/Fl_Android_Graphics_Driver.cxx @@ -24,7 +24,9 @@ #include <FL/Fl.H> #include <FL/platform.H> #include <errno.h> +#include <math.h> +static int sign(int v) { return (v<0) ? -1 : 1; } /* * By linking this module, the following static method will instantiate the @@ -229,6 +231,451 @@ void Fl_Android_Graphics_Driver::point_unscaled(float x, float y) } +/** + * Draw a line. + * FIXME: it is incredibly inefficient to call 'point', especially for long lines + * FIXME: clipping maust be moved into this call and drawing to the screen should happen right here + * FIXME: line width is not considered + */ +void Fl_Android_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1) +{ + if (x==x1) { + return yxline(x, y, y1); + } + if (y==y1) { + return xyline(x, y, x1); + } + // Bresenham + int w = x1 - x, dx = abs(w); + int h = y1 - y, dy = abs(h); + int dx1 = sign(w), dy1 = sign(h), dx2, dy2; + int min, max; + if (dx < dy) { + min = dx; max = dy; + dx2 = 0; + dy2 = dy1; + } else { + min = dy; max = dx; + dx2 = dx1; + dy2 = 0; + } + int num = max/2; + for (int i=max+1; i>0; i--) { + point_unscaled(x, y); + num += min; + if (num>=max) { + num -= max; + x += dx1; + y += dy1; + } else { + x += dx2; + y += dy2; + } + } +} + +/** + * Reset the vertex counter to zero. + */ +void Fl_Android_Graphics_Driver::begin_vertices() +{ + pnVertex = 0; + pVertexGapStart = 0; +} + +/** + * Add a vertex to the vertex list. Dynamically allocates memory. + * @param x, y position of the vertex after matrix transformation + * @param gap line and loop call offer to leave a gap in the drawing + */ +void Fl_Android_Graphics_Driver::add_vertex(float x, float y, bool gap) +{ + if (pnVertex == pNVertex) { + pNVertex += 16; + pVertex = (Vertex*)::realloc(pVertex, pNVertex*sizeof(Vertex)); + } + pVertex[pnVertex].set(x, y); + pVertex[pnVertex].pIsGap = gap; + pnVertex++; +} + +/** + * Start a list of vertices to draw multiple points. + */ +void Fl_Android_Graphics_Driver::begin_points() +{ + begin_vertices(); + Fl_Scalable_Graphics_Driver::begin_points(); +} + +/** + * Start a list of vertices to draw a polyline. + */ +void Fl_Android_Graphics_Driver::begin_line() +{ + begin_vertices(); + Fl_Scalable_Graphics_Driver::begin_line(); +} + +/** + * Start a list of vertices to draw a line loop. + */ +void Fl_Android_Graphics_Driver::begin_loop() +{ + begin_vertices(); + Fl_Scalable_Graphics_Driver::begin_loop(); +} + +/** + * Start a list of vertices to draw a polygon. + */ +void Fl_Android_Graphics_Driver::begin_polygon() +{ + begin_vertices(); + Fl_Scalable_Graphics_Driver::begin_polygon(); +} + +/** + * Start a list of vertices to draw a complex polygon. + */ +void Fl_Android_Graphics_Driver::begin_complex_polygon() +{ + begin_vertices(); + Fl_Scalable_Graphics_Driver::begin_complex_polygon(); +} + +/** + * Draw all stored vertices as points. + */ +void Fl_Android_Graphics_Driver::end_points() +{ + for (int i=0; i<pnVertex; ++i) { + Vertex &v = pVertex[i]; + if (!v.pIsGap) + point_unscaled(v.pX, v.pY); + } +} + +/** + * Draw all stored vertices as a polyline. + */ +void Fl_Android_Graphics_Driver::end_line() +{ + Vertex &v1 = pVertex[0]; + for (int i=1; i<pnVertex; ++i) { + Vertex &v2 = pVertex[i]; + if (!v1.pIsGap && !v2.pIsGap) + line_unscaled(v1.pX, v1.pY, v2.pX, v2.pY); + v1 = v2; + } +} + +/** + * Draw all stored vertices as a polyline loop. + */ +void Fl_Android_Graphics_Driver::end_loop() +{ + gap(); + Vertex &v1 = pVertex[0]; + for (int i=1; i<pnVertex; ++i) { + Vertex &v2 = pVertex[i]; + if (!v1.pIsGap) + line_unscaled(v1.pX, v1.pY, v2.pX, v2.pY); + v1 = v2; + } +} + +/** + * Draw all stored vertices as a polygon. + * FIXME: these calls are very ineffiecient. Avoid pointer lookup. + * FIXME: use the current clipping rect to accelerate rendering + * FIXME: unmix float and int + */ +void Fl_Android_Graphics_Driver::end_polygon(int begin, int end) +{ + if (end - begin < 2) return; + + Vertex *v = pVertex+0; + int xMin = v->pX, xMax = xMin, yMin = v->pY, yMax = yMin; + for (int i = begin+1; i < end; i++) { + v = pVertex+i; + if (v->pX < xMin) xMin = v->pX; + if (v->pX > xMax) xMax = v->pX; + if (v->pY < yMin) yMin = v->pY; + if (v->pY > yMax) yMax = v->pY; + } + xMax++; yMax++; + + int nodes, nodeX[end - begin], pixelX, pixelY, i, j, swap; + + // Loop through the rows of the image. + for (pixelY = yMin; pixelY < yMax; pixelY++) { + // Build a list of nodes. + nodes = 0; + j = begin; + for (i = begin+1; i < end; i++) { + if ( pVertex[i].pY < pixelY && pVertex[j].pY >= pixelY + || pVertex[j].pY < pixelY && pVertex[i].pY >= pixelY) + { + float dy = pVertex[j].pY - pVertex[i].pY; + if (fabsf(dy)>.0001) { + nodeX[nodes++] = (int)(pVertex[i].pX + + (pixelY - pVertex[i].pY) / dy + * (pVertex[j].pX - pVertex[i].pX)); + } else { + nodeX[nodes++] = pVertex[i].pX; + } + } + j = i; + } + + // Sort the nodes, via a simple “Bubble” sort. + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + // Fill the pixels between node pairs. + for (i = 0; i < nodes; i += 2) { + if (nodeX[i] >= xMax) break; + if (nodeX[i + 1] > xMin) { + if (nodeX[i] < xMin) nodeX[i] = xMin; + if (nodeX[i + 1] > xMax) nodeX[i + 1] = xMax; + xyline_unscaled(nodeX[i], pixelY, nodeX[i + 1]); + } + } + } + +} + +/** + * Draw all stored vertices as a polygon. + * Mind the gap! + */ +void Fl_Android_Graphics_Driver::end_polygon() +{ + if (pnVertex==0) return; + gap(); + int start = 0, end = 0; + for (int i=0; i<pnVertex; i++) { + if (pVertex[i].pIsGap) { + end = i+1; + end_polygon(start, end); + start = end; + i++; + } + } +} + +/** + * Draw all stored vertices as a possibly self-intersecting polygon. + * FIXME: these calls are very ineffiecient. Avoid pointer lookup. + * FIXME: use the current clipping rect to accelerate rendering + * FIXME: unmix float and int + */ +void Fl_Android_Graphics_Driver::end_complex_polygon() +{ + if (pnVertex < 2) return; + + gap(); // adds the first coordinate of this loop and marks it as a gap + int begin = 0, end = pnVertex; + + Vertex *v = pVertex+0; + int xMin = v->pX, xMax = xMin, yMin = v->pY, yMax = yMin; + for (int i = begin+1; i < end; i++) { + v = pVertex+i; + if (v->pX < xMin) xMin = v->pX; + if (v->pX > xMax) xMax = v->pX; + if (v->pY < yMin) yMin = v->pY; + if (v->pY > yMax) yMax = v->pY; + } + xMax++; yMax++; + + int nodes, nodeX[end - begin], pixelX, pixelY, i, j, swap; + + // Loop through the rows of the image. + for (pixelY = yMin; pixelY < yMax; pixelY++) { + // Build a list of nodes. + nodes = 0; + for (i = begin+1; i < end; i++) { + j = i-1; + if (pVertex[j].pIsGap) + continue; + if ( pVertex[i].pY < pixelY && pVertex[j].pY >= pixelY + || pVertex[j].pY < pixelY && pVertex[i].pY >= pixelY) + { + float dy = pVertex[j].pY - pVertex[i].pY; + if (fabsf(dy)>.0001) { + nodeX[nodes++] = (int)(pVertex[i].pX + + (pixelY - pVertex[i].pY) / dy + * (pVertex[j].pX - pVertex[i].pX)); + } else { + nodeX[nodes++] = pVertex[i].pX; + } + } + } + //Fl_Android_Application::log_e("%d nodes (must be even!)", nodes); + + // Sort the nodes, via a simple “Bubble” sort. + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + // Fill the pixels between node pairs. + for (i = 0; i < nodes; i += 2) { + if (nodeX[i] >= xMax) break; + if (nodeX[i + 1] > xMin) { + if (nodeX[i] < xMin) nodeX[i] = xMin; + if (nodeX[i + 1] > xMax) nodeX[i + 1] = xMax; + xyline_unscaled(nodeX[i], pixelY, nodeX[i + 1]); + } + } + } +} + +/** + * Add a gap to a polyline drawing + */ +void Fl_Android_Graphics_Driver::gap() +{ + // drop gaps at the start or gap after gap + if (pnVertex==0 || pnVertex==pVertexGapStart) + return; + + // create a loop + Vertex &v = pVertex[pVertexGapStart]; + add_vertex(v.pX, v.pY, true); + pVertexGapStart = pnVertex; +} + +/** + * Add a vertex to the list. + * TODO: we should maintain a bounding box for faster clipping. + */ +void Fl_Android_Graphics_Driver::transformed_vertex0(float x, float y) +{ + add_vertex(x, y); +} + + +//void Fl_Pico_Graphics_Driver::circle(double x, double y, double r) +//{ +// begin_loop(); +// double X = r; +// double Y = 0; +// fl_vertex(x+X,y+Y); +// +// double rx = fabs(transform_dx(r, r)); +// double ry = fabs(transform_dy(r, r)); +// +// double circ = M_PI*0.5*(rx+ry); +// int segs = circ * 360 / 1000; // every line is about three pixels long +// if (segs<16) segs = 16; +// +// double A = 2*M_PI; +// int i = segs; +// +// if (i) { +// double epsilon = A/i; // Arc length for equal-size steps +// double cos_e = cos(epsilon); // Rotation coefficients +// double sin_e = sin(epsilon); +// do { +// double Xnew = cos_e*X + sin_e*Y; +// Y = -sin_e*X + cos_e*Y; +// fl_vertex(x + (X=Xnew), y + Y); +// } while (--i); +// } +// end_loop(); +//} + +/** + * Draw an arc. + * @param xi + * @param yi + * @param w + * @param h + * @param a1 + * @param a2 + * FIXME: float-to-int interpolation is horrible! + */ +void Fl_Android_Graphics_Driver::arc_unscaled(float xi, float yi, float w, float h, double a1, double a2) +{ + if (a2<=a1) return; + + double rx = w/2.0; + double ry = h/2.0; + double x = xi + rx; + double y = yi + ry; + double circ = M_PI*0.5*(rx+ry); + int i, segs = circ * (a2-a1) / 1000; // every line is about three pixels long + if (segs<3) segs = 3; + + int px, py; + a1 = a1/180*M_PI; + a2 = a2/180*M_PI; + double step = (a2-a1)/segs; + + int nx = x + cos(a1)*rx; + int ny = y - sin(a1)*ry; + for (i=segs; i>0; i--) { + a1+=step; + px = nx; py = ny; + nx = x + cos(a1)*rx; + ny = y - sin(a1)*ry; + line_unscaled(px, py, nx, ny); + } +} + +void Fl_Android_Graphics_Driver::pie_unscaled(float xi, float yi, float w, float h, double b1, double b2) +{ + Fl_Color c = fl_color(); + fl_color(FL_RED); + double a1 = b1/180*M_PI; + double a2 = b2/180*M_PI; + double rx = w/2.0; + double ry = h/2.0; + double x = xi + rx; + double y = yi + ry; + double yMin = y - sin(a1), yMax = y - sin(a2); + if (yMin>yMax) { double s = yMin; yMin = yMax; yMax = s; } + Fl_Android_Application::log_e("------ PI"); + for (double i=y-ry; i<=y+ry; i++) { + double a = asin((i-y)/ry); + double aR = a; if (aR<0.0) aR+=2*M_PI; + double aL = M_PI-a; + Fl_Android_Application::log_e("%g %g", aL, aR); +#if 0 + if (aL>=a1 && aL<=a2) + xyline_unscaled(x-cos(a)*rx, i, x); + + if (aR>=a1 && aR<=a2) + xyline_unscaled(x, i, x+cos(a)*rx); +#else + xyline_unscaled(x-cos(a)*rx, i, x+cos(a)*rx); +#endif + //xyline_unscaled(sin(a)*rx, i, y); + } + fl_color(FL_GREEN); + line_unscaled(x, y, x+cos(0.5*M_PI)*rx, y+sin(0.5*M_PI)*ry); + fl_color(c); +} + + #if 0 diff --git a/src/drivers/Android/Fl_Android_Graphics_Font.cxx b/src/drivers/Android/Fl_Android_Graphics_Font.cxx index 5a06a0ad7..da8f9ddf4 100644 --- a/src/drivers/Android/Fl_Android_Graphics_Font.cxx +++ b/src/drivers/Android/Fl_Android_Graphics_Font.cxx @@ -517,11 +517,11 @@ void Fl_Android_Graphics_Driver::draw_unscaled(const char* str, int n, int x, in if (str) { int dx, dy, w, h; text_extents_unscaled(str, n, dx, dy, w, h); - pClippingRegion.print("<---- clip text to this"); - Fl_Rect_Region(x+dx, y+dy, w, h).print(str); + //pClippingRegion.print("<---- clip text to this"); + //Fl_Rect_Region(x+dx, y+dy, w, h).print(str); for (const auto &it: pClippingRegion.overlapping(Fl_Rect_Region(x+dx, y+dy, w, h))) { Fl_Rect_Region &r = it->clipped_rect(); - r.print("Clip"); + //r.print("Clip"); const char *e = str + n; for (int i = 0; i < n;) { int incr = 1; |
