This source file includes following definitions.
- gdip_create_path
- gdip_new_surface
- gdip_delete_surface
- gdip_attach_surface_to_device
- gdip_attach_surface_to_texture
- gdip_attach_surface_to_buffer
- gdip_detach_surface
- gdip_surface_set_raster_level
- gdip_surface_set_matrix
- gdip_surface_set_clipper
- gdip_get_brush
- gdip_setup_path
- gdip_surface_set_path
- gdip_surface_fill
- gdip_surface_flush
- gdip_surface_clear
- gdip_init_driver_surface
- gdip_LoadRenderer
- gdip_ShutdownRenderer
#include <windows.h>
#include "gdip_priv.h"
struct IDirectDrawSurface7;
#include "GdiplusMem.h"
#include "GdiplusEnums.h"
#include "GdiplusTypes.h"
#include "GdiplusInit.h"
#include "GdiplusPixelFormats.h"
#include "GdiplusColor.h"
#include "GdiplusMetaHeader.h"
#include "GdiplusImaging.h"
#include "GdiplusColorMatrix.h"
#include "GdiplusGpStubs.h"
#include "GdiplusColor.h"
#include "GdiplusFlat.h"
struct _graphics
{
        GpGraphics *graph;
        GpMatrix *mat;
        GpPath *clip;
        GpPath *current;
        u32 w, h;
        Bool center_coords;
        
