540 lines
13 KiB
C++
540 lines
13 KiB
C++
|
/*
|
||
|
* 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
|