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);
}