/*
The MIT License

Copyright (C) 2009-2010 DeSmuME team

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <map>

#include "GPU.h"
#include "NDSSystem.h"

#include "aggdraw.h"

#include "agg_renderer_base.h"
#include "agg_renderer_primitives.h"
#include "agg_renderer_scanline.h"
#include "agg_bounding_rect.h"
#include "agg_trans_affine.h"
#include "agg_path_storage.h"
#include "agg_color_rgba.h"

#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_scanline_p.h"

//raster text
#include "agg_glyph_raster_bin.h"
#include "agg_embedded_raster_fonts.h"
#include "agg_renderer_raster_text.h"

#include "ctrl/agg_bezier_ctrl.h"
#include "platform/agg_platform_support.h"
#include "agg_pattern_filters_rgba.h"
#include "agg_renderer_outline_image.h"
#include "agg_rasterizer_outline_aa.h"

#include "agg_image_accessors.h"
#include "agg_span_interpolator_linear.h"
#include "agg_span_image_filter_rgb.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_span_image_filter_gray.h"

#include "agg_span_allocator.h"

typedef std::map<std::string, const agg::int8u*> TAgg_Font_Table;
static TAgg_Font_Table font_table;

font_type fonts_list[] =
{
	{ agg::gse4x6, "gse4x6" },
	{ agg::gse4x8, "gse4x8" },
	{ agg::gse5x7, "gse5x7" },
	{ agg::gse5x9, "gse5x9" },
	{ agg::gse6x9, "gse6x9" },
	{ agg::gse6x12, "gse6x12" },
	{ agg::gse7x11, "gse7x11" },
	{ agg::gse7x11_bold, "gse7x11_bold" },
	{ agg::gse7x15, "gse7x15" },
	{ agg::gse7x15_bold, "gse7x15_bold" },
	{ agg::gse8x16, "gse8x16" },
	{ agg::gse8x16_bold, "gse8x16_bold" },
	{ agg::mcs11_prop, "mcs11_prop" },
	{ agg::mcs11_prop_condensed, "mcs11_prop_condensed" },
	{ agg::mcs12_prop, "mcs12_prop" },
	{ agg::mcs13_prop, "mcs13_prop" },
	{ agg::mcs5x10_mono, "mcs5x10_mono" },
	{ agg::mcs5x11_mono, "mcs5x11_mono" },
	{ agg::mcs6x10_mono, "mcs6x10_mono" },
	{ agg::mcs6x11_mono, "mcs6x11_mono" },
	{ agg::mcs7x12_mono_high, "mcs7x12_mono_high" },
	{ agg::mcs7x12_mono_low, "mcs7x12_mono_low" },
	{ agg::verdana12, "verdana12" },
	{ agg::verdana12_bold, "verdana12_bold" },
	{ agg::verdana13, "verdana13" },
	{ agg::verdana13_bold, "verdana13_bold" },
	{ agg::verdana14, "verdana14" },
	{ agg::verdana14_bold, "verdana14_bold" },
	{ agg::verdana16, "verdana16" },
	{ agg::verdana16_bold, "verdana16_bold" },
	{ agg::verdana17, "verdana17" },
	{ agg::verdana17_bold, "verdana17_bold" },
	{ agg::verdana18, "verdana18" },
	{ agg::verdana18_bold, "verdana18_bold" },
};
int font_Nums = ARRAY_SIZE(fonts_list);

const agg::int8u* AggDrawTarget::lookupFont(const std::string& name)
{ 
	TAgg_Font_Table::iterator it(font_table.find(name));
	if(it == font_table.end()) return NULL;
	else return it->second;
}

static void Agg_init_fonts()
{
	for(u32 i=0;i<font_Nums;i++)
		font_table[fonts_list[i].name] = fonts_list[i].font;
}

AggDraw_Desmume aggDraw;

T_AGG_RGBA agg_targetScreen_32bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);
T_AGG_RGB555 agg_targetScreen_16bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*2);

static std::vector<u32> luaBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2);
T_AGG_RGBA agg_targetLua((u8*)luaBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);

static std::vector<u32> hudBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2);
T_AGG_RGBA agg_targetHud((u8*)hudBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);

static AggDrawTarget* targets[] = {
	&agg_targetScreen_32bit,
	&agg_targetHud,
	&agg_targetLua,
};

void Agg_init()
{
	Agg_init_fonts();
	switch(aggDraw.screenBytesPerPixel)
	{
		case 2:
			targets[0]=&agg_targetScreen_16bit;
			break;
		case 4:
			targets[0]=&agg_targetScreen_32bit;
			break;
	}

	aggDraw.screen = targets[0];
	aggDraw.hud = targets[1];
	aggDraw.lua = targets[2];

	aggDraw.target = targets[0];

	//if we're single core, we don't want to waste time compositing
	//and the more clever compositing isnt supported in non-windows
	#ifdef WIN32
	if(CommonSettings.single_core())
		aggDraw.hud = aggDraw.screen;
	#else
	aggDraw.hud = aggDraw.screen;
	#endif

	aggDraw.hud->setFont("verdana18_bold");
}

AggDraw_Desmume::AggDraw_Desmume()
{
	screenBytesPerPixel = 4;
}

void AggDraw_Desmume::setTarget(AggTarget newTarget)
{
	target = targets[newTarget];
}

void Agg_setCustomSize(int w, int h)
{
	hudBuffer.resize(w*h);
	luaBuffer.resize(w*h);
	if(aggDraw.screen)
		aggDraw.screen->setDrawTargetDims(0, w, h, w*aggDraw.screenBytesPerPixel);
	if(aggDraw.hud)
		aggDraw.hud->setDrawTargetDims((u8*)hudBuffer.data(), w, h, w*4);
	if(aggDraw.lua)
		aggDraw.lua->setDrawTargetDims((u8*)luaBuffer.data(), w, h, w*4);
}


////temporary, just for testing the lib
//void AGGDraw() {
////
//	aggDraw.setTarget(AggTarget_Screen);
//
////	aggDraw.target->clear();
////
////	aggDraw.target->clipBox(0,0,255,383);
////
//	aggDraw.target->lineColor(0, 0, 255, 128);
//	aggDraw.target->fillColor(0, 0, 255, 128);
////	//aggDraw.target->noFill();
//	aggDraw.target->lineWidth(1.0);
//	aggDraw.target->roundedRect(10,30,256-10,192-10,4);
////
////	aggDraw.target->setFont("verdana18_bold");
////	aggDraw.target->renderText(60,60, "testing testing testing");
////
////        // Gradients (Aqua Buttons)
////        //=======================================
//////        m_graphics.font("Verdana", 20.0, false, false, TAGG2D::VectorFontCache);
////        double xb1 = 10;
////        double yb1 = 80;
////        double xb2 = xb1 + 150;
////        double yb2 = yb1 + 36;
////
////        aggDraw.target->fillColor(0,50,180,180);
////        aggDraw.target->lineColor(0,0,80, 255);
////        aggDraw.target->lineWidth(1.0);
////        aggDraw.target->roundedRect(xb1, yb1, xb2, yb2, 12, 18);
////
////        aggDraw.target->lineColor(0,0,0,0);
////        aggDraw.target->fillLinearGradient(xb1, yb1, xb1, yb1+30, 
////                                      agg::rgba8(100,200,255,255), 
////                                      agg::rgba8(255,255,255,0));
////        aggDraw.target->roundedRect(xb1+3, yb1+2.5, xb2-3, yb1+30, 9, 18, 1, 1);
////
////		aggDraw.target->fillColor(0,0,50, 200);
////        aggDraw.target->noLine();
/////*        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignCenter);
////        m_graphics.text((xb1 + xb2) / 2.0, (yb1 + yb2) / 2.0, "Aqua Button", true, 0.0, 0.0);
////*/
////        aggDraw.target->fillLinearGradient(xb1, yb2-20, xb1, yb2-3, 
////                                      agg::rgba8(0,  0,  255,0),
////                                      agg::rgba8(100,255,255,255)); 
////        aggDraw.target->roundedRect(xb1+3, yb2-20, xb2-3, yb2-2, 1, 1, 9, 18);
////
////        // Basic Shapes -- Ellipse
////        //===========================================
////        aggDraw.target->lineWidth(3.5);
////        aggDraw.target->lineColor(20,  80,  80);
////        aggDraw.target->fillColor(200, 255, 80, 200);
////        aggDraw.target->ellipse(150, 200, 50, 90);
////
////        // Paths
////        //===========================================
////        aggDraw.target->resetPath();
////        aggDraw.target->fillColor(255, 0, 0, 100);
////        aggDraw.target->lineColor(0, 0, 255, 100);
////        aggDraw.target->lineWidth(2);
////        aggDraw.target->moveTo(300/2, 200/2);
////        aggDraw.target->horLineRel(-150/2);
////        aggDraw.target->arcRel(150/2, 150/2, 0, 1, 0, 150/2, -150/2);
////        aggDraw.target->closePolygon();
////        aggDraw.target->drawPath();
////
////        aggDraw.target->resetPath();
////        aggDraw.target->fillColor(255, 255, 0, 100);
////        aggDraw.target->lineColor(0, 0, 255, 100);
////        aggDraw.target->lineWidth(2);
////        aggDraw.target->moveTo(275/2, 175/2);
////        aggDraw.target->verLineRel(-150/2);
////        aggDraw.target->arcRel(150/2, 150/2, 0, 0, 0, -150/2, 150/2);
////        aggDraw.target->closePolygon();
////        aggDraw.target->drawPath();
////
////        aggDraw.target->resetPath();
////        aggDraw.target->noFill();
////        aggDraw.target->lineColor(127, 0, 0);
////        aggDraw.target->lineWidth(5);
////        aggDraw.target->moveTo(600/2, 350/2);
////        aggDraw.target->lineRel(50/2, -25/2);
////        aggDraw.target->arcRel(25/2, 25/2, aggDraw.target->deg2Rad(-30), 0, 1, 50/2, -25/2);
////        aggDraw.target->lineRel(50/2, -25/2);
////        aggDraw.target->arcRel(25/2, 50/2, aggDraw.target->deg2Rad(-30), 0, 1, 50/2, -25/2);
////        aggDraw.target->lineRel(50/2, -25/2);
////        aggDraw.target->arcRel(25/2, 75/2, aggDraw.target->deg2Rad(-30), 0, 1, 50/2, -25/2);
////        aggDraw.target->lineRel(50, -25);
////        aggDraw.target->arcRel(25/2, 100/2, aggDraw.target->deg2Rad(-30), 0, 1, 50/2, -25/2);
////        aggDraw.target->lineRel(50/2, -25/2);
////        aggDraw.target->drawPath();
//}
////


