| /* |
| * Copyright 2019 University of Toronto |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Authors: Mario Badr, Sameh Attia and Tanner Young-Schultz |
| */ |
| |
| #ifndef EZGL_GRAPHICS_HPP |
| #define EZGL_GRAPHICS_HPP |
| |
| #include "ezgl/color.hpp" |
| #include "ezgl/point.hpp" |
| #include "ezgl/rectangle.hpp" |
| #include "ezgl/camera.hpp" |
| |
| #include <cairo.h> |
| #include <gdk/gdk.h> |
| |
| #ifdef CAIRO_HAS_XLIB_SURFACE |
| #ifdef GDK_WINDOWING_X11 |
| #include <cairo-xlib.h> |
| |
| // Speed up draw calls by using X11 instead of cairo wherever possible. |
| #define EZGL_USE_X11 |
| #endif |
| #endif |
| |
| #include <functional> |
| #include <string> |
| #include <vector> |
| #include <cfloat> |
| #include <cmath> |
| #include <algorithm> |
| |
| namespace ezgl { |
| |
| /** |
| * define ezgl::surface type used for drawing pngs |
| */ |
| typedef cairo_surface_t surface; |
| |
| /** |
| * Available coordinate systems |
| */ |
| enum t_coordinate_system { |
| /** |
| * Default coordinate system |
| */ |
| WORLD, |
| /** |
| * Screen coordinate system. Screen Coordinates are not transformed so the drawn objects do not pan or zoom. |
| */ |
| SCREEN |
| }; |
| |
| /** |
| * Text justification options |
| */ |
| enum class text_just { |
| /** |
| * Center Justification: used for both vertical and horizontal justification |
| */ |
| center, |
| /** |
| * Left justification: used for horizontal justification |
| */ |
| left, |
| /** |
| * Right justification: used for horizontal justification |
| */ |
| right, |
| /** |
| * Top justification: used for vertical justification |
| */ |
| top, |
| /** |
| * Bottom justification: used for vertical justification |
| */ |
| bottom |
| }; |
| |
| /** |
| * The slant of the font. |
| * |
| * This enum is setup to match with the cairo graphics library and should not be changed. |
| */ |
| enum class font_slant : int { |
| /** |
| * No slant. |
| */ |
| normal = CAIRO_FONT_SLANT_NORMAL, |
| |
| /** |
| * Slant is more calligraphic. Make sure the font you're using has an italic design, otherwise it may look ugly. |
| */ |
| italic = CAIRO_FONT_SLANT_ITALIC, |
| |
| /** |
| * Slanted to the right. |
| */ |
| oblique = CAIRO_FONT_SLANT_OBLIQUE |
| }; |
| |
| /** |
| * The weight of the font. |
| */ |
| enum class font_weight : int { |
| /** |
| * No additional weight. |
| */ |
| normal = CAIRO_FONT_WEIGHT_NORMAL, |
| |
| /** |
| * Bold font weight. |
| */ |
| bold = CAIRO_FONT_WEIGHT_BOLD |
| }; |
| |
| /** |
| * The shape of a line's start and end point. |
| */ |
| enum class line_cap : int { |
| /** |
| * Start and stop the line exactly where it begins/ends. |
| */ |
| butt = CAIRO_LINE_CAP_BUTT, |
| |
| /** |
| * Each end of the line has circles. |
| */ |
| round = CAIRO_LINE_CAP_ROUND |
| }; |
| |
| /** |
| * The dash style of a line. |
| */ |
| enum class line_dash : int { |
| /** |
| * No dashes in the line (i.e., solid). |
| */ |
| none, |
| |
| /** |
| * Dash to whitespace ratio is 5:3. |
| */ |
| asymmetric_5_3 |
| }; |
| |
| /** |
| * Provides functions to draw primitives (e.g., lines, shapes) to a rendering context. |
| * |
| * The renderer modifies a cairo_t context based on draw calls. The renderer uses an ezgl::camera object to convert |
| * world coordinates into cairo's expected coordinate system. |
| */ |
| class renderer { |
| public: |
| /** |
| * Change the current coordinate system |
| * |
| * @param new_coordinate_system The drawing coordinate system SCREEN or WORLD |
| */ |
| void set_coordinate_system(t_coordinate_system new_coordinate_system); |
| |
| /** |
| * Set the visible bounds of the world |
| * |
| * The function preserves the aspect ratio of the initial world |
| * |
| * @param new_world The new visible bounds of the world |
| */ |
| void set_visible_world(rectangle new_world); |
| |
| /** |
| * Get the current visible bounds of the world |
| */ |
| rectangle get_visible_world(); |
| |
| /** |
| * Get the current visible bounds of the screen |
| */ |
| rectangle get_visible_screen(); |
| |
| /** |
| * Get the screen coordinates (i.e. pixel locations) of the world coordinate rectangle box |
| * |
| * @param box: a rectangle in world coordinates |
| */ |
| rectangle world_to_screen(const rectangle& box); |
| |
| /**** Functions to set graphics attributes (for all subsequent drawing calls). ****/ |
| |
| /** |
| * Change the color for subsequent draw calls. |
| * |
| * @param new_color The new color to use. |
| */ |
| void set_color(color new_color); |
| |
| /** |
| * Change the color for subsequent draw calls. |
| * |
| * @param new_color The new color to use. |
| * @param alpha Overwrite the alpha channel in the chosen color. |
| */ |
| void set_color(color new_color, uint_fast8_t alpha); |
| |
| /** |
| * Change the color for subsequent draw calls. |
| * |
| * @param red The amount of red to use, between 0 and 255. |
| * @param green The amount of green to use, between 0 and 255. |
| * @param blue The amount of blue to use, between 0 and 255. |
| * @param alpha The transparency level (0 is fully transparent, 255 is opaque). |
| */ |
| void set_color(uint_fast8_t red, uint_fast8_t green, uint_fast8_t blue, uint_fast8_t alpha = 255); |
| |
| /** |
| * Change how line endpoints will be rendered in subsequent draw calls. |
| */ |
| void set_line_cap(line_cap cap); |
| |
| /** |
| * Change the dash style of the line. |
| */ |
| void set_line_dash(line_dash dash); |
| |
| /** |
| * Set the line width. |
| * |
| * @param width The width in pixels. |
| * A value of 0 is still one pixel wide but about 100x faster |
| * to draw than other line widths. |
| */ |
| void set_line_width(int width); |
| |
| /** |
| * Change the font size. |
| * |
| * @param new_size The new size text should be drawn at. |
| */ |
| void set_font_size(double new_size); |
| |
| /** |
| * Change the font. |
| * |
| * @param family The font family to use (e.g., serif) |
| * @param slant The slant to use (e.g., italic) |
| * @param weight The weight of the font (e.g., bold) |
| */ |
| void format_font(std::string const &family, font_slant slant, font_weight weight); |
| |
| /** |
| * Change the font. |
| * |
| * @param family The font family to use (e.g., serif) |
| * @param slant The slant to use (e.g., italic) |
| * @param weight The weight of the font (e.g., bold) |
| * @param new_size The new size text should be drawn at. |
| */ |
| void |
| format_font(std::string const &family, font_slant slant, font_weight weight, double new_size); |
| |
| /** |
| * set the rotation_angle variable that is used in rotating text. |
| * |
| * @param degrees The angle by which the text should rotate, in degrees. |
| */ |
| void set_text_rotation(double degrees); |
| |
| /** |
| * set horizontal text justification. |
| * |
| * @param horiz_just Options: center, left and right justification. |
| */ |
| void set_horiz_text_just(text_just horiz_just); |
| |
| /** |
| * set vertical text justification. |
| * |
| * @param vert_just Options: center, top and bottom justification. |
| */ |
| void set_vert_text_just(text_just vert_just); |
| |
| /**** Functions to draw various graphics primitives ****/ |
| |
| /** |
| * Draw a line. |
| * |
| * @param start The start point of the line, in pixels. |
| * @param end The end point of the line, in pixels. |
| */ |
| void draw_line(point2d start, point2d end); |
| |
| /** |
| * Draw the outline a rectangle. |
| * |
| * @param start The start point of the rectangle, in pixels. |
| * @param end The end point of the rectangle, in pixels. |
| */ |
| void draw_rectangle(point2d start, point2d end); |
| |
| /** |
| * Draw the outline of a rectangle. |
| * |
| * @param start The start point of the rectangle, in pixels. |
| * @param width How wide the rectangle is, in pixels. |
| * @param height How high the rectangle is, in pixels. |
| */ |
| void draw_rectangle(point2d start, double width, double height); |
| |
| /** |
| * Draw the outline of a rectangle. |
| */ |
| void draw_rectangle(rectangle r); |
| |
| /** |
| * Draw a filled in rectangle. |
| * |
| * @param start The start point of the rectangle, in pixels. |
| * @param end The end point of the rectangle, in pixels. |
| */ |
| void fill_rectangle(point2d start, point2d end); |
| |
| /** |
| * Draw a filled in rectangle. |
| * |
| * @param start The start point of the rectangle, in pixels. |
| * @param width How wide the rectangle is, in pixels. |
| * @param height How high the rectangle is, in pixels. |
| */ |
| void fill_rectangle(point2d start, double width, double height); |
| |
| /** |
| * Draw a filled in rectangle. |
| */ |
| void fill_rectangle(rectangle r); |
| |
| /** |
| * Draw a filled polygon. |
| * |
| * @param points The points to draw. The first and last points are connected to close the polygon. |
| */ |
| void fill_poly(std::vector<point2d> const &points); |
| |
| /** |
| * Draw the outline of an elliptic arc. |
| * |
| * @param center The center of the arc, in pixels. |
| * @param radius_x The x radius of the elliptic arc, in pixels. |
| * @param radius_y The y radius of the elliptic arc, in pixels. |
| * @param start_angle The starting angle of the arc, in degrees. |
| * @param extent_angle The extent angle of the arc, in degrees. |
| */ |
| void draw_elliptic_arc(point2d center, |
| double radius_x, |
| double radius_y, |
| double start_angle, |
| double extent_angle); |
| |
| /** |
| * Draw the outline of an arc. |
| * |
| * @param center The center of the arc, in pixels. |
| * @param radius The radius of the arc, in pixels. |
| * @param start_angle The starting angle of the arc, in degrees. |
| * @param extent_angle The extent angle of the arc, in degrees. |
| */ |
| void draw_arc(point2d center, double radius, double start_angle, double extent_angle); |
| |
| /** |
| * Draw a filled in elliptic arc. |
| * |
| * @param center The center of the arc, in pixels. |
| * @param radius_x The x radius of the elliptic arc, in pixels. |
| * @param radius_y The y radius of the elliptic arc, in pixels. |
| * @param start_angle The starting angle of the arc, in degrees. |
| * @param extent_angle The extent angle of the arc, in degrees. |
| */ |
| void fill_elliptic_arc(point2d center, |
| double radius_x, |
| double radius_y, |
| double start_angle, |
| double extent_angle); |
| |
| /** |
| * Draw a filled in arc. |
| * |
| * @param center The center of the arc, in pixels. |
| * @param radius The radius of the arc, in pixels. |
| * @param start_angle The starting angle of the arc, in degrees. |
| * @param extent_angle The extent angle of the arc, in degrees. |
| */ |
| void fill_arc(point2d center, double radius, double start_angle, double extent_angle); |
| |
| /** |
| * Draw text. |
| * |
| * @param point The point where the text is drawn, in pixels. |
| * @param text The text to draw. |
| */ |
| void draw_text(point2d point, std::string const &text); |
| |
| /** |
| * Draw text with bounds. |
| * |
| * @param point The point where the text is drawn, in pixels. |
| * @param text The text to draw. |
| * @param bound_x The maximum allowed width of the text |
| * @param bound_y The maximum allowed height of the text |
| */ |
| void draw_text(point2d point, std::string const &text, double bound_x, double bound_y); |
| |
| /** |
| * Draw a surface |
| * |
| * @param surface The surface to draw |
| * @param top_left The corner point of the drawn surface. |
| */ |
| void draw_surface(surface *surface, point2d top_left); |
| |
| /** |
| * load a png image |
| * |
| * @param file_path The path to the png image. |
| * |
| * @return a pointer to the created surface. Should be freed using free_surface() |
| */ |
| static surface *load_png(const char *file_path); |
| |
| /** |
| * Free a surface |
| * |
| * @param surface The surface to destroy |
| */ |
| static void free_surface(surface *surface); |
| |
| /** |
| * Destructor. |
| */ |
| ~renderer(); |
| |
| protected: |
| // Only the canvas class can create a renderer. |
| friend class canvas; |
| |
| /** |
| * A callback for transforming points from one coordinate system to another. |
| */ |
| using transform_fn = std::function<point2d(point2d)>; |
| |
| /** |
| * Constructor. |
| * |
| * @param cairo The cairo graphics state. |
| * @param transform The function to use to transform points to cairo's coordinate system. |
| */ |
| renderer(cairo_t *cairo, transform_fn transform, camera *m_camera, cairo_surface_t *m_surface); |
| |
| /** |
| * Update the renderer when the cairo surface/context changes |
| * |
| * @param cairo The new cairo graphics state |
| * @param m_surface The new cairo surface |
| */ |
| void update_renderer(cairo_t *cairo, cairo_surface_t *m_surface); |
| |
| private: |
| void draw_rectangle_path(point2d start, point2d end, bool fill_flag); |
| |
| void draw_arc_path(point2d center, |
| double radius, |
| double start_angle, |
| double extent_angle, |
| double stretch_factor, |
| bool fill_flag); |
| |
| // Pre-clipping function |
| bool rectangle_off_screen(rectangle rect); |
| |
| // Current coordinate system (World is the default) |
| t_coordinate_system current_coordinate_system = WORLD; |
| |
| // A non-owning pointer to a cairo graphics context. |
| cairo_t *m_cairo; |
| |
| #ifdef EZGL_USE_X11 |
| // The x11 drawable |
| Drawable x11_drawable; |
| |
| // The x11 display |
| Display *x11_display = nullptr; |
| |
| // The x11 context |
| GC x11_context; |
| |
| // Transparency flag, if set, cairo will be used |
| bool transparency_flag = false; |
| #endif |
| |
| transform_fn m_transform; |
| |
| //A non-owning pointer to camera object |
| camera *m_camera; |
| |
| // the rotation angle variable used in rotating text |
| double rotation_angle; |
| |
| // Current horizontal text justification |
| text_just horiz_text_just = text_just::center; |
| |
| // Current vertical text justification |
| text_just vert_text_just = text_just::center; |
| |
| // Current line width |
| int current_line_width = 1; |
| |
| // Current line cap |
| line_cap current_line_cap = line_cap::butt; |
| |
| // Current line dash |
| line_dash current_line_dash = line_dash::none; |
| |
| // Current color |
| color current_color = {0, 0, 0, 255}; |
| }; |
| } |
| |
| #endif //EZGL_GRAPHICS_HPP |