//----------------------------------------------------------------------------- // Backend-agnostic rendering interface, and various backends we use. // // Copyright 2016 whitequark //----------------------------------------------------------------------------- #ifndef SOLVESPACE_RENDER_H #define SOLVESPACE_RENDER_H enum class StipplePattern : uint32_t; // A mapping from 3d sketch coordinates to 2d screen coordinates, using // an axonometric projection. class Camera { public: size_t width, height; Vector offset; Vector projRight; Vector projUp; double scale; double tangent; bool hasPixels; bool IsPerspective() const { return tangent != 0.0; } Point2d ProjectPoint(Vector p) const; Vector ProjectPoint3(Vector p) const; Vector ProjectPoint4(Vector p, double *w) const; Vector UnProjectPoint(Point2d p) const; Vector UnProjectPoint3(Vector p) const; Vector VectorFromProjs(Vector rightUpForward) const; Vector AlignToPixelGrid(Vector v) const; void LoadIdentity(); void NormalizeProjectionVectors(); }; // A description of scene lighting. class Lighting { public: RgbaColor backgroundColor; double ambientIntensity; double lightIntensity[2]; Vector lightDirection[2]; }; // An interface for populating a drawing area with geometry. class Canvas { public: // Stroke and fill styles are addressed with handles to be able to quickly // group geometry into indexed draw calls. class hStroke { public: uint32_t v; }; class hFill { public: uint32_t v; }; // The layer of a geometry describes how it occludes other geometry. // Within a layer, geometry with higher z-index occludes geometry with lower z-index, // or geometry drawn earlier if z-indexes match. enum class Layer { NORMAL, // Occluded by geometry with lower Z coordinate OCCLUDED, // Only drawn over geometry with lower Z coordinate DEPTH_ONLY, // Like NORMAL, but only affects future occlusion, not color BACK, // Always drawn below all other geometry FRONT, // Always drawn above all other geometry }; // The outlines are the collection of all edges that may be drawn. // Outlines can be classified as emphasized or not; emphasized outlines indicate an abrupt // change in the surface curvature. These are indicated by the SOutline tag. // Outlines can also be classified as contour or not; contour outlines indicate the boundary // of the filled mesh. Whether an outline is a part of contour or not depends on point of view. enum class DrawOutlinesAs { EMPHASIZED_AND_CONTOUR, // Both emphasized and contour outlines EMPHASIZED_WITHOUT_CONTOUR, // Emphasized outlines except those also belonging to contour CONTOUR_ONLY // Contour outlines only }; class Stroke { public: hStroke h; Layer layer; int zIndex; RgbaColor color; double width; StipplePattern stipplePattern; double stippleScale; bool Equals(const Stroke &other) const; }; enum class FillPattern { SOLID, CHECKERED_A, CHECKERED_B }; class Fill { public: hFill h; Layer layer; int zIndex; RgbaColor color; FillPattern pattern; bool Equals(const Fill &other) const; }; IdList strokes; IdList fills; Canvas() : strokes(), fills() {}; hStroke GetStroke(const Stroke &stroke); hFill GetFill(const Fill &fill); virtual const Camera &GetCamera() const = 0; virtual void DrawLine(const Vector &a, const Vector &b, hStroke hcs) = 0; virtual void DrawEdges(const SEdgeList &el, hStroke hcs) = 0; virtual bool DrawBeziers(const SBezierList &bl, hStroke hcs) = 0; virtual void DrawOutlines(const SOutlineList &ol, hStroke hcs, DrawOutlinesAs drawAs) = 0; virtual void DrawVectorText(const std::string &text, double height, const Vector &o, const Vector &u, const Vector &v, hStroke hcs) = 0; virtual void DrawQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d, hFill hcf) = 0; virtual void DrawPoint(const Vector &o, double d, hFill hcf) = 0; virtual void DrawPolygon(const SPolygon &p, hFill hcf) = 0; virtual void DrawMesh(const SMesh &m, hFill hcfFront, hFill hcfBack = {}, hStroke hcsTriangles = {}) = 0; virtual void DrawFaces(const SMesh &m, const std::vector &faces, hFill hcf) = 0; virtual void DrawPixmap(std::shared_ptr pm, const Vector &o, const Vector &u, const Vector &v, const Point2d &ta, const Point2d &tb, hFill hcf) = 0; virtual void InvalidatePixmap(std::shared_ptr pm) = 0; }; // A wrapper around Canvas that simplifies drawing UI in screen coordinates. class UiCanvas { public: Canvas *canvas; bool flip; UiCanvas() : canvas(), flip() {}; void DrawLine(int x1, int y1, int x2, int y2, RgbaColor color, int width = 1); void DrawRect(int l, int r, int t, int b, RgbaColor fillColor, RgbaColor outlineColor); void DrawPixmap(std::shared_ptr pm, int x, int y); void DrawBitmapChar(char32_t codepoint, int x, int y, RgbaColor color); void DrawBitmapText(const std::string &str, int x, int y, RgbaColor color); int Flip(int y) const { return flip ? (int)canvas->GetCamera().height - y : y; } }; // A canvas that performs picking against drawn geometry. class ObjectPicker : public Canvas { public: Camera camera; // Configuration. Point2d point; double selRadius; // Picking state. double minDistance; int maxZIndex; uint32_t position; ObjectPicker() : camera(), point(), selRadius(), minDistance(), maxZIndex(), position() {} const Camera &GetCamera() const override { return camera; } void DrawLine(const Vector &a, const Vector &b, hStroke hcs) override; void DrawEdges(const SEdgeList &el, hStroke hcs) override; bool DrawBeziers(const SBezierList &bl, hStroke hcs) override { return false; } void DrawOutlines(const SOutlineList &ol, hStroke hcs, DrawOutlinesAs drawAs) override; void DrawVectorText(const std::string &text, double height, const Vector &o, const Vector &u, const Vector &v, hStroke hcs) override; void DrawQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d, hFill hcf) override; void DrawPoint(const Vector &o, double s, hFill hcf) override; void DrawPolygon(const SPolygon &p, hFill hcf) override; void DrawMesh(const SMesh &m, hFill hcfFront, hFill hcfBack, hStroke hcsTriangles) override; void DrawFaces(const SMesh &m, const std::vector &faces, hFill hcf) override; void DrawPixmap(std::shared_ptr pm, const Vector &o, const Vector &u, const Vector &v, const Point2d &ta, const Point2d &tb, hFill hcf) override; void InvalidatePixmap(std::shared_ptr pm) override {} void DoCompare(double distance, int zIndex, int comparePosition = 0); void DoQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d, int zIndex, int comparePosition = 0); bool Pick(std::function drawFn); }; // A canvas that uses the core OpenGL profile, for desktop systems. class OpenGl1Renderer : public Canvas { public: Camera camera; Lighting lighting; // Cached OpenGL state. struct { bool drawing; unsigned mode; // GLenum, but we don't include GL.h globally hStroke hcs; Stroke *stroke; hFill hcf; Fill *fill; std::weak_ptr texture; } current; OpenGl1Renderer() : camera(), lighting(), current() {} const Camera &GetCamera() const override { return camera; } void DrawLine(const Vector &a, const Vector &b, hStroke hcs) override; void DrawEdges(const SEdgeList &el, hStroke hcs) override; bool DrawBeziers(const SBezierList &bl, hStroke hcs) override { return false; } void DrawOutlines(const SOutlineList &ol, hStroke hcs, DrawOutlinesAs drawAs) override; void DrawVectorText(const std::string &text, double height, const Vector &o, const Vector &u, const Vector &v, hStroke hcs) override; void DrawQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d, hFill hcf) override; void DrawPoint(const Vector &o, double s, hFill hcf) override; void DrawPolygon(const SPolygon &p, hFill hcf) override; void DrawMesh(const SMesh &m, hFill hcfFront, hFill hcfBack, hStroke hcsTriangles) override; void DrawFaces(const SMesh &m, const std::vector &faces, hFill hcf) override; void DrawPixmap(std::shared_ptr pm, const Vector &o, const Vector &u, const Vector &v, const Point2d &ta, const Point2d &tb, hFill hcf) override; void InvalidatePixmap(std::shared_ptr pm) override; void SelectPrimitive(unsigned mode); void UnSelectPrimitive(); Stroke *SelectStroke(hStroke hcs); Fill *SelectFill(hFill hcf); void SelectTexture(std::shared_ptr pm); void DoFatLineEndcap(const Vector &p, const Vector &u, const Vector &v); void DoFatLine(const Vector &a, const Vector &b, double width); void DoLine(const Vector &a, const Vector &b, hStroke hcs); void DoPoint(Vector p, double radius); void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs); void UpdateProjection(bool flip = FLIP_FRAMEBUFFER); void BeginFrame(); void EndFrame(); std::shared_ptr ReadFrame(); static void GetIdent(const char **vendor, const char **renderer, const char **version); }; #endif