//
////========================
////testing stufff
//
//int width = 256;
//int height = 384;
//
//Agg2D m_graphics;
//
//void AGGDraw(unsigned char * buffer)
//    {
//        m_graphics.attach(buffer, 
//                          256, 
//                          384,
//                          512);
//
//        m_graphics.clearAll(255, 255, 255);
//        //m_graphics.clearAll(0, 0, 0);
//
//        //m_graphics.blendMode(TAGG2D::BlendSub);
//        //m_graphics.blendMode(TAGG2D::BlendAdd);
//
//        m_graphics.antiAliasGamma(1.4);
//
//        // Set flipText(true) if you have the Y axis upside down.
//        //m_graphics.flipText(true);
//
//
//        // ClipBox.
//        //m_graphics.clipBox(50, 50, rbuf_window().width() - 50, rbuf_window().height() - 50);
//
//        // Transfornations - Rotate around (300,300) to 5 degree
//        //m_graphics.translate(-300, -300);
//        //m_graphics.rotate(TAGG2D::deg2Rad(5.0));
//        //m_graphics.translate(300, 300);
//
//        // Viewport - set 0,0,600,600 to the actual window size 
//        // preserving aspect ratio and placing the viewport in the center.
//        // To ignore aspect ratio use TAGG2D::Anisotropic
//        // Note that the viewport just adds transformations to the current
//        // affine matrix. So that, set the viewport *after* all transformations!
//        m_graphics.viewport(0, 0, 600, 600, 
//                            0, 0, width, height, 
//                            //TAGG2D::Anisotropic);
//                            TAGG2D::XMidYMid);
//
//
//        // Rounded Rect
//        m_graphics.lineColor(0, 0, 0);
//        m_graphics.noFill();
//        m_graphics.roundedRect(0.5, 0.5, 600-0.5, 600-0.5, 20.0);
///*
//
//        // Reglar Text
//        m_graphics.font("Times New Roman", 14.0, false, false);
//        m_graphics.fillColor(0, 0, 0);
//        m_graphics.noLine();
//        m_graphics.text(100, 20, "Regular Raster Text -- Fast, but can't be rotated");
//
//        // Outlined Text
//        m_graphics.font("Times New Roman", 50.0, false, false, TAGG2D::VectorFontCache);
//        m_graphics.lineColor(50, 0, 0);
//        m_graphics.fillColor(180, 200, 100);
//        m_graphics.lineWidth(1.0);
//        m_graphics.text(100.5, 50.5, "Outlined Text");
//
//        // Text Alignment
//        m_graphics.line(250.5-150, 150.5,    250.5+150, 150.5);
//        m_graphics.line(250.5,     150.5-20, 250.5,     150.5+20);
//        m_graphics.line(250.5-150, 200.5,    250.5+150, 200.5);
//        m_graphics.line(250.5,     200.5-20, 250.5,     200.5+20);
//        m_graphics.line(250.5-150, 250.5,    250.5+150, 250.5);
//        m_graphics.line(250.5,     250.5-20, 250.5,     250.5+20);
//        m_graphics.line(250.5-150, 300.5,    250.5+150, 300.5);
//        m_graphics.line(250.5,     300.5-20, 250.5,     300.5+20);
//        m_graphics.line(250.5-150, 350.5,    250.5+150, 350.5);
//        m_graphics.line(250.5,     350.5-20, 250.5,     350.5+20);
//        m_graphics.line(250.5-150, 400.5,    250.5+150, 400.5);
//        m_graphics.line(250.5,     400.5-20, 250.5,     400.5+20);
//        m_graphics.line(250.5-150, 450.5,    250.5+150, 450.5);
//        m_graphics.line(250.5,     450.5-20, 250.5,     450.5+20);
//        m_graphics.line(250.5-150, 500.5,    250.5+150, 500.5);
//        m_graphics.line(250.5,     500.5-20, 250.5,     500.5+20);
//        m_graphics.line(250.5-150, 550.5,    250.5+150, 550.5);
//        m_graphics.line(250.5,     550.5-20, 250.5,     550.5+20);
//*/
///*
//        m_graphics.fillColor(100, 50, 50);
//        m_graphics.noLine();
//        //m_graphics.textHints(false);
//        m_graphics.font("Times New Roman", 40.0, false, false, TAGG2D::VectorFontCache);
//
//        m_graphics.textAlignment(TAGG2D::AlignLeft, TAGG2D::AlignBottom);
//        m_graphics.text(250.0,     150.0, "Left-Bottom", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignBottom);
//        m_graphics.text(250.0,     200.0, "Center-Bottom", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignRight, TAGG2D::AlignBottom);
//        m_graphics.text(250.0,     250.0, "Right-Bottom", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignLeft, TAGG2D::AlignCenter);
//        m_graphics.text(250.0,     300.0, "Left-Center", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignCenter);
//        m_graphics.text(250.0,     350.0, "Center-Center", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignRight, TAGG2D::AlignCenter);
//        m_graphics.text(250.0,     400.0, "Right-Center", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignLeft, TAGG2D::AlignTop);
//        m_graphics.text(250.0,     450.0, "Left-Top", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignTop);
//        m_graphics.text(250.0,     500.0, "Center-Top", true, 0, 0);
//
//        m_graphics.textAlignment(TAGG2D::AlignRight, TAGG2D::AlignTop);
//        m_graphics.text(250.0,     550.0, "Right-Top", true, 0, 0);
//
//*/
//        // Gradients (Aqua Buttons)
//        //=======================================
//        m_graphics.font("Verdana", 20.0, false, false, TAGG2D::VectorFontCache);
//        double xb1 = 400;
//        double yb1 = 80;
//        double xb2 = xb1 + 150;
//        double yb2 = yb1 + 36;
//
//        m_graphics.fillColor(TAGG2D::Color(0,50,180,180));
//        m_graphics.lineColor(TAGG2D::Color(0,0,80, 255));
//        m_graphics.lineWidth(1.0);
//        m_graphics.roundedRect(xb1, yb1, xb2, yb2, 12, 18);
//
//        m_graphics.lineColor(TAGG2D::Color(0,0,0,0));
//        m_graphics.fillLinearGradient(xb1, yb1, xb1, yb1+30, 
//                                      TAGG2D::Color(100,200,255,255), 
//                                      TAGG2D::Color(255,255,255,0));
//        m_graphics.roundedRect(xb1+3, yb1+2.5, xb2-3, yb1+30, 9, 18, 1, 1);
//
//        m_graphics.fillColor(TAGG2D::Color(0,0,50, 200));
//        m_graphics.noLine();
///*        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignCenter);
//        m_graphics.text((xb1 + xb2) / 2.0, (yb1 + yb2) / 2.0, "Aqua Button", true, 0.0, 0.0);
//*/
//        m_graphics.fillLinearGradient(xb1, yb2-20, xb1, yb2-3, 
//                                      TAGG2D::Color(0,  0,  255,0),
//                                      TAGG2D::Color(100,255,255,255)); 
//        m_graphics.roundedRect(xb1+3, yb2-20, xb2-3, yb2-2, 1, 1, 9, 18);
//
//
//        // Aqua Button Pressed
//        xb1 = 400;
//        yb1 = 30;
//        xb2 = xb1 + 150;
//        yb2 = yb1 + 36;
//
//        m_graphics.fillColor(TAGG2D::Color(0,50,180,180));
//        m_graphics.lineColor(TAGG2D::Color(0,0,0,  255));
//        m_graphics.lineWidth(2.0);
//        m_graphics.roundedRect(xb1, yb1, xb2, yb2, 12, 18);
//
//        m_graphics.lineColor(TAGG2D::Color(0,0,0,0));
//        m_graphics.fillLinearGradient(xb1, yb1+2, xb1, yb1+25, 
//                                      TAGG2D::Color(60, 160,255,255), 
//                                      TAGG2D::Color(100,255,255,0));
//        m_graphics.roundedRect(xb1+3, yb1+2.5, xb2-3, yb1+30, 9, 18, 1, 1);
//
//        m_graphics.fillColor(TAGG2D::Color(0,0,50, 255));
//        m_graphics.noLine();
///*        m_graphics.textAlignment(TAGG2D::AlignCenter, TAGG2D::AlignCenter);
//        m_graphics.text((xb1 + xb2) / 2.0, (yb1 + yb2) / 2.0, "Aqua Pressed", 0.0, 0.0);
//*/
//        m_graphics.fillLinearGradient(xb1, yb2-25, xb1, yb2-5, 
//                                      TAGG2D::Color(0,  180,255,0),
//                                      TAGG2D::Color(0,  200,255,255)); 
//        m_graphics.roundedRect(xb1+3, yb2-25, xb2-3, yb2-2, 1, 1, 9, 18);
//
//
//
//
//        // Basic Shapes -- Ellipse
//        //===========================================
//        m_graphics.lineWidth(3.5);
//        m_graphics.lineColor(20,  80,  80);
//        m_graphics.fillColor(200, 255, 80, 200);
//        m_graphics.ellipse(450, 200, 50, 90);
//
//
//        // Paths
//        //===========================================
//        m_graphics.resetPath();
//        m_graphics.fillColor(255, 0, 0, 100);
//        m_graphics.lineColor(0, 0, 255, 100);
//        m_graphics.lineWidth(2);
//        m_graphics.moveTo(300/2, 200/2);
//        m_graphics.horLineRel(-150/2);
//        m_graphics.arcRel(150/2, 150/2, 0, 1, 0, 150/2, -150/2);
//        m_graphics.closePolygon();
//        m_graphics.drawPath();
//
//        m_graphics.resetPath();
//        m_graphics.fillColor(255, 255, 0, 100);
//        m_graphics.lineColor(0, 0, 255, 100);
//        m_graphics.lineWidth(2);
//        m_graphics.moveTo(275/2, 175/2);
//        m_graphics.verLineRel(-150/2);
//        m_graphics.arcRel(150/2, 150/2, 0, 0, 0, -150/2, 150/2);
//        m_graphics.closePolygon();
//        m_graphics.drawPath();
//
//
//        m_graphics.resetPath();
//        m_graphics.noFill();
//        m_graphics.lineColor(127, 0, 0);
//        m_graphics.lineWidth(5);
//        m_graphics.moveTo(600/2, 350/2);
//        m_graphics.lineRel(50/2, -25/2);
//        m_graphics.arcRel(25/2, 25/2, TAGG2D::deg2Rad(-30), 0, 1, 50/2, -25/2);
//        m_graphics.lineRel(50/2, -25/2);
//        m_graphics.arcRel(25/2, 50/2, TAGG2D::deg2Rad(-30), 0, 1, 50/2, -25/2);
//        m_graphics.lineRel(50/2, -25/2);
//        m_graphics.arcRel(25/2, 75/2, TAGG2D::deg2Rad(-30), 0, 1, 50/2, -25/2);
//        m_graphics.lineRel(50, -25);
//        m_graphics.arcRel(25/2, 100/2, TAGG2D::deg2Rad(-30), 0, 1, 50/2, -25/2);
//        m_graphics.lineRel(50/2, -25/2);
//        m_graphics.drawPath();
//
//
//        // Master Alpha. From now on everything will be translucent
//        //===========================================
//        m_graphics.masterAlpha(0.85);
//
//
//        // Image Transformations
//        //===========================================
///*        TAGG2D::Image img(rbuf_img(0).buf(), 
//                         rbuf_img(0).width(), 
//                         rbuf_img(0).height(), 
//                         rbuf_img(0).stride());
//        m_graphics.imageFilter(TAGG2D::Bilinear);
//
//        //m_graphics.imageResample(TAGG2D::NoResample);
//        //m_graphics.imageResample(TAGG2D::ResampleAlways);
//        m_graphics.imageResample(TAGG2D::ResampleOnZoomOut);
//
//        // Set the initial image blending operation as BlendDst, that actually 
//        // does nothing. 
//        //-----------------
//        m_graphics.imageBlendMode(TAGG2D::BlendDst);
//
//
//        // Transform the whole image to the destination rectangle
//        //-----------------
//        //m_graphics.transformImage(img, 450, 200, 595, 350);
//
//        // Transform the rectangular part of the image to the destination rectangle
//        //-----------------
//        //m_graphics.transformImage(img, 60, 60, img.width()-60, img.height()-60,
//        //                          450, 200, 595, 350);
//
//        // Transform the whole image to the destination parallelogram
//        //-----------------
//        //double parl[6] = { 450, 200, 595, 220, 575, 350 };
//        //m_graphics.transformImage(img, parl);
//
//        // Transform the rectangular part of the image to the destination parallelogram
//        //-----------------
//        //double parl[6] = { 450, 200, 595, 220, 575, 350 };
//        //m_graphics.transformImage(img, 60, 60, img.width()-60, img.height()-60, parl);
//
//        // Transform image to the destination path. The scale is determined by a rectangle
//        //-----------------
//        //m_graphics.resetPath();
//        //m_graphics.moveTo(450, 200);
//        //m_graphics.cubicCurveTo(595, 220, 575, 350, 595, 350);
//        //m_graphics.lineTo(470, 340);
//        //m_graphics.transformImagePath(img, 450, 200, 595, 350);
//
//
//        // Transform image to the destination path.
//        // The scale is determined by a rectangle
//        //-----------------
//        m_graphics.resetPath();
//        m_graphics.moveTo(450, 200);
//        m_graphics.cubicCurveTo(595, 220, 575, 350, 595, 350);
//        m_graphics.lineTo(470, 340);
//        m_graphics.transformImagePath(img, 60, 60, img.width()-60, img.height()-60,
//                                      450, 200, 595, 350);
//
//        // Transform image to the destination path. 
//        // The transformation is determined by a parallelogram
//        //m_graphics.resetPath();
//        //m_graphics.moveTo(450, 200);
//        //m_graphics.cubicCurveTo(595, 220, 575, 350, 595, 350);
//        //m_graphics.lineTo(470, 340);
//        //double parl[6] = { 450, 200, 595, 220, 575, 350 };
//        //m_graphics.transformImagePath(img, parl);
//
//        // Transform the rectangular part of the image to the destination path. 
//        // The transformation is determined by a parallelogram
//        //m_graphics.resetPath();
//        //m_graphics.moveTo(450, 200);
//        //m_graphics.cubicCurveTo(595, 220, 575, 350, 595, 350);
//        //m_graphics.lineTo(470, 340);
//        //double parl[6] = { 450, 200, 595, 220, 575, 350 };
//        //m_graphics.transformImagePath(img, 60, 60, img.width()-60, img.height()-60, parl);
//*/
//
//        // Add/Sub/Contrast Blending Modes
//        m_graphics.noLine();
//        m_graphics.fillColor(70, 70, 0);
//        m_graphics.blendMode(TAGG2D::BlendAdd);
//        m_graphics.ellipse(500, 280, 20, 40);
//
//        m_graphics.fillColor(255, 255, 255);
//        m_graphics.blendMode(TAGG2D::BlendContrast);
//        m_graphics.ellipse(500+40, 280, 20, 40);
//
//
//
//        // Radial gradient.
//        m_graphics.blendMode(TAGG2D::BlendAlpha);
//        m_graphics.fillRadialGradient(400, 500, 40, 
//                                      TAGG2D::Color(255, 255, 0, 0),
//                                      TAGG2D::Color(0, 0, 127),
//                                      TAGG2D::Color(0, 255, 0, 0));
//        m_graphics.ellipse(400, 500, 40, 40);
//
//    }
//
