/** * DisablablePrimitives.hxx * * Copyright (c) 2003, Asko Soukka * This file is part of LibVob. * * LibVob is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * LibVob is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with LibVob; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * */ /* * Written by Asko Soukka */ #ifndef VOB_DISABLABLEPRIMITIVES_HXX #define VOB_DISABLABLEPRIMITIVES_HXX #ifndef VOB_PRIMITIVETRANS_DEFINED #define VOB_PRIMITIVETRANS_DEFINED(x, n) #endif #include #include namespace Vob { namespace Primitives { /** A tag interface, implying for a primitive * transform that there are parameters. */ class DisablablePrimitiveTransform { public: bool disabled; }; /** Culling transform can decide not to be drawn when its * parents' boxes do not intersect. */ class Cull : public PrimitiveTransform, public DisablablePrimitiveTransform { public: const Transform *parent; const Transform *test; const Transform *clip; enum { NDepends = 3 }; template void setParams(SPtr depends) { parent = depends[0]; test = depends[1]; clip = depends[2]; if (shouldBeDrawn()) disabled = false; else disabled = true; } virtual ZPt transform(const ZPt &p) const { return parent->transform(p); } virtual void vertex(const ZPt &p) const { parent->vertex(p); } virtual bool canPerformGL() const { return parent->canPerformGL(); } virtual bool performGL() const { return parent->performGL(); } virtual float nonlinearity(const ZPt &p, float radius) const { float n1 = parent->nonlinearity(p, radius); float n2 = clip->nonlinearity(parent->transform(p), radius); return (n1 > n2 ? n1 : n2); } typedef Cull InverseType; void inverse(InverseType &into) const { into.parent = parent; into.test = test; into.clip = clip; into.disabled = disabled; } virtual void dump(std::ostream &out) const { out << " CULL "; } virtual Pt getSqSize() const { return parent->getSqSize(); } /** Cull transforms' shouldBeDrawn() returns true always when boxes * of its test and clip coordinate systems do intersect. When * the boxes don't intersect, it should retun false. */ virtual bool shouldBeDrawn() const { Pt box; float hyp; /** Lower left and upper right points of bounding boxes for * parents' box (after transformation). */ ZPt p1, p2, p3, p4; box = test->getSqSize(); hyp = hypot(box.x/2, box.y/2); if (test->nonlinearity(ZPt(box.x/2, box.y/2, 0), hyp) > 1/hyp) findDistortedBoundingBox(test, p1, p2); else findBoundingBox(test, p1, p2); box = clip->getSqSize(); hyp = hypot(box.x/2, box.y/2); if (clip->nonlinearity(ZPt(box.x/2, box.y/2, 0), hyp) > 1/hyp) findDistortedBoundingBox(clip, p3, p4); else findBoundingBox(clip, p3, p4); return (parallelRectIntersect(p1, p2, p3, p4)); } protected: /** Checks if two parallel rectangle intersects. * "Two rectangles, represented by lower left and upper right points (p1, p2) * and (p3, p4), intersects if and only if the conjunction * (x2 >= x3) && (x4 >= x1) && (y2 >= y3) && (y4 >= y1) * is true. (The rectangles must intersect in both dimensions.)" * @param p1 first rectangle, "lower left corner" * @param p2 first rectangle, "upper right corner" * @param p3 second rectangle, "lower left corner" * @param p4 second rectangle, "upper right corner" * @return true if the given rectangles intersect */ bool parallelRectIntersect(ZPt &p1, ZPt &p2, ZPt &p3, ZPt &p4) const { return (p2.x > p3.x) && (p4.x > p1.x) && (p2.y > p3.y) && (p4.y > p1.y); } /** Checks if two parallel rectangle are within each other. * @param p1 first rectangle, "lower left corner" * @param p2 first rectangle, "upper right corner" * @param p3 second rectangle, "lower left corner" * @param p4 second rectangle, "upper right corner" * @return true if the given rectangles are within each other. */ bool parallelRectWithin(ZPt &p1, ZPt &p2, ZPt &p3, ZPt &p4) const { return (p1.x <= p3.x) && (p1.y <= p3.y) && (p4.x <= p2.x) && (p4.y <= p2.y); } /** Finds the bounding box of coordsys' box after * transformation. Assumes linear transform and transforms only * corner's of the box. * @param t the coordinate system, whose box to use * @param p1 "lower left corner" * @param p2 "upper right corner" */ void findBoundingBox(const Transform *t, ZPt &p1, ZPt &p2) const { float i, j; Pt box = t->getSqSize(); float x1, y1, x2, y2; for (i=0; i<=box.x; i+=box.x) { for (j=0; j<=box.y; j+=box.y) { if (i==0 && j==0) { /** Initializing. */ ZPt tmpPt = t->transform(ZPt(i, j, 0)); x1 = tmpPt.x; y1 = tmpPt.y; x2 = tmpPt.x; y2 = tmpPt.y; } else { /** Comparing. */ ZPt tmpPt = t->transform(ZPt(i, j, 0)); if (tmpPt.x < x1) x1 = tmpPt.x; else if (tmpPt.x > x2) x2 = tmpPt.x; if (tmpPt.y < y1) y1 = tmpPt.y; else if (tmpPt.y > y2) y2 = tmpPt.y; } } } p1 = ZPt(x1, y1, 0); p2 = ZPt(x2, y2, 0); } /** Finds the bounding box of coordsys' box after * transformation. Because the transform may be distorted, * searches bounding box's coners also along vertices. * @param t the coordinate system, whose box to use * @param p1 "lower left corner" * @param p2 "upper right corner" */ void findDistortedBoundingBox(const Transform *t, ZPt &p1, ZPt &p2) const { double i, step_x, step_y; Pt box = t->getSqSize(); float x1, y1, x2, y2; int check_dist; /** Initializing. */ check_dist = 100; // XXX Adjusts the scanning frequency. ZPt o = t->transform(ZPt(0, 0, 0)); ZPt u = t->transform(ZPt(box.x, box.y, 0)); if (fabs(o.x - u.x) / check_dist > box.x) step_x = box.x/(fabs(o.x - u.x) / check_dist); else step_x = box.x; if (fabs(o.y - u.y) / check_dist > box.y) step_y = box.y/(fabs(o.y - u.y) / check_dist); else step_y = box.y; x1 = u.x; y1 = u.y; x2 = u.x; y2 = u.y; /** Sweeps the box's vertices. */ /** Vertice (0,0) -> (w,0). */ for (i=0; i < box.x; i+=step_x) { ZPt tmpPt = t->transform(ZPt(i, 0, 0)); if (tmpPt.x < x1) x1 = tmpPt.x; else if (tmpPt.x > x2) x2 = tmpPt.x; if (tmpPt.y < y1) y1 = tmpPt.y; else if (tmpPt.y > y2) y2 = tmpPt.y; } /** Vertice (0,0) -> (0,h). */ for (i=step_y; i < box.y; i+=step_y) { ZPt tmpPt = t->transform(ZPt(0, i, 0)); if (tmpPt.x < x1) x1 = tmpPt.x; else if (tmpPt.x > x2) x2 = tmpPt.x; if (tmpPt.y < y1) y1 = tmpPt.y; else if (tmpPt.y > y2) y2 = tmpPt.y; } /** Vertice (0,h) -> (w,h) */ for (i=0; i < box.x; i+=step_x) { ZPt tmpPt = t->transform(ZPt(i, box.y, 0)); if (tmpPt.x < x1) x1 = tmpPt.x; else if (tmpPt.x > x2) x2 = tmpPt.x; if (tmpPt.y < y1) y1 = tmpPt.y; else if (tmpPt.y > y2) y2 = tmpPt.y; } /** Vertice (w,0) -> (w,h) */ for (i=0; i < box.y; i+=step_y) { ZPt tmpPt = t->transform(ZPt(box.x, i, 0)); if (tmpPt.x < x1) x1 = tmpPt.x; else if (tmpPt.x > x2) x2 = tmpPt.x; if (tmpPt.y < y1) y1 = tmpPt.y; else if (tmpPt.y > y2) y2 = tmpPt.y; } p1 = ZPt(x1, y1, 0); p2 = ZPt(x2, y2, 0); } }; VOB_PRIMITIVETRANS_DEFINED(Cull, "cull"); } } #endif