        GpBitmap *pBitmap;
};
GpPath *gdip_create_path(GF_Path *_this)
{
        GpPath *p;
        u32 j, i, nb_pts, cur;
        if (!_this || !_this->n_points) return NULL;
        GdipCreatePath(FillModeAlternate, &p);
        GdipSetPathFillMode(p, (_this->flags & GF_PATH_FILL_ZERO_NONZERO) ? FillModeWinding : FillModeAlternate);
        cur = 0;
        for (i=0; i<_this->n_contours; i++) {
                nb_pts = 1+_this->contours[i] - cur;
                GdipStartPathFigure(p);
                for (j=cur+1; j<cur+nb_pts; ) {
                        switch (_this->tags[j]) {
                        case GF_PATH_CURVE_ON:
                                GdipAddPathLine(p, FIX2FLT(_this->points[j-1].x), FIX2FLT(_this->points[j-1].y), FIX2FLT(_this->points[j].x), FIX2FLT(_this->points[j].y));
                                j++;
                                break;
                        case GF_PATH_CLOSE:
                                GdipAddPathLine(p, FIX2FLT(_this->points[j].x), FIX2FLT(_this->points[j].y), FIX2FLT(_this->points[cur].x), FIX2FLT(_this->points[cur].y));
                                j++;
                                break;
                        case GF_PATH_CURVE_CUBIC:
                                GdipAddPathBezier(p,
                                                  FIX2FLT(_this->points[j-1].x), FIX2FLT(_this->points[j-1].y),
                                                  FIX2FLT(_this->points[j].x), FIX2FLT(_this->points[j].y),
                                                  FIX2FLT(_this->points[j+1].x), FIX2FLT(_this->points[j+1].y),
                                                  FIX2FLT(_this->points[j+2].x), FIX2FLT(_this->points[j+2].y)
                                                 );
                                j+=3;
                                break;
                        case GF_PATH_CURVE_CONIC:
                        {
                                GF_Point2D ctl, end, c1, c2, start;
                                start = _this->points[j-1];
                                ctl = _this->points[j];
                                end = _this->points[j+1];
                                c1.x = start.x + 2*(ctl.x - start.x) / 3;
                                c1.y = start.y + 2*(ctl.y - start.y) / 3;
                                c2.x = c1.x + (end.x - start.x) / 3;
                                c2.y = c1.y + (end.y - start.y) / 3;
                                GdipAddPathBezier(p,
                                                  FIX2FLT(start.x), FIX2FLT(start.y),
                                                  FIX2FLT(c1.x), FIX2FLT(c1.y),
                                                  FIX2FLT(c2.x), FIX2FLT(c2.y),
                                                  FIX2FLT(end.x), FIX2FLT(end.y)
                                                 );
                                j+=2;
                        }
                        break;
                        }
                }
                GdipClosePathFigure(p);
                cur += nb_pts;
        }
        return p;
}
#define GPGRAPH() struct _graphics *_graph = (struct _graphics *)_this;
static
GF_SURFACE gdip_new_surface(GF_Raster2D *, Bool center_coords)
{
        struct _graphics *graph;
        SAFEALLOC(graph, struct _graphics);
        graph->center_coords = center_coords;
        return graph;
}
static
void gdip_delete_surface(GF_SURFACE _this)
{
        GPGRAPH();
        gf_free(_graph);
}
#define GDIP_PIXEL_MODE PixelOffsetModeHighQuality
static
GF_Err gdip_attach_surface_to_device(GF_SURFACE _this, void *os_handle, u32 width, u32 height)
{
        GpMatrix *mat;
        HDC handle = (HDC) os_handle;
        GPGRAPH();
        if (!_graph || !handle) return GF_BAD_PARAM;
        if (_graph->graph) return GF_BAD_PARAM;
        GdipCreateFromHDC(handle, &_graph->graph);
        GdipCreateMatrix(&mat);
        if (    _graph->center_coords) {
                GdipScaleMatrix(mat, 1.0, -1.0, MatrixOrderAppend);
                GdipTranslateMatrix(mat, (Float) width/2, (Float) height/2, MatrixOrderAppend);
        }
        GdipSetWorldTransform(_graph->graph, mat);
        GdipDeleteMatrix(mat);
        _graph->w = width;
        _graph->h = height;
        GdipSetPixelOffsetMode(_graph->graph, GDIP_PIXEL_MODE);
        return GF_OK;
}
static
GF_Err gdip_attach_surface_to_texture(GF_SURFACE _this, GF_STENCIL sten)
{
        GpMatrix *mat;
        struct _stencil *_sten = (struct _stencil *)sten;
        GPGRAPH();
        if (!_graph || !_sten || !_sten->pBitmap) return GF_BAD_PARAM;
        GdipGetImageGraphicsContext(_sten->pBitmap, &_graph->graph);
        if (_graph->center_coords) {
                GdipCreateMatrix(&mat);
                GdipScaleMatrix(mat, 1.0, -1.0, MatrixOrderAppend);
                GdipTranslateMatrix(mat, (Float) _sten->width/2, (Float) _sten->height/2, MatrixOrderAppend);
                GdipSetWorldTransform(_graph->graph, mat);
                GdipDeleteMatrix(mat);
        }
        _graph->w = _sten->width;
        _graph->h = _sten->height;
        GdipSetPixelOffsetMode(_graph->graph, GDIP_PIXEL_MODE);
        return GF_OK;
}
static
GF_Err gdip_attach_surface_to_buffer(GF_SURFACE _this, char *pixels, u32 width, u32 height, s32 pitch_x, s32 pitch_y, GF_PixelFormat pixelFormat)
{
        GpMatrix *mat;
        u32 pFormat;
        GPGRAPH();
        if (pitch_y%4) return GF_NOT_SUPPORTED;
        switch (pixelFormat) {
        case GF_PIXEL_ALPHAGREY:
                pFormat = PixelFormat16bppGrayScale;
                if (pitch_x != 2) return GF_NOT_SUPPORTED;
                break;
        case GF_PIXEL_RGB_555:
                pFormat = PixelFormat16bppRGB555;
                if (pitch_x != 2) return GF_NOT_SUPPORTED;
                break;
        case GF_PIXEL_RGB_565:
                pFormat = PixelFormat16bppRGB565;
                if (pitch_x != 2) return GF_NOT_SUPPORTED;
                break;
        case GF_PIXEL_RGB_24:
                pFormat = PixelFormat24bppRGB;
                if (pitch_x != 3) return GF_NOT_SUPPORTED;
                break;
        case GF_PIXEL_RGB_32:
                pFormat = PixelFormat32bppRGB;
                if (pitch_x != 4) return GF_NOT_SUPPORTED;
                break;
        case GF_PIXEL_ARGB:
                pFormat = PixelFormat32bppARGB;
                if (pitch_x != 4) return GF_NOT_SUPPORTED;
                break;
        default:
                return GF_NOT_SUPPORTED;
        }
        GdipCreateBitmapFromScan0(width, height, pitch_y, pFormat, (unsigned char*)pixels, &_graph->pBitmap);
        GdipGetImageGraphicsContext(_graph->pBitmap, &_graph->graph);
        _graph->w = width;
        _graph->h = height;
        if (_graph->center_coords) {
                GdipCreateMatrix(&mat);
                GdipScaleMatrix(mat, 1.0, -1.0, MatrixOrderAppend);
                GdipTranslateMatrix(mat, (Float) width/2, (Float) height/2, MatrixOrderAppend);
                GdipSetWorldTransform(_graph->graph, mat);
                GdipDeleteMatrix(mat);
        }
        GdipSetPixelOffsetMode(_graph->graph, GDIP_PIXEL_MODE);
        return GF_OK;
}
static
void gdip_detach_surface(GF_SURFACE _this)
{
        GPGRAPH();
        if (_graph->graph) GdipDeleteGraphics(_graph->graph);
        _graph->graph = NULL;
        if (_graph->clip) GdipDeletePath(_graph->clip);
        _graph->clip = NULL;
        if (_graph->pBitmap) GdipDisposeImage(_graph->pBitmap);
        _graph->pBitmap = NULL;
        if (_graph->current) GdipDeletePath(_graph->current);
        _graph->current = NULL;
}
static
GF_Err gdip_surface_set_raster_level(GF_SURFACE _this, GF_RasterLevel RasterSetting)
{
        GPGRAPH();
        switch (RasterSetting) {
        case GF_RASTER_HIGH_SPEED:
                GdipSetSmoothingMode(_graph->graph, SmoothingModeHighSpeed);
                GdipSetCompositingQuality(_graph->graph, CompositingQualityHighSpeed);
                break;
        case GF_RASTER_MID:
                GdipSetSmoothingMode(_graph->graph, SmoothingModeDefault);
                GdipSetCompositingQuality(_graph->graph, CompositingQualityDefault);
                break;
        case GF_RASTER_HIGH_QUALITY:
                GdipSetSmoothingMode(_graph->graph, SmoothingModeHighQuality);
                GdipSetCompositingQuality(_graph->graph, CompositingQualityDefault);
                
                
                break;
        }
        return GF_OK;
}
static
GF_Err gdip_surface_set_matrix(GF_SURFACE _this, GF_Matrix2D * mat)
{
        GPGRAPH();
        if (_graph->mat) GdipDeleteMatrix(_graph->mat);
        _graph->mat = mat_gpac_to_gdip(mat);
        return GF_OK;
}
static
GF_Err gdip_surface_set_clipper(GF_SURFACE _this, GF_IRect *rc)
{
        GPGRAPH();
        if (_graph->clip) GdipDeletePath(_graph->clip);
        _graph->clip = 0L;
        if (!rc) return GF_OK;
        GdipCreatePath(FillModeAlternate, &_graph->clip);
        GdipAddPathRectangleI(_graph->clip, rc->x, rc->y - rc->height, rc->width, rc->height);
        return GF_OK;
}
static
GpBrush *gdip_get_brush(struct _stencil *_sten)
{
        if (_sten->pSolid) return _sten->pSolid;
        if (_sten->pLinear) return _sten->pLinear;
        if (_sten->pRadial) return _sten->pRadial;
        if (_sten->pTexture) return _sten->pTexture;
        return NULL;
}
static GpPath *gdip_setup_path(struct _graphics *_this, GF_Path *path)
{
        GpPath *tr = gdip_create_path(path);
        
        if (_this->mat) GdipTransformPath(tr, _this->mat);
        return tr;
}
static
GF_Err gdip_surface_set_path(GF_SURFACE _this, GF_Path *path)
{
        struct _storepath *_path;
        GPGRAPH();
        if (!_graph) return GF_BAD_PARAM;
        if (_graph->current) GdipDeletePath(_graph->current);
        _graph->current = NULL;
        if (!path) return GF_OK;
        _path = (struct _storepath *)path;
        _graph->current = gdip_setup_path(_graph, path);
        return GF_OK;
}
static
GF_Err gdip_surface_fill(GF_SURFACE _this, GF_STENCIL stencil)
{
        GpStatus ret;
        GpMatrix *newmat;
        struct _stencil *_sten;
        GPGRAPH();
        if (!_this) return GF_BAD_PARAM;
        if (!_graph->current) return GF_OK;
        _sten = (struct _stencil *)stencil;
        assert(_sten);
#ifdef NODRAW
        return GF_OK;
#endif
        if (_graph->clip) GdipSetClipPath(_graph->graph, _graph->clip, CombineModeReplace);
        switch (_sten->type) {
        case GF_STENCIL_SOLID:
                assert(_sten->pSolid);
                GdipFillPath(_graph->graph, _sten->pSolid, _graph->current);
                break;
        case GF_STENCIL_LINEAR_GRADIENT:
                if (_sten->pMat) {
                        
                        gdip_recompute_line_gradient(_sten);
                        GdipResetTextureTransform((GpTexture*)_sten->pLinear);
                        if (_sten->pMat) {
                                GdipCloneMatrix(_sten->pMat, &newmat);
                        } else {
                                GdipCreateMatrix(&newmat);
                        }
                        GdipMultiplyMatrix(newmat, _sten->pLinearMat, MatrixOrderPrepend);
                        GdipSetTextureTransform((GpTexture*)_sten->pLinear, newmat);
                        GdipDeleteMatrix(newmat);
                }
                GdipFillPath(_graph->graph, _sten->pLinear, _graph->current);
                break;
        case GF_STENCIL_RADIAL_GRADIENT:
                
                gdip_recompute_radial_gradient(_sten);
                GdipSetCompositingQuality(_graph->graph, CompositingQualityHighSpeed);
                GdipSetInterpolationMode(_graph->graph, InterpolationModeLowQuality);
                GdipSetSmoothingMode(_graph->graph, SmoothingModeHighSpeed);
                
                if (_sten->pSolid) {
                        GpPath *tr;
                        GdipClonePath(_sten->circle, &tr);
                        GdipTransformPath(tr, _sten->pMat);
                        GdipSetClipPath(_graph->graph, tr, CombineModeExclude);
                        GdipFillPath(_graph->graph, _sten->pSolid, _graph->current);
                        GdipDeletePath(tr);
                        GdipResetClip(_graph->graph);
                        if (_graph->clip) GdipSetClipPath(_graph->graph, _graph->clip, CombineModeReplace);
                }
                GdipFillPath(_graph->graph, _sten->pRadial, _graph->current);
                break;
        case GF_STENCIL_VERTEX_GRADIENT:
                assert(_sten->pRadial);
                if (_sten->pMat) GdipSetTextureTransform((GpTexture*)_sten->pRadial, _sten->pMat);
                ret = GdipFillPath(_graph->graph, _sten->pRadial, _graph->current);
                break;
        case GF_STENCIL_TEXTURE:
                gdip_load_texture(_sten);
                if (_sten->pTexture) {
                        GpMatrix *newmat;
                        GdipResetTextureTransform((GpTexture*)_sten->pTexture);
                        if (_sten->pMat) {
                                GdipCloneMatrix(_sten->pMat, &newmat);
                        } else {
                                GdipCreateMatrix(&newmat);
                        }
                        
                        if (_graph->center_coords && !(_sten->tiling&GF_TEXTURE_FLIP) )
                                GdipScaleMatrix(newmat, 1, -1, MatrixOrderPrepend);
                        else if (!_graph->center_coords && (_sten->tiling&GF_TEXTURE_FLIP) )
                                GdipScaleMatrix(newmat, 1, -1, MatrixOrderPrepend);
                        GdipSetTextureTransform((GpTexture*)_sten->pTexture, newmat);
                        GdipDeleteMatrix(newmat);
                        GdipSetInterpolationMode(_graph->graph, (_sten->tFilter==GF_TEXTURE_FILTER_HIGH_QUALITY) ? InterpolationModeHighQuality : InterpolationModeLowQuality);
                        GdipFillPath(_graph->graph, _sten->pTexture, _graph->current);
                }
                break;
        }
        return GF_OK;
}
static
GF_Err gdip_surface_flush(GF_SURFACE _this)
{
        GPGRAPH();
        GdipFlush(_graph->graph, FlushIntentionSync);
        return GF_OK;
}
static
GF_Err gdip_surface_clear(GF_SURFACE _this, GF_IRect *rc, u32 color)
{
        GpPath *path;
        GPGRAPH();
        GdipCreatePath(FillModeAlternate, &path);
        if (rc) {
                
                GdipAddPathRectangleI(path, rc->x, rc->y - rc->height, rc->width, rc->height);
        } else {
                
                      GdipAddPathRectangleI(path, 0, 0, _graph->w, _graph->h);
        }
        
        GdipSetClipPath(_graph->graph, path, CombineModeReplace);
        GdipGraphicsClear(_graph->graph, color);
        GdipDeletePath(path);
        return GF_OK;
}
void gdip_init_driver_surface(GF_Raster2D *driver)
{
        driver->surface_new = gdip_new_surface;
        driver->surface_delete = gdip_delete_surface;
        driver->surface_attach_to_device = gdip_attach_surface_to_device;
        driver->surface_attach_to_texture = gdip_attach_surface_to_texture;
        driver->surface_attach_to_buffer = gdip_attach_surface_to_buffer;
        driver->surface_detach = gdip_detach_surface;
        driver->surface_set_raster_level = gdip_surface_set_raster_level;
        driver->surface_set_matrix = gdip_surface_set_matrix;
        driver->surface_set_clipper = gdip_surface_set_clipper;
        driver->surface_set_path = gdip_surface_set_path;
        driver->surface_fill = gdip_surface_fill;
        driver->surface_flush = gdip_surface_flush;
        driver->surface_clear = gdip_surface_clear;
}
GF_Raster2D *gdip_LoadRenderer()
{
        GdiplusStartupInput startupInput;
        GF_Raster2D *driver;
        struct _gdip_context *ctx;
        SAFEALLOC(ctx, struct _gdip_context);
        SAFEALLOC(driver, GF_Raster2D);
        GdiplusStartup(&ctx->gdiToken, &startupInput, NULL);
        driver->internal = ctx;
        GF_REGISTER_MODULE_INTERFACE(driver, GF_RASTER_2D_INTERFACE, "GDIplus 2D Raster", "gpac distribution")
        gdip_init_driver_texture(driver);
        gdip_init_driver_surface(driver);
        gdip_init_driver_grad(driver);
        return driver;
}
void gdip_ShutdownRenderer(GF_Raster2D *driver)
{
        struct _gdip_context *ctx = (struct _gdip_context *)driver->internal;
        GdiplusShutdown(ctx->gdiToken);
        gf_free(ctx);
        gf_free(driver);
}