| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2025 | |
| * 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" | |
| #ifndef GPAC_DISABLE_EVG | |
| static GF_EVGStencil *evg_solid_brush(); | |
| static GF_EVGStencil *evg_texture_brush(); | |
| static GF_EVGStencil *evg_linear_gradient_brush(); | |
| static GF_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 - 1 | |
| static void gradient_update(EVG_BaseGradient *_this) | |
| { | |
| s32 i, c; | |
| s32 start, end, diff; | |
| Fixed maxPos = INT2FIX(EVGGRADIENTMAXINTPOS); | |
| _this->updated = 1; | |
| if (_this->pos[0]>=0) { | |
| if(_this->pos[0]>0) { | |
| end = FIX2INT(gf_mulfix(_this->pos[0], maxPos)); | |
| end = MIN(end, EVGGRADIENTMAXINTPOS); | |
| for (i=0; i<= end; i++) { | |
| _this->precomputed_argb[i] = _this->col[0]; | |
| } | |
| } | |
| for (c=0; c<EVGGRADIENTSLOTS; c++) { | |
| if (_this->pos[c]<0) break; | |
| if (_this->pos[c+1]>=0) { | |
| Fixed pos = MIN(_this->pos[c], FIX_ONE); | |
| start = FIX2INT(gf_mulfix(pos, maxPos)); | |
| pos = MIN(_this->pos[c+1], FIX_ONE); | |
| end = FIX2INT(gf_mulfix(pos, maxPos)); | |
| end = MIN(end, EVGGRADIENTMAXINTPOS); | |
| diff = end-start; | |
| if (diff) { | |
| for (i=start; i<=end; i++) { | |
| _this->precomputed_argb[i] = color_interpolate(_this->col[c], _this->col[c+1], | |
| (u8) ( ( (i-start) * 255) / diff) ); | |
| } | |
| } | |
| } else { | |
| Fixed pos = MIN(_this->pos[c+0], FIX_ONE); | |
| start = FIX2INT(gf_mulfix(pos, maxPos)); | |
| for(i=start; i<=EVGGRADIENTMAXINTPOS; i++) { | |
| _this->precomputed_argb[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->precomputed_dest[(pos & max_pos) ? EVGGRADIENTMAXINTPOS - (pos % max_pos) : pos % max_pos]; | |
| case GF_GRADIENT_MODE_REPEAT: | |
| while (pos < 0) pos += max_pos; | |
| return _this->precomputed_dest[pos % max_pos]; | |
| case GF_GRADIENT_MODE_PAD: | |
| default: | |
| return _this->precomputed_dest[ MIN(EVGGRADIENTMAXINTPOS, MAX((s32) 0, pos))]; | |
| } | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_gradient_interpolation(GF_EVGStencil * 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; | |
| if (count) { | |
| 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_EXPORT | |
| GF_Err gf_evg_stencil_push_gradient_interpolation(GF_EVGStencil * p, Fixed pos, GF_Color col) | |
| { | |
| u32 count=0; | |
| EVG_BaseGradient *_this = (EVG_BaseGradient *) p; | |
| if ( (_this->type != GF_STENCIL_LINEAR_GRADIENT) && (_this->type != GF_STENCIL_RADIAL_GRADIENT) ) return GF_BAD_PARAM; | |
| while (count<EVGGRADIENTSLOTS-1) { | |
| if (_this->pos[count]==-FIX_ONE) break; | |
| count++; | |
| } | |
| if (count>=EVGGRADIENTSLOTS-1) return GF_OUT_OF_MEM; | |
| _this->col[count] = col; | |
| _this->pos[count] = pos; | |
| count++; | |
| _this->col[count] = 0; | |
| _this->pos[count] = -FIX_ONE; | |
| gradient_update(_this); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_gradient_mode(GF_EVGStencil * 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_EXPORT | |
| GF_EVGStencil * gf_evg_stencil_new(GF_StencilType type) | |
| { | |
| GF_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_texture_brush(); | |
| break; | |
| default: | |
| return NULL; | |
| } | |
| if (st) { | |
| gf_mx2d_init(st->pmat); | |
| gf_mx2d_init(st->smat); | |
| gf_cmx_init(&st->cmat); | |
| st->auto_mx = 1; | |
| } | |
| return st; | |
| } | |
| GF_EXPORT | |
| void gf_evg_stencil_delete(GF_EVGStencil * st) | |
| { | |
| switch(st->type) { | |
| case GF_STENCIL_SOLID: | |
| case GF_STENCIL_LINEAR_GRADIENT: | |
| case GF_STENCIL_RADIAL_GRADIENT: | |
| gf_free(st); | |
| return; | |
| case GF_STENCIL_TEXTURE: | |
| { | |
| EVG_Texture *tx = (EVG_Texture *)st; | |
| /*destroy local texture iof any*/ | |
| if (tx->owns_texture && tx->pixels) gf_free(tx->pixels); | |
| gf_free(st); | |
| } | |
| return; | |
| } | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_auto_matrix(GF_EVGStencil * st, Bool auto_on) | |
| { | |
| if (!st) return GF_BAD_PARAM; | |
| st->auto_mx = auto_on ? 1 : 0; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| Bool gf_evg_stencil_get_auto_matrix(GF_EVGStencil * st) | |
| { | |
| return st ? st->auto_mx : GF_FALSE; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_matrix(GF_EVGStencil * st, GF_Matrix2D *mx) | |
| { | |
| if (!st || (st->type>GF_STENCIL_TEXTURE)) return GF_BAD_PARAM; | |
| if (mx) { | |
| gf_mx2d_copy(st->smat, *mx); | |
| } else { | |
| gf_mx2d_init(st->smat); | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| Bool gf_evg_stencil_get_matrix(GF_EVGStencil * st, GF_Matrix2D *mx) | |
| { | |
| if (!st || !mx || (st->type>GF_STENCIL_TEXTURE)) return GF_FALSE; | |
| gf_mx2d_copy(*mx, st->smat); | |
| return GF_TRUE; | |
| } | |
| GF_EXPORT | |
| GF_StencilType gf_evg_stencil_type(GF_EVGStencil *sten) | |
| { | |
| return sten ? sten->type : 0; | |
| } | |
| /* | |
| Solid color stencil | |
| */ | |
| static void sc_fill_run(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 x, s32 y, u32 count) | |
| { | |
| EVG_Brush *sc = (EVG_Brush *)p; | |
| u32 *data = rctx->stencil_pix_run; | |
| u64 *data_wide = rctx->surf->not_8bits ? rctx->stencil_pix_run : NULL; | |
| while (count) { | |
| if (data) *data++ = sc->fill_col; | |
| else *data_wide++ = sc->fill_col_wide; | |
| count--; | |
| } | |
| } | |
| static GF_EVGStencil *evg_solid_brush() | |
| { | |
| EVG_Brush *tmp; | |
| GF_SAFEALLOC(tmp, EVG_Brush); | |
| if (!tmp) return 0L; | |
| tmp->fill_run = sc_fill_run; | |
| tmp->color = 0xFF000000; | |
| tmp->alpha = 0xFF; | |
| tmp->type = GF_STENCIL_SOLID; | |
| return (GF_EVGStencil *) tmp; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_brush_color(GF_EVGStencil * 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; | |
| } | |
| GF_EXPORT | |
| GF_Color gf_evg_stencil_get_brush_color(GF_EVGStencil * st) | |
| { | |
| EVG_Brush *_this = (EVG_Brush *) st; | |
| if (!_this || (_this ->type != GF_STENCIL_SOLID) ) return 0; | |
| return _this->color; | |
| } | |
| #define edgeFunction_pre2(a, b_minus_a_x, b_minus_a_y) \ | |
| ( (_x - a.x) * (b_minus_a_y) - (_y - a.y) * (b_minus_a_x) ) / surf->tri_area | |
| #define PERSP_VARS_DECL \ | |
| GF_EVGSurface *surf = rctx->surf; \ | |
| Float bc1 = edgeFunction_pre2(surf->s_v2, surf->s3_m_s2_x, surf->s3_m_s2_y); \ | |
| Float bc3 = edgeFunction_pre2(surf->s_v1, surf->s2_m_s1_x, surf->s2_m_s1_y); \ | |
| Float bc1_inc = surf->s3_m_s2_y / surf->tri_area; \ | |
| Float bc3_inc = surf->s2_m_s1_y / surf->tri_area; \ | |
| Float pbc1 = bc1 * surf->s_v1.q; \ | |
| Float pbc3 = bc3 * surf->s_v3.q; \ | |
| Float pbc2 = (1.0f - bc1 - bc3) * surf->s_v2.q; \ | |
| Float pbc1_inc = bc1_inc * surf->s_v1.q; \ | |
| Float pbc3_inc = bc3_inc * surf->s_v3.q; \ | |
| Float pbc2_inc = - (bc1_inc + bc3_inc) * surf->s_v2.q; \ | |
| Float persp_denum = pbc1 + pbc2 + pbc3; \ | |
| Float pers_denum_inc = pbc1_inc + pbc2_inc + pbc3_inc; | |
| //we map texture coords, pt1 is {0,0} pt2 is {1,0} pt3 is {0,1} | |
| //y flip is done by switching the points in evg_raster_render_path_3d | |
| #define PERSP_APPLY \ | |
| Fixed ix = FLT2FIX(pbc2 / persp_denum);\ | |
| Fixed iy = FLT2FIX(pbc3 / persp_denum);\ | |
| pbc2 += pbc2_inc;\ | |
| pbc3 += pbc3_inc;\ | |
| persp_denum += pers_denum_inc; | |
| /* | |
| linear gradient stencil | |
| */ | |
| static void lg_fill_run(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| Fixed _res; | |
| s32 val; | |
| u32 col; | |
| u32 *data = rctx->stencil_pix_run; | |
| u64 *data_wide = rctx->surf->not_8bits ? rctx->stencil_pix_run : NULL; | |
| EVG_LinearGradient *_this = (EVG_LinearGradient *) p; | |
| gf_assert(data); | |
| if (rctx->surf->is_3d_matrix) { | |
| PERSP_VARS_DECL | |
| while (count) { | |
| PERSP_APPLY | |
| gf_mx2d_apply_coords(&_this->smat, &ix, &iy); | |
| val = FIX2INT(ix); | |
| col = gradient_get_color((EVG_BaseGradient *)_this, val ); | |
| if (data_wide) *data_wide++ = evg_col_to_wide(col); | |
| else *data++ = col; | |
| count--; | |
| } | |
| } else { | |
| /*no need to move x & y to fixed*/ | |
| _res = (Fixed) (_x * _this->smat.m[0] + _y * _this->smat.m[1] + _this->smat.m[2]); | |
| while (count) { | |
| val = FIX2INT(_res); | |
| _res += _this->smat.m[0]; | |
| col = gradient_get_color((EVG_BaseGradient *)_this, val ); | |
| if (data_wide) *data_wide++ = evg_col_to_wide(col); | |
| else *data++ = col; | |
| count--; | |
| } | |
| } | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_linear_gradient(GF_EVGStencil * 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; | |
| } | |
| static GF_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 = lg_fill_run; | |
| tmp->type = GF_STENCIL_LINEAR_GRADIENT; | |
| for(i=0; i<EVGGRADIENTSLOTS; i++) tmp->pos[i]=-1; | |
| tmp->alpha = 0xFF; | |
| gf_evg_stencil_set_linear_gradient((GF_EVGStencil *)tmp, 0, 0, FIX_ONE, 0); | |
| return (GF_EVGStencil *) tmp; | |
| } | |
| /* | |
| radial gradient stencil | |
| */ | |
| static void rg_fill_run(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| Fixed x, y, dx, dy, b, val; | |
| s32 pos; | |
| u32 col; | |
| u32 *data = rctx->stencil_pix_run; | |
| u64 *data_wide = rctx->surf->not_8bits ? rctx->stencil_pix_run : NULL; | |
| EVG_RadialGradient *_this = (EVG_RadialGradient *) p; | |
| gf_assert(data); | |
| if (rctx->surf->is_3d_matrix) { | |
| PERSP_VARS_DECL | |
| while (count) { | |
| PERSP_APPLY | |
| gf_mx2d_apply_coords(&_this->smat, &ix, &iy); | |
| dx = ix - _this->d_f.x; | |
| dy = iy - _this->d_f.y; | |
| 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); | |
| col = gradient_get_color((EVG_BaseGradient *)_this, pos ); | |
| if (data_wide) *data_wide++ = evg_col_to_wide(col); | |
| else *data++ = col; | |
| count--; | |
| } | |
| } else { | |
| x = INT2FIX(_x); | |
| y = INT2FIX(_y); | |
| gf_mx2d_apply_coords(&_this->smat, &x, &y); | |
| 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); | |
| col = gradient_get_color((EVG_BaseGradient *)_this, pos); | |
| if (data_wide) *data_wide++ = evg_col_to_wide(col); | |
| else *data++ = col; | |
| 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; | |
| } | |
| } | |
| static GF_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; | |
| tmp->alpha = 0xFF; | |
| return (GF_EVGStencil *) tmp; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_radial_gradient(GF_EVGStencil * 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; | |
| } | |
| void evg_gradient_precompute(EVG_BaseGradient *grad, GF_EVGSurface *surf) | |
| { | |
| Bool do_cmat, do_yuv, has_a, has_changed; | |
| u32 i, nb_col; | |
| has_changed = grad->updated; | |
| if (surf->yuv_type) { | |
| if (grad->yuv_prof != surf->yuv_prof) { | |
| grad->yuv_prof = surf->yuv_prof; | |
| has_changed = GF_TRUE; | |
| } | |
| } else { | |
| if (grad->yuv_prof) { | |
| grad->yuv_prof = 0; | |
| has_changed = GF_TRUE; | |
| } | |
| } | |
| if (!has_changed) { | |
| return; | |
| } | |
| grad->updated = 0; | |
| do_yuv = (surf->yuv_type==EVG_YUV_NONE) ? GF_FALSE : GF_TRUE; | |
| do_cmat = (grad->cmat.identity) ? GF_FALSE : GF_TRUE; | |
| has_a = (grad->alpha==0xFF) ? GF_FALSE : GF_TRUE; | |
| nb_col = (1<<EVGGRADIENTBITS); | |
| for (i=0; i<nb_col; i++) { | |
| u32 argb = grad->precomputed_argb[i]; | |
| if (has_a) { | |
| u32 ca = ((u32) (GF_COL_A(argb) + 1) * grad->alpha) >> 8; | |
| argb = ( ((ca<<24) & 0xFF000000) ) | (argb & 0x00FFFFFF); | |
| } | |
| if (do_cmat) | |
| argb = gf_cmx_apply(&grad->cmat, argb); | |
| if (do_yuv) | |
| argb = gf_evg_argb_to_ayuv(surf, argb); | |
| grad->precomputed_dest[i] = argb; | |
| } | |
| } | |
| /* | |
| Texture stencil | |
| FIXME: add filtering , check bilinear | |
| */ | |
| static GFINLINE s32 mul255(s32 a, s32 b) | |
| { | |
| return ((a+1) * b) >> 8; | |
| } | |
| 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; | |
| if (!t) return c0; | |
| 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)); | |
| return GF_COL_ARGB(a2, r2, g2, b2); | |
| } | |
| static GFINLINE s64 mul_wide(s64 a, s64 b) | |
| { | |
| return ((a+1) * b) >> 16; | |
| } | |
| static u64 EVG_LERP_WIDE(u64 c0, u64 c1, u8 t) | |
| { | |
| s64 a0, r0, g0, b0; | |
| s64 a1, r1, g1, b1; | |
| s64 a2, r2, g2, b2; | |
| if (!t) return c0; | |
| a0 = (c0>>48) & 0xFFFF; | |
| r0 = (c0>>32) & 0xFFFF; | |
| g0 = (c0>>16) & 0xFFFF; | |
| b0 = (c0) & 0xFFFF; | |
| a1 = (c1>>48) & 0xFFFF; | |
| r1 = (c1>>32) & 0xFFFF; | |
| g1 = (c1>>16) & 0xFFFF; | |
| b1 = (c1) & 0xFFFF; | |
| a2 = a0 + mul_wide(t, (a1 - a0)); | |
| r2 = r0 + mul_wide(t, (r1 - r0)); | |
| g2 = g0 + mul_wide(t, (g1 - g0)); | |
| b2 = b0 + mul_wide(t, (b1 - b0)); | |
| return GF_COLW_ARGB(a2, r2, g2, b2); | |
| } | |
| //slightly more precise but way too expensive as it uses mx2d apply | |
| //#define EXACT_TX_COORDS | |
| static void tex_untransform_coord(EVG_Texture *_this, s32 _x, s32 _y, Fixed *outx, Fixed *outy) | |
| { | |
| Fixed x, y; | |
| /* reverse to texture coords*/ | |
| x = INT2FIX(_x); | |
| y = INT2FIX(_y); | |
| gf_mx2d_apply_coords(&_this->smat, &x, &y); | |
| #ifdef EXACT_TX_COORDS | |
| u32 checkx = 0; | |
| u32 checky = 0; | |
| if (ABS(x)< FIX_ONE/20) checkx = 1; | |
| if (ABS(y)< FIX_ONE/20) checky = 1; | |
| /*we may have a numerical stability issues, try to figure out whether we are close from 0 or width/height*/ | |
| if ( checkx || checky) { | |
| Fixed tx, ty; | |
| tx = INT2FIX(_x+1); | |
| ty = INT2FIX(_y+1); | |
| gf_mx2d_apply_coords(&_this->smat, &tx, &ty); | |
| if (checkx) { | |
| if (tx<0) x = INT2FIX(_this->width - 1); | |
| else x = 0; | |
| } | |
| if (checky) { | |
| if (ty<0) y = INT2FIX(_this->height - 1); | |
| else y = 0; | |
| } | |
| } | |
| #endif | |
| *outx=x; | |
| *outy=y; | |
| } | |
| #ifdef EXACT_TX_COORDS | |
| #define TEX_UNTRANSFORM_COORDS \ | |
| _x++; \ | |
| tex_untransform_coord(_this, _x, _y, &x, &y); | |
| #else | |
| #define TEX_UNTRANSFORM_COORDS \ | |
| x += _this->inc_x; \ | |
| y += _this->inc_y; \ | |
| #endif | |
| static u32 evg_paramtx_get_pixel(struct __evg_texture *_this, u32 x, u32 y, EVGRasterCtx *rctx) | |
| { | |
| Float a, r, g, b; | |
| _this->tx_callback(_this->tx_callback_udta, x, y, &r, &g, &b, &a); | |
| r*=255; | |
| g*=255; | |
| b*=255; | |
| a*=255; | |
| return GF_COL_ARGB(a, r, g, b); | |
| } | |
| u64 evg_paramtx_get_pixel_wide(struct __evg_texture *_this, u32 x, u32 y, EVGRasterCtx *rctx) | |
| { | |
| Float a, r, g, b; | |
| _this->tx_callback(_this->tx_callback_udta, x, y, &r, &g, &b, &a); | |
| r*=0xFFFF; | |
| g*=0xFFFF; | |
| b*=0xFFFF; | |
| a*=0xFFFF; | |
| return GF_COLW_ARGB(a, r, g, b); | |
| } | |
| static void tex_fill_run_callback(GF_EVGStencil *_p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| EVG_Texture *p = (EVG_Texture *)_p; | |
| u32 *data = rctx->stencil_pix_run; | |
| while (count) { | |
| *data = evg_paramtx_get_pixel(p, _x, _y, NULL); | |
| data++; | |
| count--; | |
| _x++; | |
| } | |
| } | |
| static void tex_fill_run_callback_wide(GF_EVGStencil *_p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| EVG_Texture *p = (EVG_Texture *)_p; | |
| u64 *data = rctx->stencil_pix_run; | |
| while (count) { | |
| *data = evg_paramtx_get_pixel_wide(p, _x, _y, NULL); | |
| data++; | |
| count--; | |
| } | |
| } | |
| //bilinear used fo 2D graphics ? | |
| #define USE_BILINEAR 1 | |
| static void tex_fill_run(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 cx, x0, y0, m_width, m_height; | |
| u32 pix; | |
| Bool has_alpha, has_cmat, repeat_s, repeat_t; | |
| Fixed x, y; | |
| #if USE_BILINEAR | |
| s32 incx, incy; | |
| #endif | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u32 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| tex_untransform_coord(_this, _x, _y, &x, &y); | |
| #if USE_BILINEAR | |
| incx = (_this->inc_x>0) ? 1 : -1; | |
| incy = (_this->inc_y>0) ? 1 : -1; | |
| #endif | |
| repeat_s = _this->mod & GF_TEXTURE_REPEAT_S; | |
| repeat_t = _this->mod & GF_TEXTURE_REPEAT_T; | |
| has_alpha = (_this->alpha != 255) ? GF_TRUE : GF_FALSE; | |
| has_cmat = _this->cmat.identity ? GF_FALSE : GF_TRUE; | |
| m_width = _this->width-1; | |
| m_height = _this->height-1; | |
| while (count) { | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| x0 = (x0) % _this->width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += _this->width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| y0 = FIX2INT(y); | |
| if (y0 > m_height) { | |
| if (repeat_t) { | |
| y0 = (y0) % _this->height; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| y0 = m_height; | |
| } | |
| } | |
| else if (y0 < 0) { | |
| if (repeat_t) { | |
| while (y0<0) y0 += _this->height; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| y0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel(_this, x0, y0, rctx); | |
| TEX_UNTRANSFORM_COORDS | |
| /*bilinear filtering*/ | |
| #if USE_BILINEAR | |
| if (_this->filter==GF_TEXTURE_FILTER_HIGH_QUALITY) { | |
| Bool do_lerp=GF_TRUE; | |
| u32 p00, p01, p10, p11; | |
| s32 x1, y1; | |
| u8 tx, ty; | |
| tx = FIX2INT(gf_muldiv(x, 255, _this->width) ); | |
| ty = FIX2INT(gf_muldiv(y, 255, _this->height) ); | |
| x1 = (x0+incx); | |
| if (x1<0) { | |
| if (!repeat_s) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (x1<0) x1 += _this->width; | |
| } else { | |
| if (!repeat_s && ((u32) x1 > _this->width)) | |
| do_lerp=GF_FALSE; | |
| else | |
| x1 = x1 % _this->width; | |
| } | |
| y1 = (y0+incy); | |
| if (y1<0) { | |
| if (!repeat_t) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (y1<0) y1+=_this->height; | |
| } else { | |
| if (!repeat_t && ((u32) y1 > _this->height)) | |
| do_lerp=GF_FALSE; | |
| else | |
| y1 = y1 % _this->height; | |
| } | |
| if (!do_lerp) goto write_pix; | |
| if (incx>0) { | |
| if (x1<x0) tx = 255-tx; | |
| } else { | |
| if (x1>x0) tx = 255-tx; | |
| } | |
| if (incy>0) { | |
| if (y1<y0) ty = 255-ty; | |
| } else { | |
| if (y1>y0) ty = 255-ty; | |
| } | |
| p00 = pix; | |
| p01 = _this->tx_get_pixel(_this, x1, y0, rctx); | |
| p10 = _this->tx_get_pixel(_this, x0, y1, rctx); | |
| p11 = _this->tx_get_pixel(_this, x1, y1, rctx); | |
| p00 = EVG_LERP(p00, p01, tx); | |
| p10 = EVG_LERP(p10, p11, tx); | |
| pix = EVG_LERP(p00, p10, ty); | |
| } | |
| #endif | |
| write_pix: | |
| if (has_alpha) { | |
| cx = ((GF_COL_A(pix) + 1) * _this->alpha) >> 8; | |
| pix = ( (((u32)cx<<24) & 0xFF000000) ) | (pix & 0x00FFFFFF); | |
| } | |
| //move pixel to target pixel format, applying color transform matrix | |
| if (_this->is_yuv) { | |
| //if surf is rgb, transform | |
| if (!yuv_type) { | |
| pix = gf_evg_ayuv_to_argb(rctx->surf, pix); | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply(&_this->cmat, pix); | |
| } else if (has_cmat) { | |
| //yuv->yuv , use color matrix in yuv domain | |
| //this is equivalent to gf_evg_ayuv_to_argb, gf_cmx_apply(&_this->cmat, pix), gf_evg_argb_to_ayuv | |
| pix = gf_cmx_apply(&_this->yuv_cmat, pix); | |
| } | |
| } | |
| //texture is RGB | |
| else { | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply(&_this->cmat, pix); | |
| //dest is yuv, transform | |
| if (yuv_type) | |
| pix = gf_evg_argb_to_ayuv(rctx->surf, pix); | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| /*just a little faster...*/ | |
| static void tex_fill_run_straight(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 x0, y0, m_width; | |
| u32 pix; | |
| u32 conv_type=0; | |
| Bool repeat_s = GF_FALSE; | |
| u32 pad_y = 0; | |
| Fixed x, y; | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u32 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| /*get texture coords in FIXED - offset*/ | |
| x = _this->smat.m[0]*_x; | |
| x += _this->smat.m[2]; | |
| y = _this->smat.m[4]*_y + _this->smat.m[5]; | |
| /*we may have a numerical stability issues, try to figure out whether we are close from 0 or width/height*/ | |
| if (ABS(x)< FIX_ONE/10) { | |
| Fixed test = _this->smat.m[0]*(_x+1) + _this->smat.m[2]; | |
| if (test<0) | |
| x = INT2FIX(_this->width - 1); | |
| else x = 0; | |
| } | |
| if (ABS(y)< FIX_ONE/10) { | |
| Fixed test = _this->smat.m[4]*(_y+1) + _this->smat.m[5]; | |
| if (test<0) | |
| y = INT2FIX(_this->height - 1); | |
| else y = 0; | |
| } | |
| repeat_s = (_this->mod & GF_TEXTURE_REPEAT_S); | |
| y0 = FIX2INT(y); | |
| if (y0<0) { | |
| if (_this->mod & GF_TEXTURE_REPEAT_T) { | |
| while (y0<0) y0 += (s32) _this->height; | |
| } else if (_this->fill_pad_color) | |
| pad_y = _this->fill_pad_color; | |
| else | |
| y0 = 0; | |
| } else if (y0 >= (s32) _this->height) { | |
| if (_this->mod & GF_TEXTURE_REPEAT_T) | |
| while (y0 >= (s32) _this->height) y0 -= (s32) _this->height; | |
| else if (_this->fill_pad_color) | |
| pad_y = _this->fill_pad_color; | |
| else | |
| y0 = _this->height-1; | |
| } | |
| if (pad_y) { | |
| while (count) { | |
| *data++ = pad_y; | |
| count--; | |
| } | |
| return; | |
| } | |
| m_width = _this->width - 1; | |
| if (_this->is_yuv && !yuv_type) conv_type = 1; | |
| else if (!_this->is_yuv && yuv_type) conv_type = 2; | |
| while (count) { | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| while ((u32) x0 >= _this->width) x0 -= _this->width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += _this->width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel(_this, x0, y0, rctx); | |
| write_pix: | |
| x += _this->inc_x; | |
| //move pixel to target pixel format | |
| switch (conv_type) { | |
| case 1: | |
| pix = gf_evg_ayuv_to_argb(rctx->surf, pix); | |
| break; | |
| case 2: | |
| pix = gf_evg_argb_to_ayuv(rctx->surf, pix); | |
| break; | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| u64 evg_col_to_wide( u32 col) | |
| { | |
| u32 a = GF_COL_A(col) << 8 | 0xFF; | |
| u32 r = GF_COL_R(col) << 8 | 0xFF; | |
| u32 g = GF_COL_G(col) << 8 | 0xFF; | |
| u32 b = GF_COL_B(col) << 8 | 0xFF; | |
| return GF_COLW_ARGB(a, r, g, b); | |
| } | |
| static void tex_fill_run_wide(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 x0, y0, m_width, m_height; | |
| u64 pix; | |
| Bool has_alpha, has_cmat, repeat_s, repeat_t; | |
| Fixed x, y; | |
| #if USE_BILINEAR | |
| s32 incx, incy; | |
| #endif | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u64 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| tex_untransform_coord(_this, _x, _y, &x, &y); | |
| #if USE_BILINEAR | |
| incx = (_this->inc_x>0) ? 1 : -1; | |
| incy = (_this->inc_y>0) ? 1 : -1; | |
| #endif | |
| repeat_s = _this->mod & GF_TEXTURE_REPEAT_S; | |
| repeat_t = _this->mod & GF_TEXTURE_REPEAT_T; | |
| has_alpha = (_this->alpha != 255) ? GF_TRUE : GF_FALSE; | |
| has_cmat = _this->cmat.identity ? GF_FALSE : GF_TRUE; | |
| m_width = _this->width - 1; | |
| m_height = _this->height - 1; | |
| while (count) { | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| x0 = (x0) % _this->width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += _this->width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| y0 = FIX2INT(y); | |
| if (y0 > m_height) { | |
| if (repeat_t) { | |
| y0 = (y0) % _this->height; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| y0 = m_height; | |
| } | |
| } | |
| else if (y0 < 0) { | |
| if (repeat_t) { | |
| while (y0<0) y0 += _this->height; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| TEX_UNTRANSFORM_COORDS | |
| goto write_pix; | |
| } else { | |
| y0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel_wide(_this, x0, y0, rctx); | |
| TEX_UNTRANSFORM_COORDS | |
| /*bilinear filtering*/ | |
| #if USE_BILINEAR | |
| if (_this->filter==GF_TEXTURE_FILTER_HIGH_QUALITY) { | |
| u64 p00, p01, p10, p11; | |
| s32 x1, y1; | |
| u8 tx, ty; | |
| Bool do_lerp=GF_TRUE; | |
| tx = FIX2INT(gf_muldiv(x, 255, _this->width) ); | |
| ty = FIX2INT(gf_muldiv(y, 255, _this->height) ); | |
| x1 = (x0+incx); | |
| if (x1<0) { | |
| if (!repeat_s) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (x1<0) x1 += _this->width; | |
| } else { | |
| if (!repeat_s && ((u32) x1 > _this->width)) | |
| do_lerp=GF_FALSE; | |
| else | |
| x1 = x1 % _this->width; | |
| } | |
| y1 = (y0+incy); | |
| if (y1<0) { | |
| if (!repeat_t) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (y1<0) y1+=_this->height; | |
| } else { | |
| if (!repeat_t && ((u32) y1 > _this->height)) | |
| do_lerp=GF_FALSE; | |
| else | |
| y1 = y1 % _this->height; | |
| } | |
| if (!do_lerp) goto write_pix; | |
| if (incx>0) { | |
| if (x1<x0) tx = 255-tx; | |
| } else { | |
| if (x1>x0) tx = 255-tx; | |
| } | |
| if (incy>0) { | |
| if (y1<y0) ty = 255-ty; | |
| } else { | |
| if (y1>y0) ty = 255-ty; | |
| } | |
| p00 = pix; | |
| p01 = _this->tx_get_pixel_wide(_this, x1, y0, rctx); | |
| p10 = _this->tx_get_pixel_wide(_this, x0, y1, rctx); | |
| p11 = _this->tx_get_pixel_wide(_this, x1, y1, rctx); | |
| p00 = EVG_LERP_WIDE(p00, p01, tx); | |
| p10 = EVG_LERP_WIDE(p10, p11, tx); | |
| pix = EVG_LERP_WIDE(p00, p10, ty); | |
| } | |
| #endif | |
| write_pix: | |
| if (has_alpha) { | |
| u64 _a = (pix>>48)&0xFF; | |
| _a = (_a * _this->alpha) >> 8; | |
| _a<<=48; | |
| pix = ( (_a & 0xFFFF000000000000UL) ) | (pix & 0x0000FFFFFFFFFFFFUL); | |
| } | |
| //move pixel to target pixel format, applying color transform matrix | |
| if (_this->is_yuv) { | |
| //if surf is rgb, transform | |
| if (!yuv_type) { | |
| pix = gf_evg_ayuv_to_argb_wide(rctx->surf, pix); | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply_wide(&_this->cmat, pix); | |
| } else if (has_cmat) { | |
| //yuv->yuv , use color matrix in yuv domain | |
| //this is equivalent to gf_evg_ayuv_to_argb, gf_cmx_apply(&_this->cmat, pix), gf_evg_argb_to_ayuv | |
| pix = gf_cmx_apply_wide(&_this->yuv_cmat, pix); | |
| } | |
| } | |
| //texture is RGB | |
| else { | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply_wide(&_this->cmat, pix); | |
| //dest is yuv, transform | |
| if (yuv_type) | |
| pix = gf_evg_argb_to_ayuv_wide(rctx->surf, pix); | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| /*just a little faster...*/ | |
| static void tex_fill_run_straight_wide(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 x0, y0, m_width; | |
| u64 pix, pad_y=0; | |
| u32 conv_type=0; | |
| Bool repeat_s = GF_FALSE; | |
| Fixed x, y; | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u64 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| /*get texture coords in FIXED - offset*/ | |
| x = _this->smat.m[0]*_x + _this->smat.m[2]; | |
| y = _this->smat.m[4]*_y + _this->smat.m[5]; | |
| /*we may have a numerical stability issues, try to figure out whether we are close from 0 or width/height*/ | |
| if (ABS(x)< FIX_ONE/10) { | |
| Fixed test = _this->smat.m[0]*(_x+1) + _this->smat.m[2]; | |
| if (test<0) x = INT2FIX(_this->width - 1); | |
| else x = 0; | |
| } | |
| if (ABS(y)< FIX_ONE/10) { | |
| Fixed test = _this->smat.m[4]*(_y+1) + _this->smat.m[5]; | |
| if (test<0) y = INT2FIX(_this->height - 1); | |
| else y = 0; | |
| } | |
| /* and move in absolute coords*/ | |
| repeat_s = (_this->mod & GF_TEXTURE_REPEAT_S); | |
| y0 = FIX2INT(y); | |
| if (y0<0) { | |
| if (_this->mod & GF_TEXTURE_REPEAT_T) | |
| while (y0<0) y0 += _this->height; | |
| else if (_this->fill_pad_color_wide) | |
| pad_y = _this->fill_pad_color_wide; | |
| else | |
| y0 = 0; | |
| } else if (y0>=(s32) _this->height) { | |
| if (_this->mod & GF_TEXTURE_REPEAT_T) | |
| while ((u32) y0 > _this->height) y0 -= _this->height; | |
| else if (_this->fill_pad_color_wide) | |
| pad_y = _this->fill_pad_color_wide; | |
| else | |
| y0 = _this->height-1; | |
| } | |
| if (pad_y) { | |
| while (count) { | |
| *data++ = pad_y; | |
| count--; | |
| } | |
| return; | |
| } | |
| m_width = _this->width - 1; | |
| if (_this->is_yuv && !yuv_type) conv_type = 1; | |
| else if (!_this->is_yuv && yuv_type) conv_type = 2; | |
| while (count) { | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| x0 = (x0) % _this->width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += _this->width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel_wide(_this, x0, y0, rctx); | |
| write_pix: | |
| x += _this->inc_x; | |
| //move pixel to target pixel format | |
| switch (conv_type) { | |
| case 1: | |
| pix = gf_evg_ayuv_to_argb_wide(rctx->surf, pix); | |
| break; | |
| case 2: | |
| pix = gf_evg_argb_to_ayuv_wide(rctx->surf, pix); | |
| break; | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| static void tex_fill_run_3d(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 cx, x0, y0, m_width, m_height; | |
| u32 pix; | |
| Bool has_alpha, has_cmat, repeat_s, repeat_t; | |
| Fixed x, y; | |
| #if USE_BILINEAR | |
| s32 incx, incy; | |
| #endif | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u32 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| #if USE_BILINEAR | |
| Bool use_bili = (_this->filter==GF_TEXTURE_FILTER_HIGH_QUALITY) ? 1 : 0; | |
| incx = (_this->inc_x>0) ? 1 : -1; | |
| incy = (_this->inc_y>0) ? 1 : -1; | |
| #endif | |
| Bool do_mx = gf_mx2d_is_identity(_this->smat_bck) ? GF_FALSE : GF_TRUE; | |
| repeat_s = _this->mod & GF_TEXTURE_REPEAT_S; | |
| repeat_t = _this->mod & GF_TEXTURE_REPEAT_T; | |
| has_alpha = (_this->alpha != 255) ? GF_TRUE : GF_FALSE; | |
| has_cmat = _this->cmat.identity ? GF_FALSE : GF_TRUE; | |
| m_width = _this->width-1; | |
| m_height = _this->height-1; | |
| PERSP_VARS_DECL | |
| while (count) { | |
| PERSP_APPLY | |
| if (do_mx) | |
| gf_mx2d_apply_coords(&_this->smat_bck, &ix, &iy); | |
| x = m_width * ix; | |
| y = m_height * iy; | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| while (x0>m_width) x0 -= m_width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += m_width; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| y0 = FIX2INT(y); | |
| if (y0 > m_height) { | |
| if (repeat_t) { | |
| while (y0>m_height) y0 -= m_height; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| y0 = m_height; | |
| } | |
| } | |
| else if (y0 < 0) { | |
| if (repeat_t) { | |
| while (y0<0) y0 += m_height; | |
| } else if (_this->fill_pad_color) { | |
| pix = _this->fill_pad_color; | |
| goto write_pix; | |
| } else { | |
| y0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel(_this, x0, y0, rctx); | |
| /*bilinear filtering*/ | |
| #if USE_BILINEAR | |
| if (use_bili) { | |
| Bool do_lerp=GF_TRUE; | |
| u32 p00, p01, p10, p11; | |
| s32 x1, y1; | |
| u8 tx, ty; | |
| tx = FIX2INT(gf_muldiv(x, 255, m_width) ); | |
| ty = FIX2INT(gf_muldiv(y, 255, m_height) ); | |
| x1 = (x0+incx); | |
| if (x1<0) { | |
| if (!repeat_s) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (x1<0) x1 += m_width; | |
| } else { | |
| if (!repeat_s && (x1 > m_width)) | |
| do_lerp=GF_FALSE; | |
| else | |
| x1 = x1 % m_width; | |
| } | |
| y1 = (y0+incy); | |
| if (y1<0) { | |
| if (!repeat_t) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (y1<0) y1 += m_height; | |
| } else { | |
| if (!repeat_t && (y1 > m_height)) | |
| do_lerp=GF_FALSE; | |
| else | |
| y1 = y1 % m_height; | |
| } | |
| if (!do_lerp) goto write_pix; | |
| if (incx>0) { | |
| if (x1<x0) tx = 255-tx; | |
| } else { | |
| if (x1>x0) tx = 255-tx; | |
| } | |
| if (incy>0) { | |
| if (y1<y0) ty = 255-ty; | |
| } else { | |
| if (y1>y0) ty = 255-ty; | |
| } | |
| p00 = pix; | |
| p01 = _this->tx_get_pixel(_this, x1, y0, rctx); | |
| p10 = _this->tx_get_pixel(_this, x0, y1, rctx); | |
| p11 = _this->tx_get_pixel(_this, x1, y1, rctx); | |
| p00 = EVG_LERP(p00, p01, tx); | |
| p10 = EVG_LERP(p10, p11, tx); | |
| pix = EVG_LERP(p00, p10, ty); | |
| } | |
| #endif | |
| write_pix: | |
| if (has_alpha) { | |
| cx = ((GF_COL_A(pix) + 1) * _this->alpha) >> 8; | |
| pix = ( (((u32)cx<<24) & 0xFF000000) ) | (pix & 0x00FFFFFF); | |
| } | |
| //move pixel to target pixel format, applying color transform matrix | |
| if (_this->is_yuv) { | |
| //if surf is rgb, transform | |
| if (!yuv_type) { | |
| pix = gf_evg_ayuv_to_argb(rctx->surf, pix); | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply(&_this->cmat, pix); | |
| } else if (has_cmat) { | |
| //yuv->yuv , use color matrix in yuv domain | |
| //this is equivalent to gf_evg_ayuv_to_argb, gf_cmx_apply(&_this->cmat, pix), gf_evg_argb_to_ayuv | |
| pix = gf_cmx_apply(&_this->yuv_cmat, pix); | |
| } | |
| } | |
| //texture is RGB | |
| else { | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply(&_this->cmat, pix); | |
| //dest is yuv, transform | |
| if (yuv_type) | |
| pix = gf_evg_argb_to_ayuv(rctx->surf, pix); | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| static void tex_fill_run_3d_wide(GF_EVGStencil *p, EVGRasterCtx *rctx, s32 _x, s32 _y, u32 count) | |
| { | |
| s32 x0, y0, m_width, m_height; | |
| u64 pix; | |
| Bool has_alpha, has_cmat, repeat_s, repeat_t; | |
| Fixed x, y; | |
| #if USE_BILINEAR | |
| s32 incx, incy; | |
| #endif | |
| EVG_YUVType yuv_type = rctx->surf->yuv_type; | |
| u64 *data = rctx->stencil_pix_run; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| #if USE_BILINEAR | |
| Bool use_bili = (_this->filter==GF_TEXTURE_FILTER_HIGH_QUALITY) ? 1 : 0; | |
| incx = (_this->inc_x>0) ? 1 : -1; | |
| incy = (_this->inc_y>0) ? 1 : -1; | |
| #endif | |
| Bool do_mx = gf_mx2d_is_identity(_this->smat_bck) ? GF_FALSE : GF_TRUE; | |
| repeat_s = _this->mod & GF_TEXTURE_REPEAT_S; | |
| repeat_t = _this->mod & GF_TEXTURE_REPEAT_T; | |
| has_alpha = (_this->alpha != 255) ? GF_TRUE : GF_FALSE; | |
| has_cmat = _this->cmat.identity ? GF_FALSE : GF_TRUE; | |
| m_width = _this->width-1; | |
| m_height = _this->height-1; | |
| PERSP_VARS_DECL | |
| while (count) { | |
| PERSP_APPLY | |
| if (do_mx) | |
| gf_mx2d_apply_coords(&_this->smat_bck, &ix, &iy); | |
| x = m_width * ix; | |
| y = m_height * iy; | |
| x0 = FIX2INT(x); | |
| if (x0 > m_width) { | |
| if (repeat_s) { | |
| while (x0>m_width) x0 -= m_width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| x0 = m_width; | |
| } | |
| } | |
| else if (x0 < 0) { | |
| if (repeat_s) { | |
| while (x0<0) x0 += m_width; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| x0 = 0; | |
| } | |
| } | |
| y0 = FIX2INT(y); | |
| if (y0 > m_height) { | |
| if (repeat_t) { | |
| while (y0>m_height) y0 -= m_height; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| y0 = m_height; | |
| } | |
| } | |
| else if (y0 < 0) { | |
| if (repeat_t) { | |
| while (y0<0) y0 += m_height; | |
| } else if (_this->fill_pad_color_wide) { | |
| pix = _this->fill_pad_color_wide; | |
| goto write_pix; | |
| } else { | |
| y0 = 0; | |
| } | |
| } | |
| pix = _this->tx_get_pixel_wide(_this, x0, y0, rctx); | |
| /*bilinear filtering*/ | |
| #if USE_BILINEAR | |
| if (use_bili) { | |
| Bool do_lerp=GF_TRUE; | |
| u64 p00, p01, p10, p11; | |
| s32 x1, y1; | |
| u8 tx, ty; | |
| tx = FIX2INT(gf_muldiv(x, 255, m_width) ); | |
| ty = FIX2INT(gf_muldiv(y, 255, m_height) ); | |
| x1 = (x0+incx); | |
| if (x1<0) { | |
| if (!repeat_s) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (x1<0) x1 += m_width; | |
| } else { | |
| if (!repeat_s && (x1 > m_width)) | |
| do_lerp=GF_FALSE; | |
| else | |
| x1 = x1 % m_width; | |
| } | |
| y1 = (y0+incy); | |
| if (y1<0) { | |
| if (!repeat_t) | |
| do_lerp=GF_FALSE; | |
| else | |
| while (y1<0) y1 += m_height; | |
| } else { | |
| if (!repeat_t && (y1 > m_height)) | |
| do_lerp=GF_FALSE; | |
| else | |
| y1 = y1 % m_height; | |
| } | |
| if (!do_lerp) goto write_pix; | |
| if (incx>0) { | |
| if (x1<x0) tx = 255-tx; | |
| } else { | |
| if (x1>x0) tx = 255-tx; | |
| } | |
| if (incy>0) { | |
| if (y1<y0) ty = 255-ty; | |
| } else { | |
| if (y1>y0) ty = 255-ty; | |
| } | |
| p00 = pix; | |
| p01 = _this->tx_get_pixel_wide(_this, x1, y0, rctx); | |
| p10 = _this->tx_get_pixel_wide(_this, x0, y1, rctx); | |
| p11 = _this->tx_get_pixel_wide(_this, x1, y1, rctx); | |
| p00 = EVG_LERP_WIDE(p00, p01, tx); | |
| p10 = EVG_LERP_WIDE(p10, p11, tx); | |
| pix = EVG_LERP_WIDE(p00, p10, ty); | |
| } | |
| #endif | |
| write_pix: | |
| if (has_alpha) { | |
| u64 _a = (pix>>48)&0xFF; | |
| _a = (_a * _this->alpha) >> 8; | |
| _a<<=48; | |
| pix = ( (_a & 0xFFFF000000000000UL) ) | (pix & 0x0000FFFFFFFFFFFFUL); | |
| } | |
| //move pixel to target pixel format, applying color transform matrix | |
| if (_this->is_yuv) { | |
| //if surf is rgb, transform | |
| if (!yuv_type) { | |
| pix = gf_evg_ayuv_to_argb_wide(rctx->surf, pix); | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply_wide(&_this->cmat, pix); | |
| } else if (has_cmat) { | |
| //yuv->yuv , use color matrix in yuv domain | |
| //this is equivalent to gf_evg_ayuv_to_argb, gf_cmx_apply(&_this->cmat, pix), gf_evg_argb_to_ayuv | |
| pix = gf_cmx_apply_wide(&_this->yuv_cmat, pix); | |
| } | |
| } | |
| //texture is RGB | |
| else { | |
| //apply cmat | |
| if (has_cmat) | |
| pix = gf_cmx_apply_wide(&_this->cmat, pix); | |
| //dest is yuv, transform | |
| if (yuv_type) | |
| pix = gf_evg_argb_to_ayuv_wide(rctx->surf, pix); | |
| } | |
| *data++ = pix; | |
| count--; | |
| } | |
| } | |
| GF_EVGStencil *evg_texture_brush() | |
| { | |
| EVG_Texture *tmp; | |
| GF_SAFEALLOC(tmp, EVG_Texture); | |
| if (!tmp) return 0L; | |
| tmp->fill_run = tex_fill_run; | |
| tmp->type = GF_STENCIL_TEXTURE; | |
| /*default is using the surface settings*/ | |
| gf_evg_stencil_set_filter( (GF_EVGStencil *) tmp, GF_TEXTURE_FILTER_HIGH_SPEED); | |
| tmp->mod = 0; | |
| gf_cmx_init(&tmp->cmat); | |
| tmp->alpha = 255; | |
| return (GF_EVGStencil *) tmp; | |
| } | |
| u32 get_pix_argb(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(*(pix) & 0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF, *(pix+3) & 0xFF); | |
| } | |
| u32 get_pix_rgba(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(*(pix+3) & 0xFF, *(pix) & 0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF); | |
| } | |
| u32 get_pix_grba(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(*(pix+3) & 0xFF, *(pix+1) & 0xFF, *(pix) & 0xFF, *(pix+2) & 0xFF); | |
| } | |
| u32 get_pix_abgr(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(*(pix) & 0xFF, *(pix+3) & 0xFF, *(pix+2) & 0xFF, *(pix+1) & 0xFF); | |
| } | |
| u32 get_pix_bgra(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(*(pix+3) & 0xFF, *(pix+2) & 0xFF, *(pix+1) & 0xFF, *(pix) & 0xFF); | |
| } | |
| u32 get_pix_rgbx(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix) & 0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF); | |
| } | |
| u32 get_pix_xrgb(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF, *(pix+3) & 0xFF); | |
| } | |
| u32 get_pix_xbgr(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix+3) & 0xFF, *(pix+2) & 0xFF, *(pix+1) & 0xFF); | |
| } | |
| u32 get_pix_bgrx(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix+2) & 0xFF, *(pix+1) & 0xFF, *(pix) & 0xFF); | |
| } | |
| u32 get_pix_rgb_24(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *pix & 0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF); | |
| } | |
| u32 get_pix_gbr_24(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix+1) & 0xFF, *(pix+2) & 0xFF, *pix & 0xFF); | |
| } | |
| u32 get_pix_bgr_24(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| return GF_COL_ARGB(0xFF, *(pix+2) & 0xFF, * (pix+1) & 0xFF, *pix & 0xFF); | |
| } | |
| u32 get_pix_332(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 r = pix[0]>>5; | |
| u32 g = (pix[0]>>2)&0x7; | |
| u32 b = pix[0]&0x3; | |
| return GF_COL_ARGB(0xFF, (r << 5), (g << 5), (b << 6)); | |
| } | |
| u32 get_pix_444(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 r = pix[0]&0x0f; | |
| u32 g = (pix[1]>>4)&0x0f; | |
| u32 b = pix[1]&0x0f; | |
| return GF_COL_ARGB(0xFF, (r << 4), (g << 4), (b << 4)); | |
| } | |
| u32 get_pix_555(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 r = (pix[0]>>2) & 0x1f; | |
| u32 g = (pix[0])&0x3; | |
| g<<=3; | |
| g |= (pix[1]>>5) & 0x7; | |
| u32 b = pix[1] & 0x1f; | |
| return GF_COL_ARGB(0xFF, (r << 3), (g << 3), (b << 3)); | |
| } | |
| u32 get_pix_565(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 r = (pix[0]>>3) & 0x1f; | |
| u32 g = (pix[0])&0x7; | |
| g<<=3; | |
| g |= (pix[1]>>5) & 0x7; | |
| u32 b = pix[1] & 0x1f; | |
| return GF_COL_ARGB(0xFF, (r << 3), (g << 2), (b << 3)); | |
| } | |
| u32 get_pix_palette_alpha(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 val = *pix; | |
| if (val >= _this->palette_colors) return GF_COL_ARGB(0xFF, 0xFF, 0xFF, 0xFF); | |
| pix = (u8*)_this->palette + val*4; | |
| return GF_COL_ARGB(pix[_this->pidx_a], pix[_this->pidx_r], pix[_this->pidx_g], pix[_this->pidx_b]); | |
| } | |
| u32 get_pix_palette(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u32 val = *pix; | |
| if (val >= _this->palette_colors) return GF_COL_ARGB(0xFF, 0xFF, 0xFF, 0xFF); | |
| pix = (u8*)_this->palette + val*3; | |
| return GF_COL_ARGB(0xFF, pix[_this->pidx_r], pix[_this->pidx_g], pix[_this->pidx_b]); | |
| } | |
| u32 get_pix_grey(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| u8 val = *pix; | |
| return GF_COL_ARGB(0xFF, val, val, val); | |
| } | |
| u32 get_pix_alphagrey(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 a, g; | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| a = *pix; | |
| g = *(pix+1); | |
| return GF_COL_ARGB(a, g, g, g); | |
| } | |
| u32 get_pix_greyalpha(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 a, g; | |
| u8 *pix = _this->pixels + y * _this->stride + _this->Bpp*x; | |
| g = *pix; | |
| a = *(pix+1); | |
| return GF_COL_ARGB(a, g, g, g); | |
| } | |
| u32 get_pix_yuv420p(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride/2 + x/2; | |
| u8 *pV = _this->pix_v + y/2 * _this->stride/2 + x/2; | |
| return GF_COL_ARGB(0xFF, *pY, *pU, *pV); | |
| } | |
| #ifdef GPAC_BIG_ENDIAN | |
| #define GET_LE_10BIT_AS_8(_ptr) ( (((u16)(_ptr)[1])<<8 | (u16)(_ptr)[0] ) >> 2 ) | |
| #define GET_LE_10BIT_AS_16(_ptr) ( (((u16)(_ptr)[1])<<8 | (u16)(_ptr)[0] ) << 6 ) | |
| //#define GET_LE_10BIT_LEFT_AS_8(_ptr) ( (((u16)(_ptr)[1])<<8 | (u16)(_ptr)[0] ) >> 8 ) | |
| #define GET_LE_10BIT_LEFT_AS_8(_ptr) ((_ptr)[1] ) | |
| #define GET_LE_10BIT_LEFT_AS_16(_ptr) ( (((u16)(_ptr)[1])<<8 | (u16)(_ptr)[0] ) & 0xFFC0 ) | |
| #define GET_BE_10BIT_AS_8(_ptr) ( (*(u16 *)(_ptr)) >> 2 ) | |
| #define GET_BE_10BIT_AS_16(_ptr) ( (*(u16 *)(_ptr)) << 6 ) | |
| #else | |
| #define GET_LE_10BIT_AS_8(_ptr) ( (*(u16 *)(_ptr)) >> 2 ) | |
| #define GET_LE_10BIT_AS_16(_ptr) ( (*(u16 *)(_ptr)) << 6 ) | |
| #define GET_LE_10BIT_LEFT_AS_8(_ptr) ( (*(u16 *)(_ptr)) >> 8 ) | |
| #define GET_LE_10BIT_LEFT_AS_16(_ptr) ( (*(u16 *)(_ptr)) & 0xFFC0 ) | |
| #define GET_BE_10BIT_AS_8(_ptr) ( (((u16)(_ptr)[0])<<8 | (u16)(_ptr)[1] ) >> 2 ) | |
| #define GET_BE_10BIT_AS_16(_ptr) ( (((u16)(_ptr)[0])<<8 | (u16)(_ptr)[1] ) << 6 ) | |
| #endif | |
| u32 get_pix_yuv420p_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride/2 + (x/2)*2; | |
| u8 *pV = _this->pix_v + y/2 * _this->stride/2 + (x/2)*2; | |
| vy = GET_LE_10BIT_AS_8(pY); | |
| vu = GET_LE_10BIT_AS_8(pU); | |
| vv = GET_LE_10BIT_AS_8(pV); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuv420p_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride/2 + (x/2)*2; | |
| u8 *pV = _this->pix_v + y/2 * _this->stride/2 + (x/2)*2; | |
| vy = GET_LE_10BIT_AS_16(pY); | |
| vu = GET_LE_10BIT_AS_16(pU); | |
| vv = GET_LE_10BIT_AS_16(pV); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_yuv420p_a(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride/2 + x/2; | |
| u8 *pV = _this->pix_v + y/2 * _this->stride/2 + x/2; | |
| u8 *pA = _this->pix_a + y * _this->stride + x; | |
| return GF_COL_ARGB(*pA, *pY, *pU, *pV); | |
| } | |
| u32 get_pix_yuv422p(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y * _this->stride/2 + x/2; | |
| u8 *pV = _this->pix_v + y * _this->stride/2 + x/2; | |
| return GF_COL_ARGB(0xFF, *pY, *pU, *pV); | |
| } | |
| u32 get_pix_yuv422p_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y * _this->stride/2 + (x/2)*2; | |
| u8 *pV = _this->pix_v + y * _this->stride/2 + (x/2)*2; | |
| vy = GET_LE_10BIT_AS_8(pY); | |
| vu = GET_LE_10BIT_AS_8(pU); | |
| vv = GET_LE_10BIT_AS_8(pV); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuv422p_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y * _this->stride/2 + (x/2)*2; | |
| u8 *pV = _this->pix_v + y * _this->stride/2 + (x/2)*2; | |
| vy = GET_LE_10BIT_AS_16(pY); | |
| vu = GET_LE_10BIT_AS_16(pU); | |
| vv = GET_LE_10BIT_AS_16(pV); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_yuv444p(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y * _this->stride + x; | |
| u8 *pV = _this->pix_v + y * _this->stride + x; | |
| return GF_COL_ARGB(0xFF, *pY, *pU, *pV); | |
| } | |
| u32 get_pix_yuv444p_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y * _this->stride + x*2; | |
| u8 *pV = _this->pix_v + y * _this->stride + x*2; | |
| vy = GET_LE_10BIT_AS_8(pY); | |
| vu = GET_LE_10BIT_AS_8(pU); | |
| vv = GET_LE_10BIT_AS_8(pV); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuv444p_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y * _this->stride + x*2; | |
| u8 *pV = _this->pix_v + y * _this->stride + x*2; | |
| vy = GET_LE_10BIT_AS_16(pY); | |
| vu = GET_LE_10BIT_AS_16(pU); | |
| vv = GET_LE_10BIT_AS_16(pV); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_yuv444p_a(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y * _this->stride + x; | |
| u8 *pV = _this->pix_v + y * _this->stride + x; | |
| u8 *pA = _this->pix_a + y * _this->stride + x; | |
| return GF_COL_ARGB(*pA, *pY, *pU, *pV); | |
| } | |
| u32 get_pix_yuv_nv12(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*2; | |
| return GF_COL_ARGB(0xFF, *pY, *pU, *(pU+1)); | |
| } | |
| u32 get_pix_yuv_nv12_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*4; | |
| vy = GET_LE_10BIT_AS_8(pY); | |
| vu = GET_LE_10BIT_AS_8(pU); | |
| vv = GET_LE_10BIT_AS_8(pU+2); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuv_nv12_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*4; | |
| vy = GET_LE_10BIT_AS_16(pY); | |
| vu = GET_LE_10BIT_AS_16(pU); | |
| vv = GET_LE_10BIT_AS_16(pU+2); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_yuv_nv21(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + x; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*2; | |
| return GF_COL_ARGB(0xFF, *pY, *(pU+1), *pU); | |
| } | |
| u32 get_pix_yuv_nv21_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*4; | |
| vy = GET_LE_10BIT_AS_8(pY); | |
| vu = GET_LE_10BIT_AS_8(pU); | |
| vv = GET_LE_10BIT_AS_8(pU+2); | |
| return GF_COL_ARGB(0xFF, vy, vv, vu); | |
| } | |
| u64 get_pix_yuv_nv21_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u8 *pY = _this->pixels + y * _this->stride + x*2; | |
| u8 *pU = _this->pix_u + y/2 * _this->stride + (x/2)*4; | |
| vy = GET_LE_10BIT_AS_16(pY); | |
| vu = GET_LE_10BIT_AS_16(pU); | |
| vv = GET_LE_10BIT_AS_16(pU+2); | |
| return GF_COLW_ARGB(0xFFFF, vy, vv, vu); | |
| } | |
| u32 get_pix_yuyv(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + (x/2)*4; | |
| u8 u = pY[1]; | |
| u8 v = pY[3]; | |
| u8 luma = (x%2) ? pY[2] : pY[0]; | |
| return GF_COL_ARGB(0xFF, luma, u, v); | |
| } | |
| u32 get_pix_yvyu(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + (x/2)*4; | |
| u8 u = pY[3]; | |
| u8 v = pY[1]; | |
| u8 luma = (x%2) ? pY[2] : pY[0]; | |
| return GF_COL_ARGB(0xFF, luma, u, v); | |
| } | |
| u32 get_pix_uyvy(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + (x/2)*4; | |
| u8 u = pY[0]; | |
| u8 v = pY[2]; | |
| u8 luma = (x%2) ? pY[3] : pY[1]; | |
| return GF_COL_ARGB(0xFF, luma, u, v); | |
| } | |
| u32 get_pix_vyuy(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 *pY = _this->pixels + y * _this->stride + (x/2)*4; | |
| u8 u = pY[2]; | |
| u8 v = pY[0]; | |
| u8 luma = (x%2) ? pY[3] : pY[1]; | |
| return GF_COL_ARGB(0xFF, luma, u, v); | |
| } | |
| u32 get_pix_yuv444_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u32 val; | |
| u8 *p_src = _this->pixels + y * _this->stride + x*4; | |
| val = p_src[3]; val<<=8; | |
| val |= p_src[2]; val<<=8; | |
| val |= p_src[1]; val<<=8; | |
| val |= p_src[0]; | |
| vu = (u8) ( ((val>>2) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val>>12) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val>>22)) >> 2); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuv444_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u32 val; | |
| u8 *p_src = _this->pixels + y * _this->stride + x*4; | |
| val = p_src[3]; val<<=8; | |
| val |= p_src[2]; val<<=8; | |
| val |= p_src[1]; val<<=8; | |
| val |= p_src[0]; | |
| vu = (u16) ( ((val>>2) & 0x3FF) << 6); | |
| vy = (u16) ( ((val>>12) & 0x3FF) << 6); | |
| vv = (u16) ( ((val>>22)) << 6); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_v210(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| u32 val1, val2; | |
| u32 x_offset = x%6; | |
| x-=x_offset; | |
| u8 *p_src = _this->pixels + y * _this->stride + (x * 16) / 6; | |
| if (x_offset>=4) p_src += 8; | |
| else if (x_offset>=2) p_src += 4; | |
| val1 = p_src[3]; val1<<=8; | |
| val1 |= p_src[2]; val1<<=8; | |
| val1 |= p_src[1]; val1<<=8; | |
| val1 |= p_src[0]; | |
| if (x_offset==0) { | |
| vu = (u8) ( ((val1) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val1>>10) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val1>>20) & 0x3FF) >> 2); | |
| } else { | |
| val2 = p_src[7]; val2<<=8; | |
| val2 |= p_src[6]; val2<<=8; | |
| val2 |= p_src[5]; val2<<=8; | |
| val2 |= p_src[4]; | |
| if (x_offset==1) { | |
| vu = (u8) ( ((val1) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val1>>20) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val2) & 0x3FF) >> 2); | |
| } else if (x_offset==2) { | |
| vu = (u8) ( ((val1>>10) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val1>>20) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val2) & 0x3FF) >> 2); | |
| } else if (x_offset==3) { | |
| vu = (u8) ( ((val1>>10) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val2) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val2>>10) & 0x3FF) >> 2); | |
| } else if (x_offset==4) { | |
| vu = (u8) ( ((val1>>20) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val2) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val2>>10) & 0x3FF) >> 2); | |
| } else { | |
| vu = (u8) ( ((val1>>20) & 0x3FF) >> 2); | |
| vv = (u8) ( ((val2>>10) & 0x3FF) >> 2); | |
| vy = (u8) ( ((val2>>20) & 0x3FF) >> 2); | |
| } | |
| } | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_v210_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u32 val1, val2; | |
| u32 x_offset = x%6; | |
| x-=x_offset; | |
| u8 *p_src = _this->pixels + y * _this->stride + (x * 16) / 6; | |
| if (x_offset>=4) p_src += 8; | |
| else if (x_offset>=2) p_src += 4; | |
| val1 = p_src[3]; val1<<=8; | |
| val1 |= p_src[2]; val1<<=8; | |
| val1 |= p_src[1]; val1<<=8; | |
| val1 |= p_src[0]; | |
| if (x_offset==0) { | |
| vu = (u16) ( ((val1) & 0x3FF) << 6); | |
| vy = (u16) ( ((val1>>10) & 0x3FF) << 6); | |
| vv = (u16) ( ((val1>>20) & 0x3FF) << 6); | |
| } else { | |
| val2 = p_src[7]; val2<<=8; | |
| val2 |= p_src[6]; val2<<=8; | |
| val2 |= p_src[5]; val2<<=8; | |
| val2 |= p_src[4]; | |
| if (x_offset==1) { | |
| vu = (u16) ( ((val1) & 0x3FF) << 6); | |
| vv = (u16) ( ((val1>>20) & 0x3FF) << 6); | |
| vy = (u16) ( ((val2) & 0x3FF) << 6); | |
| } else if (x_offset==2) { | |
| vu = (u16) ( ((val1>>10) & 0x3FF) << 6); | |
| vy = (u16) ( ((val1>>20) & 0x3FF) << 6); | |
| vv = (u16) ( ((val2) & 0x3FF) << 6); | |
| } else if (x_offset==3) { | |
| vu = (u16) ( ((val1>>10) & 0x3FF) << 6); | |
| vv = (u16) ( ((val2) & 0x3FF) << 6); | |
| vy = (u16) ( ((val2>>10) & 0x3FF) << 6); | |
| } else if (x_offset==4) { | |
| vu = (u16) ( ((val1>>20) & 0x3FF) << 6); | |
| vy = (u16) ( ((val2) & 0x3FF) << 6); | |
| vv = (u16) ( ((val2>>10) & 0x3FF) << 6); | |
| } else { | |
| vu = (u16) ( ((val1>>20) & 0x3FF) << 6); | |
| vv = (u16) ( ((val2>>10) & 0x3FF) << 6); | |
| vy = (u16) ( ((val2>>20) & 0x3FF) << 6); | |
| } | |
| } | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u32 get_pix_yuyv_10(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u8 vy, vu, vv; | |
| Bool odd = x%2; | |
| u8 *p_src = _this->pixels + y * _this->stride + (x/2)*8; | |
| vu = GET_LE_10BIT_LEFT_AS_8(p_src + _this->off_u); | |
| if (odd) | |
| vy = GET_LE_10BIT_LEFT_AS_8(p_src + _this->off_y+4); | |
| else | |
| vy = GET_LE_10BIT_LEFT_AS_8(p_src + _this->off_y); | |
| vv = GET_LE_10BIT_LEFT_AS_8(p_src + _this->off_v); | |
| return GF_COL_ARGB(0xFF, vy, vu, vv); | |
| } | |
| u64 get_pix_yuyv_10_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *ctx) | |
| { | |
| u16 vy, vu, vv; | |
| u32 odd = x%2; | |
| u8 *p_src = _this->pixels + y * _this->stride + (x/2)*8; | |
| vu = GET_LE_10BIT_LEFT_AS_16(p_src + _this->off_u); | |
| if (odd) | |
| vy = GET_LE_10BIT_LEFT_AS_16(p_src + _this->off_y+4); | |
| else | |
| vy = GET_LE_10BIT_LEFT_AS_16(p_src + _this->off_y); | |
| vv = GET_LE_10BIT_LEFT_AS_16(p_src + _this->off_v); | |
| return GF_COLW_ARGB(0xFFFF, vy, vu, vv); | |
| } | |
| u64 default_get_pixel_wide(struct __evg_texture *_this, u32 x, u32 y, EVGRasterCtx *rctx) | |
| { | |
| return evg_col_to_wide( _this->tx_get_pixel(_this, x, y, rctx) ); | |
| } | |
| static void texture_set_callbacks(EVG_Texture *_this) | |
| { | |
| Bool swap_uv = GF_FALSE; | |
| if (_this->tx_callback) | |
| return; | |
| _this->is_wide = 0; | |
| _this->is_transparent = 0; | |
| _this->tx_get_pixel = NULL; | |
| _this->tx_get_pixel_wide = default_get_pixel_wide; | |
| switch (_this->pixel_format) { | |
| case GF_PIXEL_RGBA: | |
| _this->tx_get_pixel = get_pix_rgba; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_ARGB: | |
| _this->tx_get_pixel = get_pix_argb; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_ABGR: | |
| _this->tx_get_pixel = get_pix_abgr; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_BGRA: | |
| _this->tx_get_pixel = get_pix_bgra; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_RGBX: | |
| _this->tx_get_pixel = get_pix_rgbx; | |
| return; | |
| case GF_PIXEL_BGRX: | |
| _this->tx_get_pixel = get_pix_bgrx; | |
| return; | |
| case GF_PIXEL_XRGB: | |
| _this->tx_get_pixel = get_pix_xrgb; | |
| return; | |
| case GF_PIXEL_XBGR: | |
| _this->tx_get_pixel = get_pix_xbgr; | |
| return; | |
| case GF_PIXEL_RGB: | |
| _this->tx_get_pixel = get_pix_rgb_24; | |
| return; | |
| case GF_PIXEL_BGR: | |
| _this->tx_get_pixel = get_pix_bgr_24; | |
| return; | |
| case GF_PIXEL_RGB_444: | |
| _this->tx_get_pixel = get_pix_444; | |
| return; | |
| case GF_PIXEL_RGB_332: | |
| _this->tx_get_pixel = get_pix_332; | |
| return; | |
| case GF_PIXEL_RGB_555: | |
| _this->tx_get_pixel = get_pix_555; | |
| return; | |
| case GF_PIXEL_RGB_565: | |
| _this->tx_get_pixel = get_pix_565; | |
| return; | |
| case GF_PIXEL_GREYSCALE: | |
| if (_this->palette && _this->palette_colors) { | |
| if (_this->palette_comp==4) | |
| _this->tx_get_pixel = get_pix_palette_alpha; | |
| else | |
| _this->tx_get_pixel = get_pix_palette; | |
| } else | |
| _this->tx_get_pixel = get_pix_grey; | |
| return; | |
| case GF_PIXEL_ALPHAGREY: | |
| _this->tx_get_pixel = get_pix_alphagrey; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_GREYALPHA: | |
| _this->tx_get_pixel = get_pix_greyalpha; | |
| _this->is_transparent = 1; | |
| return; | |
| case GF_PIXEL_YUV: | |
| //we swap pU and pV at setup, use the same function | |
| case GF_PIXEL_YVU: | |
| _this->tx_get_pixel = get_pix_yuv420p; | |
| break; | |
| case GF_PIXEL_YUVA: | |
| _this->tx_get_pixel = get_pix_yuv420p_a; | |
| _this->is_transparent = 1; | |
| break; | |
| case GF_PIXEL_YUV422: | |
| _this->tx_get_pixel = get_pix_yuv422p; | |
| break; | |
| case GF_PIXEL_YUV444: | |
| _this->tx_get_pixel = get_pix_yuv444p; | |
| break; | |
| case GF_PIXEL_YUVA444: | |
| _this->tx_get_pixel = get_pix_yuv444p_a; | |
| _this->is_transparent = 1; | |
| break; | |
| case GF_PIXEL_NV12: | |
| _this->tx_get_pixel = get_pix_yuv_nv12; | |
| break; | |
| case GF_PIXEL_NV21: | |
| _this->tx_get_pixel = get_pix_yuv_nv21; | |
| break; | |
| case GF_PIXEL_YUYV: | |
| _this->tx_get_pixel = get_pix_yuyv; | |
| return; | |
| case GF_PIXEL_YVYU: | |
| _this->tx_get_pixel = get_pix_yvyu; | |
| return; | |
| case GF_PIXEL_UYVY: | |
| _this->tx_get_pixel = get_pix_uyvy; | |
| return; | |
| case GF_PIXEL_VYUY: | |
| _this->tx_get_pixel = get_pix_vyuy; | |
| return; | |
| case GF_PIXEL_YUV_10: | |
| _this->tx_get_pixel = get_pix_yuv420p_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv420p_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_YUV422_10: | |
| _this->tx_get_pixel = get_pix_yuv422p_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv422p_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_YUV444_10: | |
| _this->tx_get_pixel = get_pix_yuv444p_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv444p_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_NV12_10: | |
| _this->tx_get_pixel = get_pix_yuv_nv12_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv_nv12_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_NV21_10: | |
| _this->tx_get_pixel = get_pix_yuv_nv21_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv_nv21_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| _this->tx_get_pixel = get_pix_rgba; | |
| _this->is_transparent = 1; | |
| break; | |
| case GF_PIXEL_UYVA444_PACK: | |
| _this->tx_get_pixel = get_pix_grba; | |
| _this->is_transparent = 1; | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| _this->tx_get_pixel = get_pix_rgb_24; | |
| break; | |
| case GF_PIXEL_VYU444_PACK: | |
| _this->tx_get_pixel = get_pix_gbr_24; | |
| break; | |
| case GF_PIXEL_YUV444_10_PACK: | |
| _this->tx_get_pixel = get_pix_yuv444_10; | |
| _this->tx_get_pixel_wide = get_pix_yuv444_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_V210: | |
| _this->tx_get_pixel = get_pix_v210; | |
| _this->tx_get_pixel_wide = get_pix_v210_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_YUYV_10: | |
| _this->off_y=0; | |
| _this->off_u=2; | |
| _this->off_v=4; | |
| _this->tx_get_pixel = get_pix_yuyv_10; | |
| _this->tx_get_pixel_wide = get_pix_yuyv_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_YVYU_10: | |
| _this->off_y=0; | |
| _this->off_u=4; | |
| _this->off_v=2; | |
| _this->tx_get_pixel = get_pix_yuyv_10; | |
| _this->tx_get_pixel_wide = get_pix_yuyv_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_UYVY_10: | |
| _this->off_y=2; | |
| _this->off_u=0; | |
| _this->off_v=4; | |
| _this->tx_get_pixel = get_pix_yuyv_10; | |
| _this->tx_get_pixel_wide = get_pix_yuyv_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| case GF_PIXEL_VYUY_10: | |
| _this->off_y=2; | |
| _this->off_u=4; | |
| _this->off_v=2; | |
| _this->tx_get_pixel = get_pix_yuyv_10; | |
| _this->tx_get_pixel_wide = get_pix_yuyv_10_wide; | |
| _this->is_wide = 1; | |
| break; | |
| default: | |
| return; | |
| } | |
| //assign image planes | |
| if (_this->pix_u) return; | |
| switch (_this->pixel_format) { | |
| case GF_PIXEL_YVU: | |
| swap_uv = GF_TRUE; | |
| case GF_PIXEL_YUV_10: | |
| case GF_PIXEL_YUV: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride/2; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| _this->pix_v = _this->pix_u + _this->stride_uv * _this->height/2; | |
| if (swap_uv) { | |
| u8 *tmp = _this->pix_u; | |
| _this->pix_u = _this->pix_v; | |
| _this->pix_v = tmp; | |
| } | |
| return; | |
| case GF_PIXEL_YUVA: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride/2; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| _this->pix_v = _this->pix_u + _this->stride_uv * _this->height/2; | |
| _this->pix_a = _this->pix_v + _this->stride_uv * _this->height/2; | |
| return; | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV422: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride/2; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| _this->pix_v = _this->pix_u + _this->stride_uv * _this->height; | |
| return; | |
| case GF_PIXEL_YUV444_10: | |
| case GF_PIXEL_YUV444: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| _this->pix_v = _this->pix_u + _this->stride_uv * _this->height; | |
| return; | |
| case GF_PIXEL_YUVA444: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| _this->pix_v = _this->pix_u + _this->stride_uv * _this->height; | |
| _this->pix_a = _this->pix_v + _this->stride_uv * _this->height; | |
| return; | |
| case GF_PIXEL_NV12: | |
| case GF_PIXEL_NV21: | |
| case GF_PIXEL_NV12_10: | |
| case GF_PIXEL_NV21_10: | |
| if (!_this->stride_uv) _this->stride_uv = _this->stride; | |
| _this->pix_u = _this->pixels + _this->stride*_this->height; | |
| return; | |
| } | |
| } | |
| static GF_Err gf_evg_stencil_set_texture_internal(GF_EVGStencil * st, u32 width, u32 height, GF_PixelFormat pixelFormat, const char *pixels, u32 stride, const char *u_plane, const char *v_plane, u32 uv_stride, const char *alpha_plane, u32 alpha_stride) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) st; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) || !pixels || !width || !height || _this->owns_texture) | |
| return GF_BAD_PARAM; | |
| _this->pixels = NULL; | |
| _this->is_yuv = GF_FALSE; | |
| _this->palette = NULL; | |
| _this->palette_colors = 0; | |
| switch (pixelFormat) { | |
| case GF_PIXEL_ARGB: | |
| case GF_PIXEL_RGBA: | |
| case GF_PIXEL_ABGR: | |
| case GF_PIXEL_BGRA: | |
| case GF_PIXEL_RGBX: | |
| case GF_PIXEL_XRGB: | |
| case GF_PIXEL_XBGR: | |
| case GF_PIXEL_BGRX: | |
| _this->Bpp = 4; | |
| break; | |
| case GF_PIXEL_RGB: | |
| case GF_PIXEL_BGR: | |
| _this->Bpp = 3; | |
| break; | |
| case GF_PIXEL_RGB_332: | |
| _this->Bpp = 1; | |
| break; | |
| case GF_PIXEL_RGB_555: | |
| case GF_PIXEL_RGB_565: | |
| case GF_PIXEL_RGB_444: | |
| case GF_PIXEL_ALPHAGREY: | |
| case GF_PIXEL_GREYALPHA: | |
| _this->Bpp = 2; | |
| break; | |
| case GF_PIXEL_GREYSCALE: | |
| _this->Bpp = 1; | |
| break; | |
| case GF_PIXEL_YUV: | |
| case GF_PIXEL_YVU: | |
| case GF_PIXEL_NV12: | |
| case GF_PIXEL_NV21: | |
| case GF_PIXEL_YUV422: | |
| case GF_PIXEL_YUV444: | |
| case GF_PIXEL_YUVA: | |
| case GF_PIXEL_YUVA444: | |
| _this->is_yuv = GF_TRUE; | |
| _this->Bpp = 1; | |
| break; | |
| case GF_PIXEL_YUV_10: | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV444_10: | |
| case GF_PIXEL_NV12_10: | |
| case GF_PIXEL_NV21_10: | |
| _this->is_yuv = GF_TRUE; | |
| _this->Bpp = 2; | |
| break; | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_VYUY: | |
| _this->is_yuv = GF_TRUE; | |
| _this->Bpp = 1; | |
| if (!stride) | |
| stride = 4 * width; | |
| break; | |
| case GF_PIXEL_YUYV_10: | |
| case GF_PIXEL_YVYU_10: | |
| case GF_PIXEL_UYVY_10: | |
| case GF_PIXEL_VYUY_10: | |
| _this->is_yuv = GF_TRUE; | |
| _this->Bpp = 2; | |
| if (!stride) | |
| stride = 4 * width; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| _this->Bpp = 4; | |
| _this->is_yuv = GF_TRUE; | |
| break; | |
| case GF_PIXEL_YUV444_10_PACK: | |
| _this->Bpp = 4; | |
| _this->is_yuv = GF_TRUE; | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| _this->Bpp = 3; | |
| _this->is_yuv = GF_TRUE; | |
| break; | |
| case GF_PIXEL_V210: | |
| _this->Bpp = 2; | |
| _this->is_yuv = GF_TRUE; | |
| if (!stride) { | |
| stride = width; | |
| while (stride % 48) stride++; | |
| stride = stride * 16 / 6; //4 x 32 bits to represent 6 pixels | |
| } | |
| break; | |
| default: | |
| return GF_NOT_SUPPORTED; | |
| } | |
| if (!stride) | |
| stride = _this->Bpp * width; | |
| _this->pixel_format = pixelFormat; | |
| _this->width = width; | |
| _this->height = height; | |
| _this->stride = stride; | |
| _this->stride_uv = uv_stride; | |
| _this->stride_alpha = alpha_stride ? alpha_stride : stride; | |
| _this->pixels = (char *) pixels; | |
| _this->pix_u = (char *) u_plane; | |
| _this->pix_v = (char *) v_plane; | |
| texture_set_callbacks(_this); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_texture_planes(GF_EVGStencil *stencil, u32 width, u32 height, GF_PixelFormat pixelFormat, const u8 *y_or_rgb, u32 stride, const u8 *u_plane, const u8 *v_plane, u32 uv_stride, const u8 *alpha_plane, u32 stride_alpha) | |
| { | |
| return gf_evg_stencil_set_texture_internal(stencil, width, height, pixelFormat, y_or_rgb, stride, u_plane, v_plane, uv_stride, alpha_plane, stride_alpha); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_texture(GF_EVGStencil *stencil, u8 *pixels, u32 width, u32 height, u32 stride, GF_PixelFormat pixelFormat) | |
| { | |
| return gf_evg_stencil_set_texture_internal(stencil, width, height, pixelFormat, pixels, stride, NULL, NULL, 0, NULL, 0); | |
| } | |
| GF_EXPORT | |
| Bool gf_evg_texture_format_ok(GF_PixelFormat pixelFormat) | |
| { | |
| EVG_Texture _tx; | |
| memset(&_tx, 0, sizeof(EVG_Texture)); | |
| _tx.type = GF_STENCIL_TEXTURE; | |
| GF_Err e = gf_evg_stencil_set_texture_internal((GF_EVGStencil *) &_tx, 2, 2, pixelFormat, (const u8 *) &_tx, 0, NULL, NULL, 0, NULL, 0); | |
| if (e==GF_OK) return GF_TRUE; | |
| return GF_FALSE; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_palette(GF_EVGStencil *stencil, const u8 *palette, u32 pix_fmt, u32 nb_cols) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) stencil; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) || !palette || !nb_cols) | |
| return GF_BAD_PARAM; | |
| if (_this->pixel_format != GF_PIXEL_GREYSCALE) return GF_BAD_PARAM; | |
| _this->palette = palette; | |
| _this->palette_colors = nb_cols; | |
| _this->palette_pfmt = pix_fmt; | |
| switch (pix_fmt) { | |
| case GF_PIXEL_RGB: | |
| _this->palette_comp = 3; | |
| _this->pidx_r=0; | |
| _this->pidx_g=1; | |
| _this->pidx_b=2; | |
| break; | |
| case GF_PIXEL_BGR: | |
| _this->palette_comp = 3; | |
| _this->pidx_r=2; | |
| _this->pidx_g=1; | |
| _this->pidx_b=0; | |
| break; | |
| case GF_PIXEL_RGBA: | |
| _this->palette_comp = 4; | |
| _this->pidx_r=0; | |
| _this->pidx_g=1; | |
| _this->pidx_b=2; | |
| _this->pidx_a=3; | |
| break; | |
| case GF_PIXEL_ARGB: | |
| _this->palette_comp = 4; | |
| _this->pidx_r=1; | |
| _this->pidx_g=2; | |
| _this->pidx_b=3; | |
| _this->pidx_a=0; | |
| break; | |
| case GF_PIXEL_ABGR: | |
| _this->palette_comp = 4; | |
| _this->pidx_r=3; | |
| _this->pidx_g=2; | |
| _this->pidx_b=1; | |
| _this->pidx_a=0; | |
| break; | |
| case GF_PIXEL_BGRA: | |
| _this->palette_comp = 4; | |
| _this->pidx_r=2; | |
| _this->pidx_g=1; | |
| _this->pidx_b=0; | |
| _this->pidx_a=3; | |
| break; | |
| default: | |
| _this->palette = NULL; | |
| _this->palette_colors = 0; | |
| return GF_NOT_SUPPORTED; | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_get_texture_planes(GF_EVGStencil *stencil, u8 **pY_or_RGB, u8 **pU, u8 **pV, u8 **pA, u32 *stride, u32 *stride_uv) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) stencil; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) ) | |
| return GF_BAD_PARAM; | |
| if (pY_or_RGB) *pY_or_RGB = _this->pixels; | |
| if (pU) *pU = _this->pix_u; | |
| if (pV) *pV = _this->pix_v; | |
| if (pA) *pA = _this->pix_a; | |
| if (stride) *stride = _this->stride; | |
| if (stride_uv) *stride_uv = _this->stride_uv; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_texture_parametric(GF_EVGStencil *stencil, u32 width, u32 height, GF_PixelFormat pixelFormat, gf_evg_texture_callback callback, void *cbk_data, Bool use_screen_coords) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) stencil; | |
| u8 data=0; | |
| GF_Err e; | |
| if (!callback) return GF_BAD_PARAM; | |
| e = gf_evg_stencil_set_texture_internal(stencil, width, height, pixelFormat, &data, width, NULL, NULL, 0, NULL, 0); | |
| if (e) return e; | |
| _this->pixels = NULL; | |
| _this->tx_get_pixel = evg_paramtx_get_pixel; | |
| _this->tx_get_pixel_wide = evg_paramtx_get_pixel_wide; | |
| _this->is_wide = 1; | |
| _this->tx_callback = callback; | |
| _this->tx_callback_udta = cbk_data; | |
| _this->tx_callback_screen_coords = use_screen_coords; | |
| return GF_OK; | |
| } | |
| void evg_texture_init(GF_EVGStencil *p, GF_EVGSurface *surf) | |
| { | |
| GF_Point2D p0, p1; | |
| EVG_Texture *_this = (EVG_Texture *) p; | |
| 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->inc_x = p1.x - p0.x; | |
| _this->inc_y = p1.y - p0.y; | |
| if (surf->is_3d_matrix) { | |
| if (surf->not_8bits) { | |
| _this->fill_run = tex_fill_run_3d_wide; | |
| } else { | |
| _this->fill_run = tex_fill_run_3d; | |
| } | |
| } else if (_this->tx_callback && _this->tx_callback_screen_coords) { | |
| if (surf->not_8bits) { | |
| _this->fill_run = tex_fill_run_callback_wide; | |
| } else { | |
| _this->fill_run = tex_fill_run_callback; | |
| } | |
| } | |
| else if ((_this->filter != GF_TEXTURE_FILTER_HIGH_QUALITY) && (_this->alpha == 255) | |
| && !_this->smat.m[1] && !_this->smat.m[3] | |
| && _this->cmat.identity | |
| ) { | |
| if (surf->not_8bits) { | |
| _this->fill_run = tex_fill_run_straight_wide; | |
| } else { | |
| _this->fill_run = tex_fill_run_straight; | |
| } | |
| } else { | |
| if (!_this->cmat.identity && _this->is_yuv && surf->yuv_type) { | |
| // evg_make_ayuv_color_mx(&_this->cmat, &_this->yuv_cmat); | |
| _this->yuv_cmat = _this->cmat; | |
| } | |
| if (surf->not_8bits) { | |
| _this->fill_run = tex_fill_run_wide; | |
| } else { | |
| _this->fill_run = tex_fill_run; | |
| } | |
| } | |
| if (!_this->pad_rbg) { | |
| _this->fill_pad_color = 0; | |
| } else if (_this->is_transparent) { | |
| _this->fill_pad_color = GF_COL_ARGB(0, 0xFF, 0xFF, 0xFF); | |
| } else if (_this->is_yuv) { | |
| _this->fill_pad_color = gf_evg_argb_to_ayuv(surf, _this->pad_rbg); | |
| } else { | |
| _this->fill_pad_color = _this->pad_rbg; | |
| } | |
| _this->fill_pad_color_wide = evg_col_to_wide(_this->fill_pad_color); | |
| texture_set_callbacks(_this); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_pad_color(GF_EVGStencil * st, GF_Color pad_color) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) st; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE)) return GF_BAD_PARAM; | |
| _this->pad_rbg = pad_color; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| u32 gf_evg_stencil_get_pad_color(GF_EVGStencil * st) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) st; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE)) return 0; | |
| return _this->pad_rbg; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_mapping(GF_EVGStencil * st, GF_TextureMapFlags mode) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) st; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE)) return GF_BAD_PARAM; | |
| _this->mod = mode; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_filter(GF_EVGStencil * st, GF_TextureFilter filter_mode) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *) st; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE)) return GF_BAD_PARAM; | |
| _this->filter = filter_mode; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_color_matrix(GF_EVGStencil * st, GF_ColorMatrix *cmat) | |
| { | |
| Bool is_grad; | |
| EVG_BaseGradient *_this = (EVG_BaseGradient *)st; | |
| if (!_this) return GF_BAD_PARAM; | |
| is_grad = ((_this->type==GF_STENCIL_LINEAR_GRADIENT) || (_this->type==GF_STENCIL_RADIAL_GRADIENT)) ? GF_TRUE : GF_FALSE; | |
| if (!cmat) { | |
| if (is_grad && !_this->cmat.identity) | |
| _this->updated = 1; | |
| gf_cmx_init(&_this->cmat); | |
| } else { | |
| if (is_grad && memcmp(&_this->cmat.m, &cmat->m, sizeof(Fixed)*20)) | |
| _this->updated = 1; | |
| gf_cmx_copy(&_this->cmat, cmat); | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_get_color_matrix(GF_EVGStencil * st, GF_ColorMatrix *cmat) | |
| { | |
| EVG_BaseGradient *_this = (EVG_BaseGradient *)st; | |
| if (!_this || !cmat) return GF_BAD_PARAM; | |
| gf_cmx_copy(cmat, &_this->cmat); | |
| return GF_OK; | |
| } | |
| static u32 gf_evg_stencil_get_pixel_intern(EVG_Texture *_this, s32 x, s32 y, Bool want_yuv) | |
| { | |
| u32 col; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) || !_this->tx_get_pixel) return 0; | |
| if (x<0) x=0; | |
| else if ((u32) x>=_this->width) x = _this->width-1; | |
| if (y<0) y=0; | |
| else if ((u32) y>=_this->height) y = _this->height-1; | |
| col = _this->tx_get_pixel(_this, x, y, NULL); | |
| if (_this->is_yuv) { | |
| if (!want_yuv) return gf_evg_ayuv_to_argb(NULL, col); | |
| } else { | |
| if (want_yuv) return gf_evg_argb_to_ayuv(NULL, col); | |
| } | |
| return col; | |
| } | |
| GF_EXPORT | |
| u32 gf_evg_stencil_get_pixel(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return gf_evg_stencil_get_pixel_intern((EVG_Texture *)st, x, y, GF_FALSE); | |
| } | |
| GF_EXPORT | |
| u32 gf_evg_stencil_get_pixel_yuv(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return gf_evg_stencil_get_pixel_intern((EVG_Texture *)st, x, y, GF_TRUE); | |
| } | |
| u32 gf_evg_stencil_get_pixel_fast(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return ((EVG_Texture *)st)->tx_get_pixel((EVG_Texture *)st, x, y, NULL); | |
| } | |
| u64 gf_evg_stencil_get_pixel_wide_fast(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return ((EVG_Texture *)st)->tx_get_pixel_wide((EVG_Texture *)st, x, y, NULL); | |
| } | |
| static u64 gf_evg_stencil_get_pixel_wide_intern(EVG_Texture *_this, s32 x, s32 y, Bool want_yuv) | |
| { | |
| u64 col; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) || !_this->tx_get_pixel_wide) return 0; | |
| if (x<0) x=0; | |
| else if ((u32) x>=_this->width) x = _this->width-1; | |
| if (y<0) y=0; | |
| else if ((u32) y>=_this->height) y = _this->height-1; | |
| col = _this->tx_get_pixel_wide(_this, x, y, NULL); | |
| if (_this->is_yuv) { | |
| if (!want_yuv) return gf_evg_ayuv_to_argb_wide(NULL, col); | |
| } else { | |
| if (want_yuv) return gf_evg_argb_to_ayuv_wide(NULL, col); | |
| } | |
| return col; | |
| } | |
| GF_EXPORT | |
| u64 gf_evg_stencil_get_pixel_wide(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return gf_evg_stencil_get_pixel_wide_intern((EVG_Texture *)st, x, y, GF_FALSE); | |
| } | |
| GF_EXPORT | |
| u64 gf_evg_stencil_get_pixel_yuv_wide(GF_EVGStencil *st, s32 x, s32 y) | |
| { | |
| return gf_evg_stencil_get_pixel_intern((EVG_Texture *)st, x, y, GF_TRUE); | |
| } | |
| static GF_Vec4 gf_evg_stencil_get_pixel_f_intern(EVG_Texture *_this, Float x, Float y, Bool want_yuv) | |
| { | |
| u32 col; | |
| GF_Vec4 res; | |
| if (!_this || (_this->type != GF_STENCIL_TEXTURE) || (!_this->tx_get_pixel && !_this->tx_get_pixel_wide) ) { | |
| memset(&res, 0, sizeof(GF_Vec4)); | |
| return res; | |
| } | |
| if (_this->mod & GF_TEXTURE_FLIP_X) x = -x; | |
| if (_this->mod & GF_TEXTURE_FLIP_Y) y = -y; | |
| x*=_this->width; | |
| y*=_this->height; | |
| if (_this->mod & GF_TEXTURE_REPEAT_S) { | |
| while (x<0) x += _this->width; | |
| while (x>=_this->width) x -= _this->width; | |
| } else { | |
| if (x<0) x=0; | |
| else if (x>=_this->width) x = (Float)_this->width-1; | |
| } | |
| if (_this->mod & GF_TEXTURE_REPEAT_T) { | |
| while (y<0) y += _this->height; | |
| while (y>=_this->height) y -= _this->height; | |
| } else { | |
| if (y<0) y=0; | |
| else if (y>=_this->height) y = (Float)_this->height-1; | |
| } | |
| //10-bit or more texture, use wide and convert to float | |
| if (_this->is_wide) { | |
| u64 colw; | |
| if (_this->filter==GF_TEXTURE_FILTER_HIGH_SPEED) { | |
| colw = _this->tx_get_pixel_wide(_this, (s32) x, (s32) y, NULL); | |
| } else { | |
| u32 _x = (u32) floor(x); | |
| u32 _y = (u32) floor(y); | |
| if (_this->filter==GF_TEXTURE_FILTER_MID) { | |
| if ((x - _x > 0.5) && _x+1<_this->width) _x++; | |
| if ((y - _y > 0.5) && _y+1<_this->height) _y++; | |
| colw = _this->tx_get_pixel_wide(_this, _x, _y, NULL); | |
| } else { | |
| u64 col01, col11, col10; | |
| s32 _x1 = _x+1; | |
| s32 _y1 = _y+1; | |
| u8 diff_x = (u8) (255 * (x - _x)); | |
| u8 diff_y = (u8) (255 * (y - _y)); | |
| if ((u32)_x1>=_this->width) _x1 = _this->width-1; | |
| if ((u32)_y1>=_this->height) _y1 = _this->height-1; | |
| colw = _this->tx_get_pixel_wide(_this, _x, _y, NULL); | |
| col10 = _this->tx_get_pixel_wide(_this, _x1, _y, NULL); | |
| col01 = _this->tx_get_pixel_wide(_this, _x, _y1, NULL); | |
| col11 = _this->tx_get_pixel_wide(_this, _x1, _y1, NULL); | |
| colw = EVG_LERP_WIDE(colw, col10, diff_x); | |
| col11 = EVG_LERP_WIDE(col01, col11, diff_x); | |
| colw = EVG_LERP_WIDE(colw, col11, diff_y); | |
| } | |
| } | |
| if (_this->is_yuv) { | |
| if (!want_yuv) colw = gf_evg_ayuv_to_argb_wide(NULL, colw); | |
| } else { | |
| if (want_yuv) colw = gf_evg_argb_to_ayuv_wide(NULL, colw); | |
| } | |
| res.x = GF_COLW_R(colw); res.x /= 0xFFFF; | |
| res.y = GF_COLW_G(colw); res.y /= 0xFFFF; | |
| res.z = GF_COLW_B(colw); res.z /= 0xFFFF; | |
| res.q = GF_COLW_A(colw); res.q /= 0xFFFF; | |
| return res; | |
| } | |
| //8-bit texture, use regular and convert to float | |
| if (_this->filter==GF_TEXTURE_FILTER_HIGH_SPEED) { | |
| col = _this->tx_get_pixel(_this, (s32) x, (s32) y, NULL); | |
| } else { | |
| u32 _x = (u32) floor(x); | |
| u32 _y = (u32) floor(y); | |
| if (_this->filter==GF_TEXTURE_FILTER_MID) { | |
| if ((x - _x > 0.5) && _x+1<_this->width) _x++; | |
| if ((y - _y > 0.5) && _y+1<_this->height) _y++; | |
| col = _this->tx_get_pixel(_this, _x, _y, NULL); | |
| } else { | |
| u32 col01, col11, col10; | |
| s32 _x1 = _x+1; | |
| s32 _y1 = _y+1; | |
| u8 diff_x = (u8) (255 * (x - _x)); | |
| u8 diff_y = (u8) (255 * (y - _y)); | |
| if ((u32)_x1>=_this->width) _x1 = _this->width-1; | |
| if ((u32)_y1>=_this->height) _y1 = _this->height-1; | |
| col = _this->tx_get_pixel(_this, _x, _y, NULL); | |
| col10 = _this->tx_get_pixel(_this, _x1, _y, NULL); | |
| col01 = _this->tx_get_pixel(_this, _x, _y1, NULL); | |
| col11 = _this->tx_get_pixel(_this, _x1, _y1, NULL); | |
| col = EVG_LERP(col, col10, diff_x); | |
| col11 = EVG_LERP(col01, col11, diff_x); | |
| col = EVG_LERP(col, col11, diff_y); | |
| } | |
| } | |
| if (_this->is_yuv) { | |
| if (!want_yuv) col = gf_evg_ayuv_to_argb(NULL, col); | |
| } else { | |
| if (want_yuv) col = gf_evg_argb_to_ayuv(NULL, col); | |
| } | |
| res.x = (Float) ( GF_COL_R(col) / 255.0 ); | |
| res.y = (Float)( GF_COL_G(col) / 255.0 ); | |
| res.z = (Float)( GF_COL_B(col) / 255.0 ); | |
| res.q = (Float)( GF_COL_A(col) / 255.0 ); | |
| return res; | |
| } | |
| GF_EXPORT | |
| GF_Vec4 gf_evg_stencil_get_pixel_f(GF_EVGStencil *st, Float x, Float y) | |
| { | |
| return gf_evg_stencil_get_pixel_f_intern((EVG_Texture *)st, x, y, GF_FALSE); | |
| } | |
| GF_EXPORT | |
| GF_Vec4 gf_evg_stencil_get_pixel_yuv_f(GF_EVGStencil *st, Float x, Float y) | |
| { | |
| return gf_evg_stencil_get_pixel_f_intern((EVG_Texture *)st, x, y, GF_TRUE); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_stencil_set_alpha(GF_EVGStencil * st, u8 alpha) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *)st; | |
| if (!_this) return GF_BAD_PARAM; | |
| if (_this->type==GF_STENCIL_SOLID) { | |
| ((EVG_Brush *)st)->alpha = alpha; | |
| return GF_OK; | |
| } | |
| if (_this->type==GF_STENCIL_TEXTURE) | |
| _this->alpha = alpha; | |
| else { | |
| if ( ((EVG_BaseGradient*)st)->alpha != alpha) { | |
| ((EVG_BaseGradient*)st)->updated = 1; | |
| } | |
| ((EVG_BaseGradient*)st)->alpha = alpha; | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| u8 gf_evg_stencil_get_alpha(GF_EVGStencil * st) | |
| { | |
| EVG_Texture *_this = (EVG_Texture *)st; | |
| if (!_this) return 0; | |
| if (_this->type==GF_STENCIL_SOLID) { | |
| return ((EVG_Brush *)st)->alpha; | |
| } | |
| if (_this->type==GF_STENCIL_TEXTURE) | |
| return _this->alpha; | |
| return ((EVG_BaseGradient*)st)->alpha; | |
| } | |
| void *evg_fill_run(GF_EVGStencil *p, EVGRasterCtx *rctx, EVG_Span *span, s32 y) | |
| { | |
| if (rctx->surf->direct_yuv_3d) { | |
| u32 *src = rctx->stencil_pix_run; | |
| return src + span->x; | |
| } | |
| if (rctx->surf->is_shader) { | |
| rctx->frag_param.coverage = span->coverage; | |
| rctx->frag_param.odd_flag = span->odd_flag; | |
| rctx->frag_param.screen_x = (Float) span->x; | |
| rctx->frag_param.screen_y = (Float) y; | |
| } | |
| if (rctx->surf->odd_fill) { | |
| if (!span->odd_flag && rctx->surf->sten2) { | |
| rctx->surf->sten2->fill_run(rctx->surf->sten2, rctx, span->x, y, span->len); | |
| } else { | |
| p->fill_run(p, rctx, span->x, y, span->len); | |
| } | |
| return rctx->stencil_pix_run; | |
| } | |
| if (p) | |
| p->fill_run(p, rctx, span->x, y, span->len); | |
| if (rctx->surf->update_run) { | |
| void *bck = rctx->stencil_pix_run; | |
| if (rctx->surf->sten2) { | |
| rctx->stencil_pix_run = rctx->stencil_pix_run2; | |
| rctx->surf->sten2->fill_run(rctx->surf->sten2, rctx, span->x, y, span->len); | |
| } | |
| if (rctx->surf->sten3) { | |
| rctx->stencil_pix_run = rctx->stencil_pix_run3; | |
| rctx->surf->sten3->fill_run(rctx->surf->sten3, rctx, span->x, y, span->len); | |
| } | |
| rctx->stencil_pix_run = bck; | |
| rctx->surf->update_run(rctx, span->len); | |
| return rctx->stencil_pix_run; | |
| } | |
| if (rctx->surf->get_alpha) { | |
| u32 i; | |
| GF_EVGSurface *surf = rctx->surf; | |
| EVG_Texture *_p = (EVG_Texture *)p; | |
| if (_p->Bpp>8) { | |
| u64 *coll = (u64 *)rctx->stencil_pix_run; | |
| for (i=0; i<span->len; i++) { | |
| u64 a = (*coll>>48)&0xFFFF; | |
| a = 0xFF * surf->get_alpha(surf->get_alpha_udta, (u8) (a/0xFF), span->x+i, y); | |
| *coll = (a<<48) | ((*coll) & 0x0000FFFFFFFFFFFFUL); | |
| coll ++; | |
| } | |
| } else { | |
| u32 *col = (u32 *)rctx->stencil_pix_run; | |
| for (i=0; i<span->len; i++) { | |
| u32 a = GF_COL_A(*col); | |
| a = surf->get_alpha(surf->get_alpha_udta, a, span->len+i, y); | |
| *col = (a<<24) | ((*col) & 0x00FFFFFF); | |
| col ++; | |
| } | |
| } | |
| } | |
| return rctx->stencil_pix_run; | |
| } | |
| void *evg_fill_run_mask(GF_EVGStencil *p, EVGRasterCtx *rctx, EVG_Span *span, s32 y) | |
| { | |
| void *res = evg_fill_run(p, rctx, span, y); | |
| u8 *mask = rctx->surf->internal_mask + y*rctx->surf->width + span->x; | |
| u32 i; | |
| if (rctx->surf->not_8bits) { | |
| u64 *wcols = res; | |
| for (i=0; i<span->len; i++) { | |
| *wcols = (*wcols & 0x0000FFFFFFFFFFFFUL) | (((u64) *mask)*256)<<48; | |
| wcols++; | |
| mask++; | |
| } | |
| } else { | |
| u32 * cols = res; | |
| for (i=0; i<span->len; i++) { | |
| *cols = (*cols & 0x00FFFFFF) | ((u32)*mask)<<24; | |
| cols++; | |
| mask++; | |
| } | |
| } | |
| return res; | |
| } | |
| void *evg_fill_run_mask_inv(GF_EVGStencil *p, EVGRasterCtx *rctx, EVG_Span *span, s32 y) | |
| { | |
| void *res = evg_fill_run(p, rctx, span, y); | |
| u8 *mask = rctx->surf->internal_mask + y*rctx->surf->width + span->x; | |
| u32 i; | |
| if (rctx->surf->not_8bits) { | |
| u64 *wcols = res; | |
| for (i=0; i<span->len; i++) { | |
| *wcols = (*wcols & 0x0000FFFFFFFFFFFFUL) | (((u64) (0xFF- *mask))*256)<<48; | |
| wcols++; | |
| mask++; | |
| } | |
| } else { | |
| u32 * cols = res; | |
| for (i=0; i<span->len; i++) { | |
| *cols = (*cols & 0x00FFFFFF) | ((u32) (0xFF- *mask) )<<24; | |
| cols++; | |
| mask++; | |
| } | |
| } | |
| return res; | |
| } | |
| void evg_fill_span_mask(int y, int count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx) | |
| { | |
| EVG_Span aspan, *ospan; | |
| int i; | |
| aspan.idx1 = aspan.idx2 = 0; | |
| //disable yuv flush for 420 and 422 | |
| rctx->no_yuv_flush = 1; | |
| for (i=0; i<count; i++) { | |
| u32 len, o_x; | |
| ospan = &spans[i]; | |
| o_x = ospan->x; | |
| len = ospan->len; | |
| aspan.len = 0; | |
| u8 *mask = surf->internal_mask + surf->width * y + o_x; | |
| while (len) { | |
| u32 mv = *mask; | |
| if (mv) { | |
| if (!aspan.len) { | |
| aspan.x = o_x; | |
| aspan.coverage = ospan->coverage; | |
| aspan.odd_flag = ospan->odd_flag; | |
| } | |
| aspan.len++; | |
| if (mv == 0xFF) | |
| *mask = 0xFF - aspan.coverage; | |
| else { | |
| *mask = 0; | |
| aspan.coverage = 0xFF; | |
| } | |
| } else if (aspan.len) { | |
| surf->fill_spans(y, 1, &aspan, surf, rctx); | |
| aspan.len = 0; | |
| } | |
| mask++; | |
| o_x++; | |
| len--; | |
| } | |
| //flush | |
| if (aspan.len) { | |
| //last span, enable yuv flush for 420 and 422 | |
| //we can do it now because we know we get called only once per y for YUV 420/422 | |
| if (i+1==count) | |
| rctx->no_yuv_flush = 0; | |
| surf->fill_spans(y, 1, &aspan, surf, rctx); | |
| } | |
| } | |
| } | |
| #define mix_run_func(_type, _val, _shift, _R, _G, _B, _ARGB) \ | |
| u32 r1, g1, b1, r2, g2, b2; \ | |
| u32 mix = rctx->surf->mix_val; \ | |
| u32 imix = _val - mix; \ | |
| u32 i=0; \ | |
| _type col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2; \ | |
| if (!mix) return; \ | |
| if (!imix) return;\ | |
| \ | |
| while (i<count) { \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| r1 = _R(col1); \ | |
| g1 = _G(col1); \ | |
| b1 = _B(col1); \ | |
| r2 = _R(col2); \ | |
| g2 = _G(col2); \ | |
| b2 = _B(col2); \ | |
| r1 = (r1 * imix + r2 * mix) >> _shift; \ | |
| g1 = (g1 * imix + g2 * mix) >> _shift; \ | |
| b1 = (b1 * imix + b2 * mix) >> _shift; \ | |
| col1p[i] = _ARGB(_val, r1, g1, b1); \ | |
| i++; \ | |
| } \ | |
| static void mix_run(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_run_func(u32, 0xFF, 8, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_run_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_run_func(u64, 0xFFFF, 16, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| #define mixa_run_func(_type, _val, _shift, _A, _R, _G, _B, _ARGB) \ | |
| u32 a1, r1, g1, b1, a2, r2, g2, b2; \ | |
| u32 mix = rctx->surf->mix_val; \ | |
| u32 imix = _val - mix; \ | |
| u32 i=0; \ | |
| _type col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2; \ | |
| if (!mix) return; \ | |
| if (!imix) return; \ | |
| \ | |
| while (i<count) { \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| a1 = _A(col1); \ | |
| r1 = _R(col1); \ | |
| g1 = _G(col1); \ | |
| b1 = _B(col1); \ | |
| a2 = _A(col2); \ | |
| r2 = _R(col2); \ | |
| g2 = _G(col2); \ | |
| b2 = _B(col2); \ | |
| a1 = (a1 * imix + a2 * mix) >> _shift; \ | |
| r1 = (r1 * imix + r2 * mix) >> _shift; \ | |
| g1 = (g1 * imix + g2 * mix) >> _shift; \ | |
| b1 = (b1 * imix + b2 * mix) >> _shift; \ | |
| col1p[i] = _ARGB(a1, r1, g1, b1); \ | |
| i++; \ | |
| } \ | |
| static void mixa_run(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mixa_run_func(u32, 0xFF, 8, GF_COL_A, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mixa_run_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mixa_run_func(u64, 0xFFFF, 16, GF_COLW_A, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| #define repa_run_func(_type, _shift, _mask, _A) \ | |
| u32 i=0; \ | |
| _type a2, col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2; \ | |
| \ | |
| while (i<count) { \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| a2 = _A(col2);\ | |
| col1p[i] = (a2<<_shift) | (col1 & _mask);\ | |
| i++; \ | |
| } \ | |
| static void replace_alpha_run_a(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u32, 24, 0x00FFFFFF, GF_COL_A) | |
| } | |
| static void replace_alpha_run_a_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u64, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_A) | |
| } | |
| static void replace_alpha_run_r(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u32, 24, 0x00FFFFFF, GF_COL_R) | |
| } | |
| static void replace_alpha_run_r_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u64, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_R) | |
| } | |
| static void replace_alpha_run_g(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u32, 24, 0x00FFFFFF, GF_COL_G) | |
| } | |
| static void replace_alpha_run_g_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u64, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_G) | |
| } | |
| static void replace_alpha_run_b(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u32, 24, 0x00FFFFFF, GF_COL_B) | |
| } | |
| static void replace_alpha_run_b_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_run_func(u64, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_B) | |
| } | |
| #define repa_m1_run_func(_type, _val, _shift, _mask, _A) \ | |
| u32 i=0; \ | |
| _type a2, col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2; \ | |
| \ | |
| while (i<count) { \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| a2 = _val - _A(col2);\ | |
| col1p[i] = (a2<<_shift) | (col1 & _mask);\ | |
| i++; \ | |
| } \ | |
| static void replace_alpha_m1_run_a(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u32, 0xFF, 24, 0x00FFFFFF, GF_COL_A) | |
| } | |
| static void replace_alpha_m1_run_a_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u64, 0xFFFF, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_A) | |
| } | |
| static void replace_alpha_m1_run_r(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u32, 0xFF, 24, 0x00FFFFFF, GF_COL_R) | |
| } | |
| static void replace_alpha_m1_run_r_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u64, 0xFFFF, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_R) | |
| } | |
| static void replace_alpha_m1_run_g(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u32, 0xFF, 24, 0x00FFFFFF, GF_COL_G) | |
| } | |
| static void replace_alpha_m1_run_g_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u64, 0xFFFF, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_G) | |
| } | |
| static void replace_alpha_m1_run_b(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u32, 0xFF, 24, 0x00FFFFFF, GF_COL_B) | |
| } | |
| static void replace_alpha_m1_run_b_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| repa_m1_run_func(u64, 0xFFFF, 56, 0x0000FFFFFFFFFFFFUL, GF_COLW_B) | |
| } | |
| #define mix_dyn_run_func(_type, _val, _shift, _A, _R, _G, _B, _ARGB) \ | |
| u32 r1, g1, b1, r2, g2, b2; \ | |
| u32 i=0; \ | |
| _type col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2, *col3p = rctx->stencil_pix_run3; \ | |
| \ | |
| while (i<count) { \ | |
| u32 mix = _A(col3p[i]); \ | |
| u32 imix = _val - mix; \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| r1 = _R(col1); \ | |
| g1 = _G(col1); \ | |
| b1 = _B(col1); \ | |
| r2 = _R(col2); \ | |
| g2 = _G(col2); \ | |
| b2 = _B(col2); \ | |
| r1 = (r1 * imix + r2 * mix) >> _shift; \ | |
| g1 = (g1 * imix + g2 * mix) >> _shift; \ | |
| b1 = (b1 * imix + b2 * mix) >> _shift; \ | |
| col1p[i] = _ARGB(_val, r1, g1, b1); \ | |
| i++; \ | |
| } \ | |
| static void mix_dyn_run_a(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u32, 0xFF, 8, GF_COL_A, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyn_run_a_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u64, 0xFFFF, 16, GF_COLW_A, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyn_run_r(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u32, 0xFF, 8, GF_COL_R, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyn_run_r_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u64, 0xFFFF, 16, GF_COLW_R, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyn_run_g(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u32, 0xFF, 8, GF_COL_G, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyn_run_g_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u64, 0xFFFF, 16, GF_COLW_G, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyn_run_b(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u32, 0xFF, 8, GF_COL_B, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyn_run_b_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyn_run_func(u64, 0xFFFF, 16, GF_COLW_B, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| #define mix_dyna_run_func(_type, _val, _shift, _A, _R, _G, _B, _ARGB) \ | |
| u32 a1, r1, g1, b1, a2, r2, g2, b2; \ | |
| u32 i=0; \ | |
| _type col1, col2, *col1p = rctx->stencil_pix_run, *col2p = rctx->stencil_pix_run2, *col3p = rctx->stencil_pix_run3; \ | |
| \ | |
| while (i<count) { \ | |
| u32 mix = _A(col3p[i]); \ | |
| u32 imix = _val - mix; \ | |
| col1 = col1p[i]; \ | |
| col2 = col2p[i]; \ | |
| a1 = _A(col1); \ | |
| r1 = _R(col1); \ | |
| g1 = _G(col1); \ | |
| b1 = _B(col1); \ | |
| a2 = _A(col2); \ | |
| r2 = _R(col2); \ | |
| g2 = _G(col2); \ | |
| b2 = _B(col2); \ | |
| a1 = (a1 * imix + a2 * mix) >> _shift; \ | |
| r1 = (r1 * imix + r2 * mix) >> _shift; \ | |
| g1 = (g1 * imix + g2 * mix) >> _shift; \ | |
| b1 = (b1 * imix + b2 * mix) >> _shift; \ | |
| col1p[i] = _ARGB(a1, r1, g1, b1); \ | |
| i++; \ | |
| } \ | |
| static void mix_dyna_run_a(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u32, 0xFF, 8, GF_COL_A, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyna_run_a_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u64, 0xFFFF, 16, GF_COLW_A, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyna_run_r(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u32, 0xFF, 8, GF_COL_R, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyna_run_r_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u64, 0xFFFF, 16, GF_COLW_R, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyna_run_g(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u32, 0xFF, 8, GF_COL_G, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyna_run_g_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u64, 0xFFFF, 16, GF_COLW_G, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| static void mix_dyna_run_b(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u32, 0xFF, 8, GF_COL_B, GF_COL_R, GF_COL_G, GF_COL_B, GF_COL_ARGB) | |
| } | |
| static void mix_dyna_run_b_wide(EVGRasterCtx *rctx, u32 count) | |
| { | |
| mix_dyna_run_func(u64, 0xFFFF, 16, GF_COLW_B, GF_COLW_R, GF_COLW_G, GF_COLW_B, GF_COLW_ARGB) | |
| } | |
| GF_Err gf_evg_setup_multi_texture(GF_EVGSurface *surf, GF_EVGMultiTextureMode operand, GF_EVGStencil *sten2, GF_EVGStencil *sten3, Float *params) | |
| { | |
| Float param1 = params ? params[0] : 0; | |
| surf->sten2 = surf->sten3 = NULL; | |
| surf->odd_fill = 0; | |
| switch (operand) { | |
| case GF_EVG_OPERAND_MIX: | |
| if (!sten2 || !params) return GF_BAD_PARAM; | |
| surf->sten2 = sten2; | |
| if (surf->not_8bits) { | |
| surf->mix_val = (u32) (params[0] * 0xFFFF); | |
| surf->update_run = mix_run_wide; | |
| if (!surf->mix_val) surf->sten2 = NULL; | |
| else if (surf->mix_val==0xFFFF) { | |
| surf->sten2 = NULL; | |
| surf->sten = sten2; | |
| } | |
| } else { | |
| surf->mix_val = (u32) (params[0] * 255); | |
| surf->update_run = mix_run; | |
| if (!surf->mix_val) surf->sten2 = NULL; | |
| else if (surf->mix_val==0xFF) { | |
| surf->sten2 = NULL; | |
| surf->sten = sten2; | |
| } | |
| } | |
| break; | |
| case GF_EVG_OPERAND_MIX_ALPHA: | |
| if (!sten2 || !params) return GF_BAD_PARAM; | |
| surf->sten2 = sten2; | |
| if (surf->not_8bits) { | |
| surf->mix_val = (u32) (params[0] * 0xFFFF); | |
| surf->update_run = mixa_run_wide; | |
| if (!surf->mix_val) surf->sten2 = NULL; | |
| else if (surf->mix_val==0xFFFF) { | |
| surf->sten2 = NULL; | |
| surf->sten = sten2; | |
| } | |
| } else { | |
| surf->mix_val = (u32) (params[0] * 255); | |
| surf->update_run = mixa_run; | |
| if (!surf->mix_val) surf->sten2 = NULL; | |
| else if (surf->mix_val==0xFF) { | |
| surf->sten2 = NULL; | |
| surf->sten = sten2; | |
| } | |
| } | |
| break; | |
| case GF_EVG_OPERAND_REPLACE_ALPHA: | |
| if (!sten2) return GF_BAD_PARAM; | |
| if (param1>=3) | |
| surf->update_run = surf->not_8bits ? replace_alpha_run_b_wide : replace_alpha_run_b; | |
| else if (param1>=2) | |
| surf->update_run = surf->not_8bits ? replace_alpha_run_g_wide : replace_alpha_run_g; | |
| else if (param1>=1) | |
| surf->update_run = surf->not_8bits ? replace_alpha_run_r_wide : replace_alpha_run_r; | |
| else | |
| surf->update_run = surf->not_8bits ? replace_alpha_run_a_wide : replace_alpha_run_a; | |
| surf->sten2 = sten2; | |
| break; | |
| case GF_EVG_OPERAND_REPLACE_ONE_MINUS_ALPHA: | |
| if (!sten2) return GF_BAD_PARAM; | |
| if (param1>=3) | |
| surf->update_run = surf->not_8bits ? replace_alpha_m1_run_b_wide : replace_alpha_m1_run_b; | |
| else if (param1>=2) | |
| surf->update_run = surf->not_8bits ? replace_alpha_m1_run_g_wide : replace_alpha_m1_run_g; | |
| else if (param1>=1) | |
| surf->update_run = surf->not_8bits ? replace_alpha_m1_run_r_wide : replace_alpha_m1_run_r; | |
| else | |
| surf->update_run = surf->not_8bits ? replace_alpha_m1_run_a_wide : replace_alpha_m1_run_a; | |
| surf->sten2 = sten2; | |
| break; | |
| case GF_EVG_OPERAND_MIX_DYN: | |
| if (!sten2 || !sten3) return GF_BAD_PARAM; | |
| if (param1>=3) | |
| surf->update_run = surf->not_8bits ? mix_dyn_run_b_wide : mix_dyn_run_b; | |
| else if (param1>=2) | |
| surf->update_run = surf->not_8bits ? mix_dyn_run_g_wide : mix_dyn_run_g; | |
| else if (param1>=1) | |
| surf->update_run = surf->not_8bits ? mix_dyn_run_r_wide : mix_dyn_run_r; | |
| else | |
| surf->update_run = surf->not_8bits ? mix_dyn_run_a_wide : mix_dyn_run_a; | |
| surf->sten2 = sten2; | |
| surf->sten3 = sten3; | |
| break; | |
| case GF_EVG_OPERAND_MIX_DYN_ALPHA: | |
| if (!sten2 || !sten3 || !params) return GF_BAD_PARAM; | |
| if (param1>=3) | |
| surf->update_run = surf->not_8bits ? mix_dyna_run_b_wide : mix_dyna_run_b; | |
| else if (param1>=2) | |
| surf->update_run = surf->not_8bits ? mix_dyna_run_g_wide : mix_dyna_run_g; | |
| else if (param1>=1) | |
| surf->update_run = surf->not_8bits ? mix_dyna_run_r_wide : mix_dyna_run_r; | |
| else | |
| surf->update_run = surf->not_8bits ? mix_dyna_run_a_wide : mix_dyna_run_a; | |
| surf->sten2 = sten2; | |
| surf->sten3 = sten3; | |
| break; | |
| case GF_EVG_OPERAND_ODD_FILL: | |
| if (!sten2) return GF_BAD_PARAM; | |
| surf->sten2 = sten2; | |
| surf->odd_fill = 1; | |
| break; | |
| default: | |
| return GF_BAD_PARAM; | |
| } | |
| surf->run_size = sizeof(u32) * (surf->width+2); | |
| if (surf->not_8bits) surf->run_size *= 2; | |
| if (surf->sten2 && !surf->raster_ctx.stencil_pix_run2) { | |
| surf->raster_ctx.stencil_pix_run2 = gf_malloc(sizeof(u8) * surf->run_size); | |
| if (!surf->raster_ctx.stencil_pix_run2) return GF_OUT_OF_MEM; | |
| } | |
| if (surf->sten3 && !surf->raster_ctx.stencil_pix_run3) { | |
| surf->raster_ctx.stencil_pix_run3 = gf_malloc(sizeof(u8) * surf->run_size); | |
| if (!surf->raster_ctx.stencil_pix_run3) return GF_OUT_OF_MEM; | |
| } | |
| #ifndef GPAC_DISABLE_THREADS | |
| u32 i; | |
| for (i=0; i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| if (surf->sten2 && !rctx->stencil_pix_run2) { | |
| rctx->stencil_pix_run2 = gf_malloc(sizeof(u8) * surf->run_size); | |
| if (!rctx->stencil_pix_run2) return GF_OUT_OF_MEM; | |
| } | |
| if (surf->sten3 && !rctx->stencil_pix_run3) { | |
| rctx->stencil_pix_run3 = gf_malloc(sizeof(u8) * surf->run_size); | |
| if (!rctx->stencil_pix_run3) return GF_OUT_OF_MEM; | |
| } | |
| } | |
| #endif | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_EVG |