[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/KmolYuan/solvespace/python/src/render/render2d.cpp [Back]  [Original]

//-----------------------------------------------------------------------------
// Rendering projections to 2d surfaces: z-sorting, occlusion testing, etc.
//
// Copyright 2016 whitequark
//-----------------------------------------------------------------------------
#include "solvespace.h"

namespace SolveSpace {

// FIXME: The export coordinate system has a different handedness than display
// coordinate system; lighting and occlusion calculations are right-handed.
static Vector ProjectPoint3RH(const Camera &camera, Vector p) {
    p = p.Plus(camera.offset);

    Vector r;
    r.x = p.Dot(camera.projRight);
    r.y = p.Dot(camera.projUp);
    r.z = p.Dot(camera.projRight.Cross(camera.projUp));

    double w = 1 + r.z*camera.tangent*camera.scale;
    return r.ScaledBy(camera.scale/w);
}

//-----------------------------------------------------------------------------
// Accumulation of geometry
//-----------------------------------------------------------------------------

void SurfaceRenderer::DrawLine(const Vector &a, const Vector &b, hStroke hcs) {
    edges[hcs].AddEdge(ProjectPoint3RH(camera, a),
                       ProjectPoint3RH(camera, b));
}

void SurfaceRenderer::DrawEdges(const SEdgeList &el, hStroke hcs) {
    for(const SEdge &e : el.l) {
        edges[hcs].AddEdge(ProjectPoint3RH(camera, e.a),
                           ProjectPoint3RH(camera, e.b));
    }
}

bool SurfaceRenderer::DrawBeziers(const SBezierList &bl, hStroke hcs) {
    if(!CanOutputCurves())
        return false;

    for(const SBezier &b : bl.l) {
        SBezier pb = camera.ProjectBezier(b);
        beziers[hcs].l.Add(&pb);
    }
    return true;
}

void SurfaceRenderer::DrawOutlines(const SOutlineList &ol, hStroke hcs, DrawOutlinesAs drawAs) {
    Vector projDir = camera.projRight.Cross(camera.projUp);
    for(const SOutline &o : ol.l) {
        if(drawAs == DrawOutlinesAs::EMPHASIZED_AND_CONTOUR &&
                !(o.IsVisible(projDir) || o.tag != 0))
            continue;
        if(drawAs == DrawOutlinesAs::EMPHASIZED_WITHOUT_CONTOUR &&
                !(!o.IsVisible(projDir) && o.tag != 0))
            continue;
        if(drawAs == DrawOutlinesAs::CONTOUR_ONLY &&
                !(o.IsVisible(projDir)))
            continue;

        edges[hcs].AddEdge(ProjectPoint3RH(camera, o.a),
                           ProjectPoint3RH(camera, o.b));
    }
}

void SurfaceRenderer::DrawVectorText(const std::string &text, double height,
                                     const Vector &o, const Vector &u, const Vector &v,
                                     hStroke hcs) {
    auto traceEdge = [&](Vector a, Vector b) {
        edges[hcs].AddEdge(ProjectPoint3RH(camera, a),
                           ProjectPoint3RH(camera, b));
    };
    VectorFont::Builtin()->Trace(height, o, u, v, text, traceEdge, camera);
}

void SurfaceRenderer::DrawQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d,
                               hFill hcf) {
    Fill *fill = fills.FindById(hcf);
    ssassert(fill->layer == Layer::NORMAL ||
             fill->layer == Layer::DEPTH_ONLY ||
             fill->layer == Layer::FRONT ||
             fill->layer == Layer::BACK, "Unexpected mesh layer");

    Vector zOffset = {};
    if(fill->layer == Layer::BACK) {
        zOffset.z -= 1e6;
    } else if(fill->layer == Layer::FRONT) {
        zOffset.z += 1e6;
    }
    zOffset.z += camera.scale * fill->zIndex;

    STriMeta meta = {};
    if(fill->layer != Layer::DEPTH_ONLY) {
        meta.color = fill->color;
    }
    Vector ta = ProjectPoint3RH(camera, a).Plus(zOffset),
           tb = ProjectPoint3RH(camera, b).Plus(zOffset),
           tc = ProjectPoint3RH(camera, c).Plus(zOffset),
           td = ProjectPoint3RH(camera, d).Plus(zOffset);
    mesh.AddTriangle(meta, tc, tb, ta);
    mesh.AddTriangle(meta, ta, td, tc);
}

void SurfaceRenderer::DrawPoint(const Vector &o, Canvas::hStroke hcs) {
    Stroke *stroke = strokes.FindById(hcs);

    Fill fill = {};
    fill.layer  = stroke->layer;
    fill.zIndex = stroke->zIndex;
    fill.color  = stroke->color;
    hFill hcf = GetFill(fill);

    Vector u = camera.projRight.ScaledBy(stroke->width/2.0/camera.scale),
           v = camera.projUp.ScaledBy(stroke->width/2.0/camera.scale);
    DrawQuad(o.Minus(u).Minus(v), o.Minus(u).Plus(v),
             o.Plus(u).Plus(v),   o.Plus(u).Minus(v), hcf);
}

void SurfaceRenderer::DrawPolygon(const SPolygon &p, hFill hcf) {
    SMesh m = {};
    p.TriangulateInto(&m);
    DrawMesh(m, hcf, {});
    m.Clear();
}

void SurfaceRenderer::DrawMesh(const SMesh &m,
                               hFill hcfFront, hFill hcfBack) {
    Fill *fill = fills.FindById(hcfFront);
    ssassert(fill->layer == Layer::NORMAL ||
             fill->layer == Layer::DEPTH_ONLY, "Unexpected mesh layer");

    Vector l0 = (lighting.lightDirection[0]).WithMagnitude(1),
           l1 = (lighting.lightDirection[1]).WithMagnitude(1);
    for(STriangle tr : m.l) {
        tr.a = ProjectPoint3RH(camera, tr.a);
        tr.b = ProjectPoint3RH(camera, tr.b);
        tr.c = ProjectPoint3RH(camera, tr.c);

        if(CanOutputTriangles() && fill->layer == Layer::NORMAL) {
            if(fill->color.IsEmpty()) {
                // Compute lighting, since we're going to draw the shaded triangles.
                Vector n = tr.Normal().WithMagnitude(1);
                double intensity = lighting.ambientIntensity +
                                        max(0.0, (lighting.lightIntensity[0])*(n.Dot(l0))) +
                                        max(0.0, (lighting.lightIntensity[1])*(n.Dot(l1)));
                double r = min(1.0, tr.meta.color.redF()   * intensity),
                       g = min(1.0, tr.meta.color.greenF() * intensity),
                       b = min(1.0, tr.meta.color.blueF()  * intensity);
                tr.meta.color = RGBf(r, g, b);
            } else {
                // We're going to draw this triangle, but it's not shaded.
                tr.meta.color = fill->color;
            }
        } else {
            // This triangle is just for occlusion testing.
            tr.meta.color = {};
        }
        mesh.AddTriangle(&tr);
    }
}

void SurfaceRenderer::DrawFaces(const SMesh &m, const std::vector &faces, hFill hcf) {
    Fill *fill = fills.FindById(hcf);
    ssassert(fill->layer == Layer::NORMAL ||
             fill->layer == Layer::DEPTH_ONLY, "Unexpected mesh layer");

    Vector zOffset = {};
    zOffset.z += camera.scale * fill->zIndex;

    size_t facesSize = faces.size();
    for(STriangle tr : m.l) {
        uint32_t face = tr.meta.face;
        for(size_t j = 0; j < facesSize; j++) {
            if(faces[j] != face) continue;
            if(!fill->color.IsEmpty()) {
                tr.meta.color = fill->color;
            }
            mesh.AddTriangle(tr.meta,
                ProjectPoint3RH(camera, tr.a).Plus(zOffset),
                ProjectPoint3RH(camera, tr.b).Plus(zOffset),
                ProjectPoint3RH(camera, tr.c).Plus(zOffset));
            break;
        }
    }
}

void SurfaceRenderer::DrawPixmap(std::shared_ptr pm,
                    const Vector &o, const Vector &u, const Vector &v,
                    const Point2d &ta, const Point2d &tb, hFill hcf) {
    dbp("Not implemented");
}

void SurfaceRenderer::InvalidatePixmap(std::shared_ptr pm) {
    dbp("Not implemented");
}

//-----------------------------------------------------------------------------
// Processing of geometry
//-----------------------------------------------------------------------------

void SurfaceRenderer::CalculateBBox() {
    bbox.minp = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
    bbox.maxp = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);

    for(auto &it : edges) {
        SEdgeList &el = it.second;
        for(SEdge &e : el.l) {
            bbox.Include(e.a);
            bbox.Include(e.b);
        }
    }

    for(auto &it : beziers) {
        SBezierList &bl = it.second;
        for(SBezier &b : bl.l) {
            for(int i = 0; i 

Web Proxy Viewer  |  New URL  |  Original Page