📄 stencil.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / software 2D 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 "rast_soft.h"EVGStencil *evg_solid_brush();EVGStencil *evg_gf_sr_texture_brush();EVGStencil *evg_linear_gradient_brush();EVGStencil *evg_radial_gradient_brush();GF_Color color_interpolate(u32 a, u32 b, u8 pos) { u32 ca = ((a>>24) )*(u32)(0xFF-pos)+((b>>24) )*(u32)pos; u32 cr = ((a>>16)&0xFF)*(u32)(0xFF-pos)+((b>>16)&0xFF)*(u32)pos; u32 cg = ((a>> 8)&0xFF)*(u32)(0xFF-pos)+((b>> 8)&0xFF)*(u32)pos; u32 cb = ((a )&0xFF)*(u32)(0xFF-pos)+((b )&0xFF)*(u32)pos; return (((ca+(ca>>8)+1)>>8)<<24)| (((cr+(cr>>8)+1)>>8)<<16)| (((cg+(cg>>8)+1)>>8)<< 8)| (((cb+(cb>>8)+1)>>8) );}/* Generic gradient tools*/#define EVGGRADIENTBUFFERSIZE (1<<EVGGRADIENTBITS)#define EVGGRADIENTMAXINTPOS EVGGRADIENTBUFFERSIZE - 1static void gradient_update(EVG_BaseGradient *_this){ s32 i, c; s32 start, end, diff; Fixed maxPos = INT2FIX(EVGGRADIENTMAXINTPOS); if (_this->pos[0]>=0) { if(_this->pos[0]>0) { end = FIX2INT(gf_mulfix(_this->pos[0], maxPos)); for (i=0; i<= end;i++) { _this->pre[i] = _this->col[0]; } } for (c=0; c<EVGGRADIENTSLOTS;c++) { if (_this->pos[c]<0) break; if (_this->pos[c+1]>=0) { start = FIX2INT(gf_mulfix(_this->pos[c], maxPos)); end = FIX2INT(gf_mulfix(_this->pos[c+1], maxPos)); diff = end-start; if (diff) { for (i=start;i<=end;i++) { _this->pre[i] = color_interpolate(_this->col[c], _this->col[c+1], (u8) ( ( (i-start) * 255) / diff) ); } } } else { start = FIX2INT(gf_mulfix(_this->pos[c+0], maxPos)); for(i=start;i<=EVGGRADIENTMAXINTPOS;i++) { _this->pre[i] = _this->col[c]; } } } }}static u32 gradient_get_color(EVG_BaseGradient *_this, s32 pos) { s32 max_pos = 1 << EVGGRADIENTBITS; switch (_this->mod) { case GF_GRADIENT_MODE_SPREAD: if (pos<0) pos = -pos; return _this->pre[(pos & max_pos) ? EVGGRADIENTMAXINTPOS - (pos % max_pos) : pos % max_pos]; case GF_GRADIENT_MODE_REPEAT: while (pos < 0) pos += max_pos; return _this->pre[pos % max_pos]; case GF_GRADIENT_MODE_PAD: default: return _this->pre[ MIN(EVGGRADIENTMAXINTPOS, MAX((s32) 0, pos))]; }}GF_Err evg_stencil_set_gradient_interpolation(GF_STENCIL p, Fixed *pos, GF_Color *col, u32 count){ EVG_BaseGradient *_this = (EVG_BaseGradient *) p; if ( (_this->type != GF_STENCIL_LINEAR_GRADIENT) && (_this->type != GF_STENCIL_RADIAL_GRADIENT) ) return GF_BAD_PARAM; if (count>=EVGGRADIENTSLOTS-1) return GF_OUT_OF_MEM; memcpy(_this->col, col, sizeof(GF_Color) * count); memcpy(_this->pos, pos, sizeof(Fixed) * count); _this->col[count] = 0; _this->pos[count] = -FIX_ONE; gradient_update(_this); return GF_OK;}GF_Err evg_stencil_set_gradient_mode(GF_STENCIL p, GF_GradientMode mode){ EVG_BaseGradient *_this = (EVG_BaseGradient *) p; if ( (_this->type != GF_STENCIL_LINEAR_GRADIENT) && (_this->type != GF_STENCIL_RADIAL_GRADIENT) ) return GF_BAD_PARAM; _this->mod = mode; return GF_OK;}/* Generic stencil*/GF_STENCIL evg_stencil_new(GF_Raster2D *_dr, GF_StencilType type){ EVGStencil *st; switch (type) { case GF_STENCIL_SOLID: st = evg_solid_brush(); break; case GF_STENCIL_LINEAR_GRADIENT: st = evg_linear_gradient_brush(); break; case GF_STENCIL_RADIAL_GRADIENT: st = evg_radial_gradient_brush(); break; case GF_STENCIL_TEXTURE: st = evg_gf_sr_texture_brush(); break; default: return 0L; } if (st) { gf_mx2d_init(st->pmat); gf_mx2d_init(st->smat); gf_cmx_init(&st->cmat); } return st;}void evg_stencil_delete(GF_STENCIL st){ EVGStencil *_this = (EVGStencil *) st; switch(_this->type) { case GF_STENCIL_SOLID: case GF_STENCIL_LINEAR_GRADIENT: case GF_STENCIL_RADIAL_GRADIENT: free(_this); return; case GF_STENCIL_TEXTURE: { EVG_Texture *tx = (EVG_Texture *)_this; /*destroy conversion buffer if any*/ if ( tx->conv_buf) free( tx->conv_buf ); /*destroy local texture iof any*/ if (tx->owns_texture && tx->pixels) free(tx->pixels); free(_this); } return; }}GF_Err evg_stencil_set_matrix(GF_STENCIL st, GF_Matrix2D *mx){ EVGStencil *_this = (EVGStencil *)st; if (!_this || _this->type>GF_STENCIL_TEXTURE) return GF_BAD_PARAM; if (mx) { gf_mx2d_copy(_this->smat, *mx); } else { gf_mx2d_init(_this->smat); } return GF_OK;}/* Solid color stencil*/EVGStencil *evg_solid_brush(){ EVG_Brush *tmp; GF_SAFEALLOC(tmp, EVG_Brush); if (!tmp) return 0L; tmp->fill_run = NULL; tmp->color = 0xFF000000; tmp->type = GF_STENCIL_SOLID; return (EVGStencil *) tmp;}GF_Err evg_stencil_set_brush_color(GF_STENCIL st, GF_Color c){ EVG_Brush *_this = (EVG_Brush *) st; if (!_this || (_this ->type != GF_STENCIL_SOLID) ) return GF_BAD_PARAM; _this->color = c; return GF_OK;}/* linear gradient stencil*/static void lgb_fill_run(EVGStencil *p, EVGSurface *surf, s32 x, s32 y, u32 count) { Fixed _res; s32 val, inc; u32 *data = surf->stencil_pix_run; u32 shifter = (EVGGRADIENTSCALEBITS - EVGGRADIENTBITS); EVG_LinearGradient *_this = (EVG_LinearGradient *) p; /*no need to move x & y to fixed*/ _res = (Fixed) (x * _this->smat.m[0] + y * _this->smat.m[1] + _this->smat.m[2]); /*but remove val to int*/ val = FIX2INT(_res); inc = FIX2INT(_this->smat.m[0]); while (count) { *data++ = gradient_get_color((EVG_BaseGradient *)_this, (val >> shifter) ); val += inc; count--; }}GF_Err evg_stencil_set_linear_gradient(GF_STENCIL st, Fixed start_x, Fixed start_y, Fixed end_x, Fixed end_y){ GF_Matrix2D mtx; GF_Point2D s; Fixed f; EVG_LinearGradient *_this = (EVG_LinearGradient *) st; if (_this->type != GF_STENCIL_LINEAR_GRADIENT) return GF_BAD_PARAM; _this->start.x = start_x; _this->start.y = start_y; _this->end.x = end_x; _this->end.y = end_y; s.x = end_x - start_x; s.y = end_y - start_y; f = gf_v2d_len(&s); if (f) f = gf_invfix(f); gf_mx2d_init(mtx); mtx.m[2] = - _this->start.x; mtx.m[5] = - _this->start.y; _this->vecmat = mtx; gf_mx2d_init(mtx); gf_mx2d_add_rotation(&mtx, 0, 0, - gf_atan2(s.y, s.x)); gf_mx2d_add_matrix(&_this->vecmat, &mtx); gf_mx2d_init(mtx); gf_mx2d_add_scale(&mtx, f, f); gf_mx2d_add_matrix(&_this->vecmat, &mtx); return GF_OK;}EVGStencil *evg_linear_gradient_brush(){ s32 i; EVG_LinearGradient *tmp; GF_SAFEALLOC(tmp, EVG_LinearGradient); if (!tmp) return 0L; gf_mx2d_init(tmp->vecmat); tmp->fill_run = lgb_fill_run; tmp->type = GF_STENCIL_LINEAR_GRADIENT; for(i=0; i<EVGGRADIENTSLOTS; i++) tmp->pos[i]=-1; evg_stencil_set_linear_gradient((EVGStencil *)tmp, 0, 0, FIX_ONE, 0); return (EVGStencil *) tmp;}/* radial gradient stencil*/static void rg_fill_run(EVGStencil *p, EVGSurface *surf, s32 _x, s32 _y, u32 count) { Fixed x, y, dx, dy, b, val; Bool has_cmat; s32 pos; u32 col; u32 *data = surf->stencil_pix_run; EVG_RadialGradient *_this = (EVG_RadialGradient *) p; x = INT2FIX(_x); y = INT2FIX(_y); gf_mx2d_apply_coords(&_this->smat, &x, &y); has_cmat = _this->cmat.identity ? 0 : 1; dx = x - _this->d_f.x; dy = y - _this->d_f.y; while (count) { b = gf_mulfix(_this->rad, gf_mulfix(dx, _this->d_f.x) + gf_mulfix(dy, _this->d_f.y)); val = gf_mulfix(b, b) + gf_mulfix(_this->rad, gf_mulfix(dx, dx)+gf_mulfix(dy, dy)); b += gf_sqrt(val); pos = FIX2INT(EVGGRADIENTBUFFERSIZE*b); if (has_cmat) { col = gradient_get_color((EVG_BaseGradient *)_this, pos); *data++ = gf_cmx_apply(&p->cmat, col); } else { *data++ = gradient_get_color((EVG_BaseGradient *)_this, pos); } dx += _this->d_i.x; dy += _this->d_i.y; count--; }}void evg_radial_init(EVG_RadialGradient *_this) { GF_Point2D p0, p1; p0.x = p0.y = p1.y = 0; p1.x = FIX_ONE; gf_mx2d_apply_point(&_this->smat, &p0); gf_mx2d_apply_point(&_this->smat, &p1); _this->d_i.x = p1.x - p0.x; _this->d_i.y = p1.y - p0.y; _this->rad = FIX_ONE - gf_mulfix(_this->d_f.x, _this->d_f.x) - gf_mulfix(_this->d_f.y, _this->d_f.y); if (_this->rad) { _this->rad = gf_invfix(_this->rad); } else { _this->rad = EVGGRADIENTBUFFERSIZE; }}EVGStencil *evg_radial_gradient_brush(){ s32 i; EVG_RadialGradient *tmp; GF_SAFEALLOC(tmp, EVG_RadialGradient); if (!tmp) return 0L; tmp->fill_run = rg_fill_run; tmp->type = GF_STENCIL_RADIAL_GRADIENT; for(i=0; i<EVGGRADIENTSLOTS; i++) tmp->pos[i]=-1; tmp->center.x = tmp->center.y = FIX_ONE/2; tmp->focus = tmp->center; tmp->radius = tmp->center; return (EVGStencil *) tmp;}GF_Err evg_stencil_set_radial_gradient(GF_STENCIL st, Fixed cx, Fixed cy, Fixed fx, Fixed fy, Fixed x_radius, Fixed y_radius){ EVG_RadialGradient *_this = (EVG_RadialGradient *) st; if (_this->type != GF_STENCIL_RADIAL_GRADIENT) return GF_BAD_PARAM; _this->center.x = cx; _this->center.y = cy; _this->focus.x = fx; _this->focus.y = fy; _this->radius.x = x_radius; _this->radius.y = y_radius; return GF_OK;}/* Texture stencil */static s32mul255(s32 a, s32 b){ return ((a+1) * b) >> 8;}#if 0/*thx to charcoal for the bilinear filter*/static u32 EVG_LERP(u32 c0, u32 c1, u8 t){ s32 a0, r0, g0, b0; s32 a1, r1, g1, b1; s32 a2, r2, g2, b2; a0 = GF_COL_A(c0); r0 = GF_COL_R(c0); g0 = GF_COL_G(c0); b0 = GF_COL_B(c0); a1 = GF_COL_A(c1); r1 = GF_COL_R(c1); g1 = GF_COL_G(c1); b1 = GF_COL_B(c1); a2 = a0 + mul255(t, (a1 - a0)); r2 = r0 + mul255(t, (r1 - r0)); g2 = g0 + mul255(t, (g1 - g0)); b2 = b0 + mul255(t, (b1 - b0));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -