DrawingRequest and DrawingContext ================================= The DrawingContext class is similar to the CL_GraphicContext class in that it offers drawing functions, but as opposed to the current CL_GraphicContext it doesn't draw directly to the screen but keeps the drawing commands (encapsuled in a DrawingRequest) in a buffer, postprocesses them and only then flushes them down to the screen. Why buffer graphics? ==================== Buffering graphics instead of rendering directly to the screen provides quite a few benefits which include: * sorting graphics after z-coordinate; while the z-buffer can do that, it fails to do that properly for transparent images * post-processing, simple effects like screenshaking, random sprite scaling or the like can be applied to the DrawingContext * multi-pass rendering, the DrawingContext can be rendered to the screen or multiple pbuffers to create some effects * cleaner code on the games side, by allowing a game to render to multiple drawing buffers and process later the game logic itself will be freed to keep rendering commands in order/sorted and can draw things out of order * performance, by allowing all drawing commands to be collected and sorted, the graphics can be sorted by texture-id and thus all objects with the same texture-id can be rendered at once, thus avoiding frequent texture changing Performance Problems ==================== When lots of little objects get drawn, like in a particel system, it might be expensive to sort them, to avoid that it should be possible to either group DrawingRequests or to just write special DrawingRequests. Class Structure =============== /** The DrawingContext collects all DrawingRequests and allows you to flush them all down to the graphics card in one run, this has the advantage that it is possible to z-sort, texture-id sort or otherwise optimize the drawing. In addition to that it also allows you do render the drawing commands to multiple buffers which might be usefull for post-processing effects and such. */ class DrawingContext { private: typedef std::vector DrawingRequests; DrawingRequests drawingrequests; std::vector translate_stack; public: DrawingContext(); /** Draws everything in the drawing context to the screen */ void render(CL_GraphicContext* gc); /** Empties the drawing context */ void clear(); /** Fills the screen with a given color, this is different from clear() in that it doesn't remove other DrawingRequest from the queue */ void fill_screen(const CL_Color& color); /*{ */ void draw(DrawingRequest* request); void draw(const CL_Sprite& sprite, float x, float y, float z = 0); void draw(const std::string& text, float x, float y, float z = 0); /*} */ /** Translate the drawing context */ void translate(float x, float y); /** Set the rotation of the drawing context */ void rotate(float angel); /** Set the scaling of the drawing context */ void scale(float x, float y); void push_modelview(); void pop_modelview(); /** Return the area of the screen that will be visible*/ CL_Rect get_clip_rect(); private: DrawingContext (const DrawingContext&); DrawingContext& operator= (const DrawingContext&); }; class DrawingRequest { protected: CL_Vector pos; public: DrawingRequest(const CL_Vector& pos_) : pos(pos_) {} virtual void draw(CL_GraphicContext* gc) = 0; /** Returns true if the request contains an alpha channel and needs to be drawn in order */ virtual bool has_alpha() { return true; } /** Returns the position at which the request should be drawn */ virtual float get_z_pos() { return pos.z; } private: DrawingRequest (const DrawingRequest&); DrawingRequest& operator= (const DrawingRequest&); }; /** Example DrawingRequest to render a CL_Sprite */ class SpriteDrawingRequest : public DrawingRequest { private: CL_Sprite sprite; public: SpriteDrawingRequest(const CL_Sprite& sprite_, const CL_Vector& pos_) : DrawingRequest(pos_), sprite(sprite_) {} virtual ~SpriteDrawingRequest() {} void draw(CL_GraphicContext* gc) { sprite.draw(static_cast(pos.x), static_cast(pos.y), gc); } }; Other Examples ============== Both Windstille and SuperTux use currently a system which handles DrawingRequests. Code above is copy&paste from Windstille Problems ======== While translate() is easy to implemented, other kinds of modeview() transformation will get more tricky to implement, since the request will get reorded one cannot rely on glTranslate/glRotate and friends. Other Issues ============ Its unclear at which point DrawingContext should get integrated, letting it replace CL_GraphicContext would remove to much freedom from the application, while making it completly seperate might make it look awkward (sprite.draw(x, y) vs drawing_context.draw(sprite, x, y)). # EOF #