📄 gdip_rend.cpp
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / GDIplus rasterizer module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "gdip_priv.h"#include <windows.h>#ifndef ULONG_PTR #define ULONG_PTR DWORD#endif#ifndef INT16typedef s16 INT16;#endif#ifndef UINT16typedef u16 UINT16;#endif/*all GDIPLUS includes for C api*/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; /*offscreen buffer handling*/ 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;staticGF_SURFACE gf_new_surface(GF_Raster2D *, Bool center_coords){ struct _graphics *graph; SAFEALLOC(graph, struct _graphics); graph->center_coords = center_coords; return graph;}staticvoid gf_delete_surface(GF_SURFACE _this){ GPGRAPH(); free(_graph);}/*should give the best results with the clippers*/#define GDIP_PIXEL_MODE PixelOffsetModeHighQualitystaticGF_Err gf_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;}staticGF_Err gf_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;}staticGF_Err gf_attach_surface_to_buffer(GF_SURFACE _this, char *pixels, u32 width, u32 height, u32 stride, GF_PixelFormat pixelFormat){ GpMatrix *mat; u32 pFormat; GPGRAPH(); if (stride%4) return GF_NOT_SUPPORTED; switch (pixelFormat) { case GF_PIXEL_ALPHAGREY: pFormat = PixelFormat16bppGrayScale; break; case GF_PIXEL_RGB_555: pFormat = PixelFormat16bppRGB555; break; case GF_PIXEL_RGB_565: pFormat = PixelFormat16bppRGB565; break; case GF_PIXEL_RGB_24: pFormat = PixelFormat24bppRGB; break; case GF_PIXEL_RGB_32: pFormat = PixelFormat32bppRGB; break; case GF_PIXEL_ARGB: pFormat = PixelFormat32bppARGB; break; default: return GF_NOT_SUPPORTED; } GdipCreateBitmapFromScan0(width, height, stride, 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;}staticvoid gf_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;}staticGF_Err gf_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); /*THIS IS HORRIBLY SLOW DON'T EVEN THINK ABOUT IT*/ /*GdipSetCompositingQuality(_graph->graph, CompositingQualityHighQuality);*/ break; } return GF_OK;}staticGF_Err gf_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;}staticGF_Err gf_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;}staticGpBrush *gf_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 *gf_setup_path(struct _graphics *_this, GF_Path *path){ GpPath *tr = gdip_create_path(path); /*append current matrix*/ if (_this->mat) GdipTransformPath(tr, _this->mat); return tr;}staticGF_Err gf_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 = gf_setup_path(_graph, path); return GF_OK;}//#define NODRAWstaticGF_Err gf_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) { /*rebuild gradient*/ gf_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: /*build gradient*/ gf_recompute_radial_gradient(_sten); GdipSetCompositingQuality(_graph->graph, CompositingQualityHighSpeed); GdipSetInterpolationMode(_graph->graph, InterpolationModeLowQuality); GdipSetSmoothingMode(_graph->graph, SmoothingModeHighSpeed); /*check if we need to draw solid background (GDIplus doesn't implement padded mode on path gradients)*/ 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: gf_load_texture(_sten); if (_sten->pTexture) { GpMatrix *newmat; GdipResetTextureTransform((GpTexture*)_sten->pTexture); if (_sten->pMat) { GdipCloneMatrix(_sten->pMat, &newmat); } else { GdipCreateMatrix(&newmat); } /*gdip flip*/ if (_graph->center_coords) 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;}staticGF_Err gf_surface_flush(GF_SURFACE _this){ GPGRAPH(); GdipFlush(_graph->graph, FlushIntentionSync); return GF_OK;}staticGF_Err gf_surface_clear(GF_SURFACE _this, GF_IRect *rc, u32 color){ GpPath *path; GPGRAPH(); GdipCreatePath(FillModeAlternate, &path); if (rc) { /*luckily enough this maps well for both flipped and unflipped coords*/ GdipAddPathRectangleI(path, rc->x, rc->y - rc->height, rc->width, rc->height); } else {/* if (_graph->center_coords) { GdipAddPathRectangleI(path, -1 * (s32)_graph->w / 2, -1 * (s32)_graph->h / 2, _graph->w, _graph->h); } else {*/ GdipAddPathRectangleI(path, 0, 0, _graph->w, _graph->h);// } } /*we MUST use clear otherwise ARGB surfaces are not cleared correctly*/ GdipSetClipPath(_graph->graph, path, CombineModeReplace); GdipGraphicsClear(_graph->graph, color); GdipDeletePath(path); return GF_OK;}void gf_init_driver_surface(GF_Raster2D *driver){ driver->surface_new = gf_new_surface; driver->surface_delete = gf_delete_surface; driver->surface_attach_to_device = gf_attach_surface_to_device; driver->surface_attach_to_texture = gf_attach_surface_to_texture; driver->surface_attach_to_buffer = gf_attach_surface_to_buffer; driver->surface_detach = gf_detach_surface; driver->surface_set_raster_level = gf_surface_set_raster_level; driver->surface_set_matrix = gf_surface_set_matrix; driver->surface_set_clipper = gf_surface_set_clipper; driver->surface_set_path = gf_surface_set_path; driver->surface_fill = gf_surface_fill; driver->surface_flush = gf_surface_flush; driver->surface_clear = gf_surface_clear;}GF_Raster2D *gdip_LoadRenderer(){ GdiplusStartupInput startupInput; GF_Raster2D *driver; struct _gf_context *ctx; SAFEALLOC(ctx, struct _gf_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") gf_init_driver_texture(driver); gf_init_driver_surface(driver); gf_init_driver_grad(driver); return driver;}void gdip_ShutdownRenderer(GF_Raster2D *driver){ struct _gf_context *ctx = (struct _gf_context *)driver->internal; GdiplusShutdown(ctx->gdiToken); free(driver->internal); free(driver);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -