vgfx.h

Go to the documentation of this file.
00001 /*
00002  * vgfx.h
00003  *
00004  * Copyright (C) 2007  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Vector graphics library.
00032  */
00033 
00034 #ifndef WAVEPACKET_VGFX__H_
00035 #define WAVEPACKET_VGFX__H_
00036 
00037 // includes --------------------------------------------------------------------
00038 #include <sstream>
00039 
00040 #include "bezier/bezier.h"
00041 #include "bezier/quad.h"
00042 #include "objtree/objtree.h"    // TODO: do I want an objtree dependency here???
00043 #include "geometry/xform_2d.h"
00044 #include "util/parsing.h"
00045 
00046 
00047 // namespace
00048 namespace vgfx {
00049 
00050 
00051 ////////////////////////////////////////////////////////////////////////////////
00052 ///
00053 /// \ingroup  lib
00054 /// \defgroup vgfx Vector Graphics Engine
00055 ///
00056 /// vgfx is the Vector Graphics Engine.  It exists to represent the logical
00057 /// model of nested, transformed 2D shapes.
00058 ///
00059 /// The library is heavily optimized for two use cases:
00060 ///  - atomic, transactional updates (writes)
00061 ///  - very fast queries (reads)
00062 ///
00063 /// In particular, the library doesn't try to be particularly fast on writes.
00064 /// It is more concerned with correctness (of course), and with constructing a
00065 /// rollback request for internal and external use.
00066 ///
00067 /// Because any write operation returns a corresponding rollback request, it is
00068 /// easy for calling applications to set up an undo/redo stack.
00069 ///
00070 /// The request language is intended to be human-readable and easy for
00071 /// applications to generate on the fly.  Think of something like SQL updates.
00072 ///
00073 /// Queries are focused on either lookups by object ID, or lookups based on a
00074 /// 2D rectangle.  Reads (queries) are intended to be fast so the engine can
00075 /// be used in a real-time rendering application.
00076 ///
00077 /// Typical client usage is:
00078 ///  - create an ObjectMap to represent your state
00079 ///  - construct requests (text statements) - see \ref vgfx_format
00080 ///  - call processRequest() to invoke requests on your ObjectMap
00081 ///             (this will populate and modify the map)
00082 ///  - call various ObjectMap or Primitive APIs to query the state of any
00083 ///             interesting objects.
00084 ///
00085 /// If you want to draw any of this:
00086 ///  - provide an object that implements the vgfx::Drawer interface
00087 ///  - use the vgfx::Primitive::draw() method to recursively draw nested
00088 ///     object trees.
00089 ///
00090 /// \n
00091 /// Keep in mind: an ObjectMap isn't actually a canvas!  Think of it as a big
00092 /// registry of objects which you can look up by name (ID).  And objects can
00093 /// reference each other by their IDs.
00094 ///
00095 /// To draw something, you have to provide an object to draw.  Typically an
00096 /// application will create a bunch of objects in the ObjectMap, and then
00097 /// put everything visible under a known root group object.  For display, the
00098 /// application will call draw() on the root group object.  (To do this, the
00099 /// application will have to create an object that implements the \ref Drawer
00100 /// interface, and then call vgfx::Primitive::draw() on the root group
00101 /// object).
00102 ///
00103 /// \n
00104 /// Other descriptions of vgfx (mostly for search engines):
00105 ///  - scriptable vector graphics engine
00106 ///  - transactional vector graphics engine
00107 ///  - queriable vector graphics engine
00108 ///  - programmable vector graphics engine
00109 ///
00110 ////////////////////////////////////////////////////////////////////////////////
00111 
00112 /*@{*/
00113 
00114 
00115 // typedefs
00116 typedef point2d_t<float>        point_t;
00117 typedef rect2d_t<float>         rect_t;
00118 
00119 class ObjectMap;                        // forward declaration
00120 class Primitive;
00121 class Drawer;
00122 
00123 /// hit detection results
00124 enum eHitDetect {
00125         eHit_Overlap            = 1,    ///<- rects overlap at all
00126         eHit_Contained          = 2,    ///<- counts as a hit only if contained
00127         eHit_Always             = 3,    ///<- ignore rect, always hit
00128 
00129         eHit_Invalid            = 0
00130 };
00131 
00132 
00133 /// hit detection results
00134 struct visit_result_t {
00135         // constructor, manipulators
00136         visit_result_t(void) throw() { this->clear(); }
00137 
00138         void clear(void) throw() {
00139                         p = NULL;
00140                         tag_path = NULL;
00141                         T.setIdentity();
00142                 }
00143 
00144         // data fields
00145         Primitive *     p;              // pointer to current node
00146         const char *    tag_path;       // tag path to current node
00147         xform_2d_t      T;              // node local -> global coordinates
00148 };
00149 
00150 
00151 typedef bool (*callback_t)(IN void * context,
00152                                 IN visit_result_t& result);
00153 
00154 
00155 /// the base class from which all vector graphics objects inherit.
00156 class Primitive {
00157 public:
00158         // constructor, destructor ---------------------------------------------
00159         Primitive(void) throw();
00160         virtual ~Primitive(void) throw();
00161 
00162         // vgfx::Primitive ref counting methods (all primitives get these) -----
00163         virtual long getRefCount(void) const throw() { return m_refcount; }
00164         virtual void incrementRefCount(void) throw() {
00165                         ++m_refcount;
00166                 //      DPRINTF("Incrementing ref count for object '%s': %ld",
00167                 //          this->getID(), m_refcount);
00168                 }
00169         virtual void decrementRefCount(void) throw() {
00170                         --m_refcount;
00171                 //      DPRINTF("Decrementing ref count for object '%s': %ld",
00172                 //          this->getID(), m_refcount);
00173                         ASSERT(m_refcount >= 0,
00174                             "Bad ref count: %ld", m_refcount);
00175                  }
00176 
00177         // vgfx::Primitive class interface methods -----------------------------
00178         virtual const char * getID(void) const throw();
00179         virtual void setID(IN const char * id);
00180         virtual const char * getType(void) const throw() = 0;
00181         virtual void persist(OUT std::ostream& stream) const = 0;
00182         virtual void listContainers(IN const VecString& path,
00183                                 OUT VecString& ids) const;
00184         virtual bool doesContainerExist(IN const VecString& path) const;
00185         virtual bool canCreateContainer(IN const VecString& path) const;
00186         virtual void removeContainer(IN const VecString& path);
00187         virtual void getContainerDictionary(IN const VecString& path,
00188                                 OUT dictionary_t& data) const;
00189         virtual void setContainerDictionary(IN const VecString& path,
00190                                 IN const dictionary_t& data);
00191         virtual void recalcBoundingRect(IN const char * tag_path,
00192                                 IN Drawer * drawer,
00193                                 IN const xform_2d_t& T) = 0; //<- local -> drawer
00194         virtual bool getBoundingRect(OUT rect_t& r) const throw() = 0;
00195         virtual bool getPrimitive(IN const char * tag_path,
00196                                 IN const xform_2d_t& T,      //<- local -> global
00197                                 OUT visit_result_t& vr);
00198 
00199         /// draw this primitive and all children, recursively
00200         virtual void draw(IN Drawer * drawer,
00201                                 IN const rect_t& r_pix,      //<- absolute
00202                                 IN const xform_2d_t& T) = 0; //<- local -> drawer
00203         virtual bool visit(IN const rect_t& r,          // global coords
00204                                 IN const xform_2d_t& T, // local --> global
00205                                 IN const char * tag_path,
00206                                 IN callback_t callback,
00207                                 IN void * context,
00208                                 IN eHitDetect hit);
00209 
00210         // static factory methods ----------------------------------------------
00211         static smart_ptr<Primitive> create(IN const char * type,
00212                                 IN const dictionary_t& data);
00213 
00214 private:
00215         // private member data -------------------------------------------------
00216         long            m_refcount;
00217         std::string     m_id;
00218 };
00219 
00220 
00221 
00222 /// an ObjectMap is a physical manifestation of a vector graphics 2D area.
00223 ///
00224 /// This is the state that contains all primitives.
00225 ///
00226 /// It is recommended that you do NOT use these APIs to modify the map!
00227 /// Use vgfx::processRequest() instead.
00228 class ObjectMap {
00229 public:
00230         // virtual destructor --------------------------------------------------
00231         virtual ~ObjectMap(void) throw();
00232 
00233         // vgfx::ObjectMap class interface methods -----------------------------
00234         virtual long size(void) const throw() = 0;
00235         virtual void newObjectID(IN const char * prefix,
00236                                 OUT std::string& id) = 0;
00237         virtual void addObject(IN smart_ptr<Primitive>& primitive) = 0;
00238         virtual Primitive * findObject(IN const char * ID) const throw() = 0;
00239         virtual smart_ptr<Primitive> removeObject(IN const char * ID) = 0;
00240 
00241         // static factory methods ----------------------------------------------
00242         static smart_ptr<ObjectMap> create(void);
00243 };
00244 
00245 
00246 
00247 ////////////////////////////////////////////////////////////////////////////////
00248 //
00249 //      Parsing functions
00250 //
00251 ////////////////////////////////////////////////////////////////////////////////
00252 
00253 /// Request that an ObjectMap be updated with the given request.
00254 ///
00255 /// Returns false on failure.
00256 ///
00257 /// \param map ObjectMap upon which the request will act.
00258 /// \param stream Input text stream containing request.  See \ref vgfx_format.
00259 /// \param single_transaction If true, the request will be handled as an
00260 ///     atomic operation and an undo request will be returned.  If false, there
00261 ///     is no rollback of partial commits.  Use true unless you have good reason
00262 ///     otherwise.
00263 /// \param undo_request On output, this contains a request which will undo the
00264 ///     original input request.  Handy for undo/redo stacks.
00265 /// \param diagnostic If the return value is false, this string will contain
00266 ///     some details on output which may be helpful in tracking down what
00267 ///     failed.
00268 bool processRequest(IN ObjectMap * map, 
00269                                 IN std::istream& stream,
00270                                 IN bool single_transaction,
00271                                 OUT std::string& undo_request,
00272                                 OUT std::string& diagnostic);
00273 
00274 
00275 
00276 ////////////////////////////////////////////////////////////////////////////////
00277 //
00278 //      Function objects
00279 //
00280 ////////////////////////////////////////////////////////////////////////////////
00281 
00282 // raw invocation (returns partial request)
00283 void invokeFunction(IN Primitive * function,
00284                                 IN ObjectMap * map,
00285                                 IN const dictionary_t& in_params,
00286                                 OUT std::ostream& stream);
00287 
00288 // better helper methods
00289 
00290 // addFunctionFromPath(map, path) - given a filesystem path, checks to see
00291 //   if we already have this function loaded, and if not, loads it and adds
00292 //   it to the map
00293 //   either way, the function returns a pointer to the Function object
00294 Primitive * addFunctionFromPath(IN ObjectMap * map,
00295                                 IN const char * path);
00296 
00297 
00298 // setScript(map, parent, script, stream) - updates stream with instructions
00299 //   to add a script parameter group, and a child group which has the script
00300 //   results.  Also returns ID of root script parameter object.
00301 void setScript(IN ObjectMap * map,
00302                                 IN const char * parent_id,
00303                                 IN const char * script_id,
00304                                 IN const objtree::property_set_t& defaults,
00305                                 IO std::ostream& stream,
00306                                 OUT std::string& root_id);
00307 
00308 // updateScriptParameters(map, parent, pset, stream) - updates stream with
00309 //   instructions to update script parameters, and re-run the child script
00310 void updateScriptParameters(IN ObjectMap * map,
00311                                 IN const char * parent_id,
00312                                 IN const objtree::property_set_t& pset,
00313                                 IO std::ostream& stream);
00314 
00315 // resizeScript(map, parent, width, height, stream) - updates stream with script
00316 //      having re-run given new size
00317 void resizeScript(IN ObjectMap * map,
00318                                 IN const char * parent_id,
00319                                 IN float width,
00320                                 IN float height,
00321                                 IO std::ostream& stream);
00322 
00323 
00324 // helpful for objects
00325 template <class T>
00326 std::string getStringValue(const T& t)
00327 {
00328         std::ostringstream out;
00329         out << t;
00330         return out.str();
00331 }
00332 
00333 
00334 
00335 ////////////////////////////////////////////////////////////////////////////////
00336 //
00337 //      Vector Graphics Primitives (vgfx primitives)
00338 //
00339 //      This just declares factories with necessary input data.
00340 //      A naming scheme is carefully followed to make use of macros easier.
00341 //
00342 //      Clients don't normally need these, although it does give you the power
00343 //      to directly create primitives outside of the parser, either using
00344 //      parser-like data or with custom data structures.
00345 //
00346 ////////////////////////////////////////////////////////////////////////////////
00347 
00348 // base initialization struct for all primitives
00349 struct init_primitive_t {
00350         std::string     id;
00351 };
00352 
00353 
00354 // point
00355 struct init_point_t : public init_primitive_t {
00356         float x0;
00357         float y0;
00358 };
00359 
00360 void init_point_from_data(IN const dictionary_t& data,
00361                                 OUT init_point_t&);
00362 smart_ptr<Primitive> create_point(IN const init_point_t&);
00363 
00364 
00365 // bezier
00366 struct init_bezier_t : public init_primitive_t {
00367         bezier::curve_t         curve;
00368 };
00369 
00370 void init_bezier_from_data(IN const dictionary_t& data,
00371                                 OUT init_bezier_t&);
00372 smart_ptr<Primitive> create_bezier(IN const init_bezier_t&);
00373 
00374 
00375 // rect
00376 struct init_rect_t : public init_primitive_t {
00377         rect_t                  rect;
00378         bool                    fill;   // fill rect when drawing?
00379 };
00380 
00381 void init_rect_from_data(IN const dictionary_t& data,
00382                                 OUT init_rect_t&);
00383 smart_ptr<Primitive> create_rect(IN const init_rect_t&);
00384 
00385 
00386 // line
00387 struct init_line_t : public init_primitive_t {
00388         float                   x0;
00389         float                   y0;
00390         float                   x1;
00391         float                   y1;
00392 };
00393 
00394 void init_line_from_data(IN const dictionary_t& data,
00395                                 OUT init_line_t&);
00396 smart_ptr<Primitive> create_line(IN const init_line_t&);
00397 
00398 
00399 // dxdy
00400 struct init_dxdy_t : public init_primitive_t {
00401         float                   dx;
00402         float                   dy;
00403 };
00404 
00405 void init_dxdy_from_data(IN const dictionary_t& data,
00406                                 OUT init_dxdy_t&);
00407 smart_ptr<Primitive> create_dxdy(IN const init_dxdy_t&);
00408 
00409 
00410 // quad (quadratic bezier)
00411 struct init_quad_t : public init_primitive_t {
00412         bezier::quad_bezier_t   quad;
00413 };
00414 
00415 void init_quad_from_data(IN const dictionary_t& data,
00416                                 OUT init_quad_t&);
00417 smart_ptr<Primitive> create_quad(IN const init_quad_t&);
00418 
00419 
00420 // group
00421 smart_ptr<Primitive> parseGroup(IN std::istream& stream,
00422                                 IN ObjectMap * map);
00423 
00424 // function
00425 smart_ptr<Primitive> parseFunction(IN std::istream& stream,
00426                                 IN ObjectMap * map);
00427 
00428 
00429 // text
00430 struct init_text_t : public init_primitive_t {
00431         std::string     text;
00432 };
00433 
00434 void init_text_from_data(IN const dictionary_t& data,
00435                                 OUT init_text_t&);
00436 smart_ptr<Primitive> create_text(IN const init_text_t&);
00437 
00438 
00439 };      // vgfx primitives
00440 
00441 
00442 #endif  // WAVEPACKET_VGFX__H__
00443