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