| /* | |
| * 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 void get_surface_world_matrix(GF_EVGSurface *surf, GF_Matrix2D *mat) | |
| { | |
| gf_mx2d_init(*mat); | |
| if (surf->center_coords) { | |
| gf_mx2d_add_scale(mat, FIX_ONE, -FIX_ONE); | |
| gf_mx2d_add_translation(mat, INT2FIX(surf->width / 2), INT2FIX(surf->height / 2)); | |
| } | |
| } | |
| static GF_Err evg_raster_ctx_init(EVGRasterCtx *raster_ctx, GF_EVGSurface *surf) | |
| { | |
| raster_ctx->max_gray_spans = raster_ctx->alloc_gray_spans = FT_MAX_GRAY_SPANS; | |
| raster_ctx->gray_spans = gf_malloc(sizeof(EVG_Span)* raster_ctx->max_gray_spans); | |
| if (!raster_ctx->gray_spans) return GF_OUT_OF_MEM; | |
| raster_ctx->surf = surf; | |
| return GF_OK; | |
| } | |
| static void evg_raster_ctx_uninit(EVGRasterCtx *raster_ctx) | |
| { | |
| if (raster_ctx->gray_spans) gf_free(raster_ctx->gray_spans); | |
| if (raster_ctx->stencil_pix_run) gf_free(raster_ctx->stencil_pix_run); | |
| if (raster_ctx->stencil_pix_run2) gf_free(raster_ctx->stencil_pix_run2); | |
| if (raster_ctx->stencil_pix_run3) gf_free(raster_ctx->stencil_pix_run3); | |
| if (raster_ctx->uv_alpha) gf_free(raster_ctx->uv_alpha); | |
| } | |
| GF_EXPORT | |
| GF_EVGSurface *gf_evg_surface_new(Bool center_coords) | |
| { | |
| GF_Err e; | |
| GF_EVGSurface *surf; | |
| GF_SAFEALLOC(surf, GF_EVGSurface); | |
| if (!surf) return NULL; | |
| surf->center_coords = center_coords; | |
| surf->qlevel = GF_RASTER_HIGH_QUALITY; | |
| surf->yuv_prof = 1; | |
| e = evg_raster_ctx_init(&surf->raster_ctx, surf); | |
| if (e) { | |
| gf_free(surf); | |
| return NULL; | |
| } | |
| return surf; | |
| } | |
| EVG_Surface3DExt *evg_init_3d_surface(GF_EVGSurface *surf); | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_enable_3d(GF_EVGSurface *surf) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| if (surf->ext3d) return GF_OK; | |
| surf->ext3d = evg_init_3d_surface(surf); | |
| if (!surf->ext3d) return GF_OUT_OF_MEM; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_enable_threading(GF_EVGSurface *surf, s32 nb_threads) | |
| { | |
| #ifndef GPAC_DISABLE_THREADS | |
| u32 i, run_size; | |
| char szName[100]; | |
| if (!surf) return GF_BAD_PARAM; | |
| if (surf->nb_threads) return GF_OK; | |
| if (gf_opts_get_bool("core", "no-mx")) return GF_OK; | |
| if (nb_threads<0) { | |
| GF_SystemRTInfo rti; | |
| gf_sys_get_rti(0, &rti, 0); | |
| if (rti.nb_cores<2) return GF_IO_ERR; | |
| nb_threads = rti.nb_cores-1; | |
| } | |
| surf->nb_threads = (u32) nb_threads; | |
| if (!surf->nb_threads) return GF_OK; | |
| surf->th_raster_ctx = gf_malloc(sizeof(EVGRasterCtx) * surf->nb_threads); | |
| sprintf(szName, "EVGMX%p", surf); | |
| surf->raster_mutex = gf_mx_new(szName); | |
| if (!surf->th_raster_ctx || !surf->raster_mutex) { | |
| surf->nb_threads = 0; | |
| return GF_OUT_OF_MEM; | |
| } | |
| run_size = surf->width ? (sizeof(u32) * (surf->width+2)) : 0; | |
| if (surf->width && surf->not_8bits) run_size *= 2; | |
| memset(surf->th_raster_ctx, 0, sizeof(EVGRasterCtx) * surf->nb_threads); | |
| for (i=0; i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| sprintf(szName, "gf_evg_%d", i+1); | |
| rctx->th = gf_th_new(szName); | |
| if (!rctx->th) { | |
| surf->nb_threads = i; | |
| break; | |
| } | |
| rctx->surf = surf; | |
| rctx->max_gray_spans = rctx->alloc_gray_spans = FT_MAX_GRAY_SPANS; | |
| rctx->gray_spans = gf_malloc(sizeof(EVG_Span) * rctx->max_gray_spans); | |
| if (run_size) { | |
| rctx->stencil_pix_run = gf_realloc(rctx->stencil_pix_run, run_size); | |
| } | |
| if (!rctx->gray_spans || !rctx->stencil_pix_run) { | |
| surf->nb_threads = i; | |
| break; | |
| } | |
| rctx->th_state = 1; | |
| } | |
| surf->raster_sem = gf_sema_new(surf->nb_threads, 0); | |
| if (!surf->raster_sem) | |
| surf->nb_threads = 0; | |
| //launch all threads | |
| for (i=0; i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| gf_th_run(rctx->th, th_sweep_lines, rctx); | |
| } | |
| #endif //GPAC_DISABLE_THREADS | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| void gf_evg_surface_set_center_coords(GF_EVGSurface *surf, Bool center_coords) | |
| { | |
| if (surf) surf->center_coords = center_coords; | |
| } | |
| GF_EXPORT | |
| void gf_evg_surface_delete(GF_EVGSurface *surf) | |
| { | |
| u32 i; | |
| if (!surf) | |
| return; | |
| for (i=0; i<surf->max_lines; i++) { | |
| gf_free(surf->scanlines[i].cells); | |
| if (surf->scanlines[i].pixels) | |
| gf_free(surf->scanlines[i].pixels); | |
| } | |
| gf_free(surf->scanlines); | |
| if (surf->internal_mask) gf_free(surf->internal_mask); | |
| evg_raster_ctx_uninit(&surf->raster_ctx); | |
| if (surf->ext3d) { | |
| gf_free(surf->ext3d); | |
| } | |
| #ifndef GPAC_DISABLE_THREADS | |
| if (surf->nb_threads) { | |
| for (i=0; i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| rctx->th_state = 0; | |
| } | |
| gf_sema_notify(surf->raster_sem, surf->nb_threads); | |
| for (i=0; i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| //wait for destruction | |
| while (!rctx->th_state) { | |
| gf_sleep(0); | |
| } | |
| gf_th_del(surf->th_raster_ctx[i].th); | |
| evg_raster_ctx_uninit(&surf->th_raster_ctx[i]); | |
| } | |
| gf_free(surf->th_raster_ctx); | |
| gf_mx_del(surf->raster_mutex); | |
| gf_sema_del(surf->raster_sem); | |
| } | |
| #endif | |
| gf_free(surf); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_set_matrix(GF_EVGSurface *surf, GF_Matrix2D *mat) | |
| { | |
| GF_Matrix2D tmp; | |
| if (!surf) return GF_BAD_PARAM; | |
| get_surface_world_matrix(surf, &surf->mat); | |
| surf->is_3d_matrix = GF_FALSE; | |
| if (!mat) { | |
| gf_mx2d_init(surf->shader_mx); | |
| return GF_OK; | |
| } | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_add_matrix(&tmp, &surf->mat); | |
| gf_mx2d_copy(surf->mat, tmp); | |
| gf_mx2d_copy(surf->shader_mx, *mat); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_set_matrix_3d(GF_EVGSurface *surf, GF_Matrix *mat) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| get_surface_world_matrix(surf, &surf->mat); | |
| surf->is_3d_matrix = GF_FALSE; | |
| if (!mat) return GF_OK; | |
| gf_mx_copy(surf->mx3d, *mat); | |
| surf->is_3d_matrix = GF_TRUE; | |
| return GF_OK; | |
| } | |
| static void evg_surface_set_components_idx(GF_EVGSurface *surf) | |
| { | |
| surf->idx_y1=surf->idx_u=surf->idx_v=0; | |
| surf->idx_a=surf->idx_r=surf->idx_g=surf->idx_b=0; | |
| switch (surf->pixelFormat) { | |
| case GF_PIXEL_YUYV: | |
| surf->idx_y1=0; | |
| surf->idx_u=1; | |
| surf->idx_v=3; | |
| break; | |
| case GF_PIXEL_YVYU: | |
| surf->idx_y1=0; | |
| surf->idx_u=3; | |
| surf->idx_v=1; | |
| break; | |
| case GF_PIXEL_UYVY: | |
| surf->idx_y1=1; | |
| surf->idx_u=0; | |
| surf->idx_v=2; | |
| break; | |
| case GF_PIXEL_VYUY: | |
| surf->idx_y1=1; | |
| surf->idx_u=2; | |
| surf->idx_v=0; | |
| break; | |
| case GF_PIXEL_ALPHAGREY: | |
| surf->idx_a = 0; | |
| surf->idx_g = 1; | |
| break; | |
| case GF_PIXEL_GREYALPHA: | |
| surf->idx_a = 1; | |
| surf->idx_g = 0; | |
| break; | |
| case GF_PIXEL_ARGB: | |
| surf->idx_a=0; | |
| surf->idx_r=1; | |
| surf->idx_g=2; | |
| surf->idx_b=3; | |
| break; | |
| case GF_PIXEL_RGBA: | |
| case GF_PIXEL_YUVA444_PACK: | |
| surf->idx_a=3; | |
| surf->idx_r=0; | |
| surf->idx_g=1; | |
| surf->idx_b=2; | |
| break; | |
| case GF_PIXEL_UYVA444_PACK: | |
| surf->idx_a=3; | |
| surf->idx_r=1; | |
| surf->idx_g=0; | |
| surf->idx_b=2; | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| surf->idx_r=0; | |
| surf->idx_g=1; | |
| surf->idx_b=2; | |
| break; | |
| case GF_PIXEL_VYU444_PACK: | |
| surf->idx_r=1; | |
| surf->idx_g=2; | |
| surf->idx_b=0; | |
| break; | |
| case GF_PIXEL_BGRA: | |
| surf->idx_a=3; | |
| surf->idx_r=2; | |
| surf->idx_g=1; | |
| surf->idx_b=0; | |
| break; | |
| case GF_PIXEL_ABGR: | |
| surf->idx_a=0; | |
| surf->idx_r=3; | |
| surf->idx_g=2; | |
| surf->idx_b=1; | |
| break; | |
| case GF_PIXEL_RGBX: | |
| surf->idx_r=0; | |
| surf->idx_g=1; | |
| surf->idx_b=2; | |
| surf->idx_a=3; | |
| break; | |
| case GF_PIXEL_BGRX: | |
| surf->idx_r=2; | |
| surf->idx_g=1; | |
| surf->idx_b=0; | |
| surf->idx_a=3; | |
| break; | |
| case GF_PIXEL_XRGB: | |
| surf->idx_a=0; | |
| surf->idx_r=1; | |
| surf->idx_g=2; | |
| surf->idx_b=3; | |
| break; | |
| case GF_PIXEL_XBGR: | |
| surf->idx_a=0; | |
| surf->idx_r=3; | |
| surf->idx_g=2; | |
| surf->idx_b=1; | |
| break; | |
| case GF_PIXEL_RGB: | |
| surf->idx_r=0; | |
| surf->idx_g=1; | |
| surf->idx_b=2; | |
| break; | |
| case GF_PIXEL_BGR: | |
| surf->idx_r=2; | |
| surf->idx_g=1; | |
| surf->idx_b=0; | |
| break; | |
| } | |
| } | |
| static GF_Err gf_evg_surface_attach_to_buffer_internal(GF_EVGSurface *surf, u8 *pixels, u32 width, u32 height, s32 pitch_x, s32 pitch_y, GF_PixelFormat pixelFormat, Bool probe_only) | |
| { | |
| u32 BPP; | |
| Bool size_changed=GF_FALSE; | |
| if (!probe_only) { | |
| if (!surf || !pixels) return GF_BAD_PARAM; | |
| surf->is_transparent = GF_FALSE; | |
| surf->not_8bits = GF_FALSE; | |
| } | |
| switch (pixelFormat) { | |
| case GF_PIXEL_GREYSCALE: | |
| BPP = 1; | |
| break; | |
| case GF_PIXEL_ALPHAGREY: | |
| case GF_PIXEL_GREYALPHA: | |
| BPP = 2; | |
| if (!probe_only) | |
| surf->is_transparent = GF_TRUE; | |
| break; | |
| case GF_PIXEL_RGB_332: | |
| BPP = 1; | |
| break; | |
| case GF_PIXEL_RGB_444: | |
| case GF_PIXEL_RGB_555: | |
| case GF_PIXEL_RGB_565: | |
| BPP = 2; | |
| break; | |
| case GF_PIXEL_ARGB: | |
| case GF_PIXEL_BGRA: | |
| case GF_PIXEL_RGBA: | |
| case GF_PIXEL_ABGR: | |
| if (!probe_only) | |
| surf->is_transparent = GF_TRUE; | |
| case GF_PIXEL_RGBX: | |
| case GF_PIXEL_BGRX: | |
| case GF_PIXEL_XRGB: | |
| case GF_PIXEL_XBGR: | |
| BPP = 4; | |
| break; | |
| case GF_PIXEL_BGR: | |
| case GF_PIXEL_RGB: | |
| BPP = 3; | |
| 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_YUYV: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_VYUY: | |
| BPP = 1; | |
| break; | |
| case GF_PIXEL_YUV_10: | |
| case GF_PIXEL_NV12_10: | |
| case GF_PIXEL_NV21_10: | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV444_10: | |
| BPP = 2; | |
| if (!probe_only) | |
| surf->not_8bits = GF_TRUE; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| if (!probe_only) | |
| surf->is_transparent = GF_TRUE; | |
| BPP = 4; | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| BPP = 3; | |
| break; | |
| default: | |
| return GF_NOT_SUPPORTED; | |
| } | |
| if (probe_only) return GF_OK; | |
| if (!pitch_x) pitch_x = BPP; | |
| if (!pitch_y) { | |
| gf_pixel_get_size_info(pixelFormat, width, height, NULL, &pitch_y, NULL, NULL, NULL); | |
| } | |
| surf->pitch_x = pitch_x; | |
| surf->pitch_y = pitch_y; | |
| if (!surf->raster_ctx.stencil_pix_run || (surf->width != width)) { | |
| u32 run_size = sizeof(u32) * (width+2); | |
| if (surf->not_8bits) run_size *= 2; | |
| surf->raster_ctx.stencil_pix_run = gf_realloc(surf->raster_ctx.stencil_pix_run, run_size); | |
| if (!surf->raster_ctx.stencil_pix_run) return GF_OUT_OF_MEM; | |
| if (surf->raster_ctx.stencil_pix_run2) { | |
| surf->raster_ctx.stencil_pix_run2 = gf_realloc(surf->raster_ctx.stencil_pix_run2, run_size); | |
| if (!surf->raster_ctx.stencil_pix_run2) return GF_OUT_OF_MEM; | |
| } | |
| if (surf->raster_ctx.stencil_pix_run3) { | |
| surf->raster_ctx.stencil_pix_run3 = gf_realloc(surf->raster_ctx.stencil_pix_run3, 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]; | |
| rctx->stencil_pix_run = gf_realloc(rctx->stencil_pix_run, run_size); | |
| if (!rctx->stencil_pix_run) return GF_OUT_OF_MEM; | |
| if (rctx->stencil_pix_run2) { | |
| rctx->stencil_pix_run2 = gf_realloc(rctx->stencil_pix_run2, run_size); | |
| if (!rctx->stencil_pix_run2) return GF_OUT_OF_MEM; | |
| } | |
| if (rctx->stencil_pix_run3) { | |
| rctx->stencil_pix_run3 = gf_realloc(rctx->stencil_pix_run3, run_size); | |
| if (!rctx->stencil_pix_run3) return GF_OUT_OF_MEM; | |
| } | |
| } | |
| #endif | |
| } | |
| if (surf->width != width) { | |
| surf->width = width; | |
| size_changed = GF_TRUE; | |
| } | |
| if (surf->height != height) { | |
| surf->height = height; | |
| size_changed = GF_TRUE; | |
| } | |
| surf->pixels = (char*)pixels; | |
| surf->pixelFormat = pixelFormat; | |
| surf->BPP = BPP; | |
| evg_surface_set_components_idx(surf); | |
| gf_evg_surface_set_matrix(surf, NULL); | |
| if (size_changed && surf->internal_mask) { | |
| gf_free(surf->internal_mask); | |
| surf->internal_mask = NULL; | |
| } | |
| if (surf->ext3d && size_changed) { | |
| surf->ext3d->depth_buffer = NULL; | |
| if (!surf->vp_w || !surf->vp_h) { | |
| surf->vp_x = 0; | |
| surf->vp_y = 0; | |
| surf->vp_w = surf->width; | |
| surf->vp_h = surf->height; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_attach_to_buffer(GF_EVGSurface *surf, u8 *pixels, u32 width, u32 height, s32 pitch_x, s32 pitch_y, GF_PixelFormat pixelFormat) | |
| { | |
| return gf_evg_surface_attach_to_buffer_internal(surf, pixels, width, height, pitch_x, pitch_y, pixelFormat, GF_FALSE); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_attach_to_texture(GF_EVGSurface *surf, GF_EVGStencil * sten) | |
| { | |
| EVG_Texture *tx = (EVG_Texture *) sten; | |
| if (!surf || (tx->type != GF_STENCIL_TEXTURE)) return GF_BAD_PARAM; | |
| return gf_evg_surface_attach_to_buffer_internal(surf, tx->pixels, tx->width, tx->height, 0, tx->stride, tx->pixel_format, GF_FALSE); | |
| } | |
| GF_EXPORT | |
| Bool gf_evg_surface_format_ok(GF_PixelFormat pixelFormat) | |
| { | |
| GF_Err e = gf_evg_surface_attach_to_buffer_internal(NULL, NULL, 0, 0, 0, 0, pixelFormat, GF_TRUE); | |
| if (e==GF_OK) return GF_TRUE; | |
| return GF_FALSE; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_clear(GF_EVGSurface *surf, GF_IRect *rc, u32 color) | |
| { | |
| GF_IRect clear; | |
| if (!surf) return GF_BAD_PARAM; | |
| if (rc) { | |
| s32 _x, _y; | |
| if (surf->center_coords) { | |
| _x = rc->x + surf->width / 2; | |
| _y = surf->height / 2 - rc->y; | |
| } else { | |
| _x = rc->x; | |
| _y = rc->y - rc->height; | |
| } | |
| /*clip is outside our bounds, ignore*/ | |
| if ((_x>=(s32) surf->width) || (_x + rc->width < 0)) | |
| return GF_OK; | |
| if ((_y>= (s32) surf->height) || (_y + rc->height < 0)) | |
| return GF_OK; | |
| clear.width = (u32) rc->width; | |
| if (_x>=0) { | |
| clear.x = (u32) _x; | |
| } else { | |
| if ( (s32) clear.width + _x < 0) return GF_BAD_PARAM; | |
| clear.width += _x; | |
| clear.x = 0; | |
| } | |
| if (clear.x + clear.width > (s32) surf->width) | |
| clear.width = surf->width - clear.x; | |
| if (!clear.width) | |
| return GF_OK; | |
| clear.height = (u32) rc->height; | |
| if (_y>=0) { | |
| clear.y = _y; | |
| } else { | |
| if ( (s32) clear.height + _y < 0) return GF_BAD_PARAM; | |
| clear.height += _y; | |
| clear.y = 0; | |
| } | |
| if (clear.y + clear.height > (s32) surf->height) | |
| clear.height = surf->height - clear.y; | |
| if (!clear.height) | |
| return GF_OK; | |
| } else { | |
| clear.x = clear.y = 0; | |
| clear.width = surf->width; | |
| clear.height = surf->height; | |
| } | |
| switch (surf->pixelFormat) { | |
| /*RGB formats*/ | |
| case GF_PIXEL_GREYSCALE: | |
| return evg_surface_clear_grey(surf, clear, color); | |
| case GF_PIXEL_ALPHAGREY: | |
| case GF_PIXEL_GREYALPHA: | |
| return evg_surface_clear_alphagrey(surf, clear, color); | |
| case GF_PIXEL_ARGB: | |
| case GF_PIXEL_BGRA: | |
| case GF_PIXEL_RGBA: | |
| case GF_PIXEL_ABGR: | |
| return evg_surface_clear_argb(surf, clear, color); | |
| case GF_PIXEL_RGBX: | |
| case GF_PIXEL_BGRX: | |
| case GF_PIXEL_XRGB: | |
| case GF_PIXEL_XBGR: | |
| return evg_surface_clear_rgbx(surf, clear, color); | |
| case GF_PIXEL_RGB: | |
| case GF_PIXEL_BGR: | |
| return evg_surface_clear_rgb(surf, clear, color); | |
| case GF_PIXEL_RGB_444: | |
| return evg_surface_clear_444(surf, clear, color); | |
| case GF_PIXEL_RGB_555: | |
| return evg_surface_clear_555(surf, clear, color); | |
| case GF_PIXEL_RGB_565: | |
| return evg_surface_clear_565(surf, clear, color); | |
| case GF_PIXEL_RGB_332: | |
| return evg_surface_clear_332(surf, clear, color); | |
| /*YUV formats*/ | |
| case GF_PIXEL_YUV: | |
| case GF_PIXEL_YVU: | |
| return evg_surface_clear_yuv420p(surf, clear, color); | |
| case GF_PIXEL_YUV422: | |
| return evg_surface_clear_yuv422p(surf, clear, color); | |
| case GF_PIXEL_NV12: | |
| return evg_surface_clear_nv12(surf, clear, color, GF_FALSE); | |
| case GF_PIXEL_NV21: | |
| return evg_surface_clear_nv12(surf, clear, color, GF_TRUE); | |
| case GF_PIXEL_YUV444: | |
| return evg_surface_clear_yuv444p(surf, clear, color); | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_VYUY: | |
| return evg_surface_clear_yuyv(surf, clear, color); | |
| case GF_PIXEL_YUV_10: | |
| return evg_surface_clear_yuv420p_10(surf, clear, color); | |
| case GF_PIXEL_NV12_10: | |
| return evg_surface_clear_nv12_10(surf, clear, color, GF_FALSE); | |
| case GF_PIXEL_NV21_10: | |
| return evg_surface_clear_nv12_10(surf, clear, color, GF_TRUE); | |
| case GF_PIXEL_YUV422_10: | |
| return evg_surface_clear_yuv422p_10(surf, clear, color); | |
| case GF_PIXEL_YUV444_10: | |
| return evg_surface_clear_yuv444p_10(surf, clear, color); | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| return evg_surface_clear_argb(surf, clear, gf_evg_argb_to_ayuv(surf, color) ); | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| return evg_surface_clear_rgb(surf, clear, gf_evg_argb_to_ayuv(surf, color) ); | |
| default: | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_set_raster_level(GF_EVGSurface *surf, GF_RasterQuality RasterSetting) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| surf->qlevel = RasterSetting; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_RasterQuality gf_evg_surface_get_raster_level(GF_EVGSurface *surf) | |
| { | |
| if (!surf) return GF_RASTER_HIGH_QUALITY; | |
| return surf->qlevel; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_force_aa(GF_EVGSurface *surf) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| surf->aa_level = 0xFF; | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_set_clipper(GF_EVGSurface *surf , GF_IRect *rc) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| if (rc) { | |
| surf->clipper = *rc; | |
| surf->useClipper = 1; | |
| /*clipper was given in BIFS like coords, we work with bottom-min for rect, (0,0) top-left of surface*/ | |
| if (surf->center_coords) { | |
| surf->clipper.x += surf->width / 2; | |
| surf->clipper.y = surf->height / 2 - rc->y; | |
| } else { | |
| surf->clipper.y -= rc->height; | |
| } | |
| if (surf->clipper.x <=0) { | |
| if (surf->clipper.x + (s32) surf->clipper.width < 0) return GF_BAD_PARAM; | |
| surf->clipper.width += surf->clipper.x; | |
| surf->clipper.x = 0; | |
| } | |
| if (surf->clipper.y <=0) { | |
| if (surf->clipper.y + (s32) surf->clipper.height < 0) return GF_BAD_PARAM; | |
| surf->clipper.height += surf->clipper.y; | |
| surf->clipper.y = 0; | |
| } | |
| if (surf->clipper.x + surf->clipper.width > (s32) surf->width) { | |
| surf->clipper.width = surf->width - surf->clipper.x; | |
| } | |
| if (surf->clipper.y + surf->clipper.height > (s32) surf->height) { | |
| surf->clipper.height = surf->height - surf->clipper.y; | |
| } | |
| } else { | |
| surf->useClipper = 0; | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| Bool gf_evg_surface_use_clipper(GF_EVGSurface *surf) | |
| { | |
| if (!surf) return 0; | |
| return surf->useClipper ? GF_TRUE : GF_FALSE; | |
| } | |
| static Bool setup_grey_callback(GF_EVGSurface *surf, Bool for_3d, Bool multi_sten) | |
| { | |
| u32 a, uv_alpha_size=0; | |
| Bool use_const = GF_TRUE; | |
| //default fill_run callback | |
| surf->fill_run = evg_fill_run; | |
| //mask mode draw, | |
| if (surf->mask_mode == GF_EVGMASK_DRAW) { | |
| if (surf->sten && (surf->sten->type == GF_STENCIL_SOLID)) { | |
| EVG_Brush *sc = (EVG_Brush *)surf->sten; | |
| u32 col = sc->color; | |
| if (sc->alpha < 0xFF) { | |
| u32 ca = ((u32) (GF_COL_A(col) + 1) * sc->alpha) >> 8; | |
| col = ( ((ca<<24) & 0xFF000000) ) | (col & 0x00FFFFFF); | |
| } | |
| surf->fill_col = col; | |
| surf->fill_col_wide = evg_col_to_wide(surf->fill_col); | |
| if (GF_COL_A(col)<0xFF) | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_const_a; | |
| else | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_const; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_grey_fill_single; | |
| surf->fill_single_a = evg_grey_fill_single_a; | |
| } | |
| return GF_TRUE; | |
| } | |
| //in 3D mode, we only write one pixel at a time except in YUV modes | |
| if (for_3d) { | |
| a = 1; | |
| use_const = GF_TRUE; | |
| } | |
| else if (!multi_sten && surf->sten && (surf->sten->type == GF_STENCIL_SOLID)) { | |
| EVG_Brush *sc = (EVG_Brush *)surf->sten; | |
| u32 col = sc->color; | |
| if (sc->alpha < 0xFF) { | |
| u32 ca = ((u32) (GF_COL_A(col) + 1) * sc->alpha) >> 8; | |
| col = ( ((ca<<24) & 0xFF000000) ) | (col & 0x00FFFFFF); | |
| } | |
| surf->fill_col = col; | |
| a = GF_COL_A(surf->fill_col); | |
| } else { | |
| a = 0; | |
| use_const = GF_FALSE; | |
| } | |
| //mask is used, force fill with variable alpha (xxx_fill_var) and use masking callback for fill_run | |
| if ((surf->mask_mode == GF_EVGMASK_USE) || (surf->mask_mode == GF_EVGMASK_RECORD) ){ | |
| a = 0; | |
| use_const = GF_FALSE; | |
| if (surf->mask_mode == GF_EVGMASK_USE) | |
| surf->fill_run = evg_fill_run_mask; | |
| } else if (surf->mask_mode == GF_EVGMASK_USE_INV) { | |
| a = 0; | |
| use_const = GF_FALSE; | |
| surf->fill_run = evg_fill_run_mask_inv; | |
| } | |
| if (use_const && !a && !surf->is_transparent) return GF_FALSE; | |
| surf->is_422 = GF_FALSE; | |
| surf->yuv_type = 0; | |
| surf->swap_uv = GF_FALSE; | |
| surf->yuv_flush_uv = NULL; | |
| surf->direct_yuv_3d = GF_FALSE; | |
| if (surf->comp_mode) a=100; | |
| else if (surf->get_alpha) a=100; | |
| surf->fill_single = NULL; | |
| surf->fill_single_a = NULL; | |
| switch (surf->pixelFormat) { | |
| case GF_PIXEL_GREYSCALE: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_grey_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_grey_fill_single; | |
| surf->fill_single_a = evg_grey_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_ALPHAGREY: | |
| case GF_PIXEL_GREYALPHA: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_alphagrey_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_alphagrey_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_alphagrey_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_alphagrey_fill_single; | |
| surf->fill_single_a = evg_alphagrey_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| surf->yuv_type = EVG_YUV; | |
| case GF_PIXEL_ARGB: | |
| case GF_PIXEL_RGBA: | |
| case GF_PIXEL_BGRA: | |
| case GF_PIXEL_ABGR: | |
| if (use_const) { | |
| if (!a) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_argb_fill_erase; | |
| } else if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_argb_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_argb_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_argb_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_argb_fill_single; | |
| surf->fill_single_a = evg_argb_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_RGBX: | |
| case GF_PIXEL_BGRX: | |
| case GF_PIXEL_XRGB: | |
| case GF_PIXEL_XBGR: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgbx_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgbx_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgbx_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_rgbx_fill_single; | |
| surf->fill_single_a = evg_rgbx_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| surf->yuv_type = EVG_YUV; | |
| case GF_PIXEL_RGB: | |
| case GF_PIXEL_BGR: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgb_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgb_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_rgb_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_rgb_fill_single; | |
| surf->fill_single_a = evg_rgb_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_RGB_565: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_565_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_565_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_565_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_565_fill_single; | |
| surf->fill_single_a = evg_565_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_RGB_444: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_444_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_444_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_444_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_444_fill_single; | |
| surf->fill_single_a = evg_444_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_RGB_555: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_555_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_555_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_555_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_555_fill_single; | |
| surf->fill_single_a = evg_555_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_RGB_332: | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_332_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_332_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_332_fill_var; | |
| } | |
| if (surf->ext3d) { | |
| surf->fill_single = evg_332_fill_single; | |
| surf->fill_single_a = evg_332_fill_single_a; | |
| } | |
| break; | |
| case GF_PIXEL_YVU: | |
| surf->swap_uv = GF_TRUE; | |
| case GF_PIXEL_YUV: | |
| surf->yuv_type = EVG_YUV; | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_yuv420p_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const; | |
| } | |
| uv_alpha_size=2*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_yuv420p_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_var; | |
| uv_alpha_size = 2 * 3*surf->width; | |
| if (for_3d) { | |
| surf->sten = &surf->ext3d->yuv_sten; | |
| surf->direct_yuv_3d = GF_TRUE; | |
| } | |
| } | |
| break; | |
| case GF_PIXEL_NV21: | |
| surf->swap_uv = GF_TRUE; | |
| case GF_PIXEL_NV12: | |
| surf->yuv_type = EVG_YUV; | |
| if (surf->swap_uv) { | |
| surf->idx_u = 1; | |
| surf->idx_v = 0; | |
| } else { | |
| surf->idx_u = 0; | |
| surf->idx_v = 1; | |
| } | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_nv12_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const; | |
| } | |
| uv_alpha_size = 2*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_nv12_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_var; | |
| uv_alpha_size = 2 * 3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_YUV422: | |
| surf->yuv_type = EVG_YUV; | |
| surf->is_422 = GF_TRUE; | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_yuv422p_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_const; | |
| } | |
| uv_alpha_size = 2*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_yuv422p_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_fill_var; | |
| uv_alpha_size = 2 * 3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_YUV444: | |
| surf->yuv_type = EVG_YUV_444; | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_fill_var; | |
| } | |
| break; | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_VYUY: | |
| surf->yuv_type = EVG_YUV; | |
| if (use_const && !for_3d) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuyv_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuyv_fill_const; | |
| } | |
| uv_alpha_size = 2*surf->width; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuyv_fill_var; | |
| uv_alpha_size = 2 * 3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_YUV_10: | |
| surf->yuv_type = EVG_YUV; | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_yuv420p_10_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const; | |
| } | |
| uv_alpha_size = 4*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_yuv420p_10_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_var; | |
| uv_alpha_size = 4*3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_NV21_10: | |
| surf->swap_uv = GF_TRUE; | |
| case GF_PIXEL_NV12_10: | |
| surf->yuv_type = EVG_YUV; | |
| if (surf->swap_uv) { | |
| surf->idx_u = 1; | |
| surf->idx_v = 0; | |
| } else { | |
| surf->idx_u = 0; | |
| surf->idx_v = 1; | |
| } | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_nv12_10_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const; | |
| } | |
| uv_alpha_size = 4*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_nv12_10_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_var; | |
| uv_alpha_size = 4 * 3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_YUV422_10: | |
| surf->yuv_type = EVG_YUV; | |
| surf->is_422 = GF_TRUE; | |
| if (use_const && !for_3d) { | |
| surf->yuv_flush_uv = evg_yuv422p_10_flush_uv_const; | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_const; | |
| } | |
| uv_alpha_size = 4*surf->width; | |
| } else { | |
| surf->yuv_flush_uv = evg_yuv422p_10_flush_uv_var; | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv420p_10_fill_var; | |
| uv_alpha_size = 4 * 3*surf->width; | |
| } | |
| break; | |
| case GF_PIXEL_YUV444_10: | |
| surf->yuv_type = EVG_YUV_444; | |
| if (use_const) { | |
| if (a!=0xFF) { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_10_fill_const_a; | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_10_fill_const; | |
| } | |
| } else { | |
| surf->fill_spans = (EVG_SpanFunc) evg_yuv444p_10_fill_var; | |
| } | |
| break; | |
| default: | |
| return GF_FALSE; | |
| } | |
| if (uv_alpha_size) { | |
| #ifndef GPAC_DISABLE_THREADS | |
| u32 i; | |
| #endif | |
| //safety for uneven size in 422/420 rounding (fuzz) | |
| uv_alpha_size += 4; | |
| if (surf->uv_alpha_alloc < uv_alpha_size) { | |
| surf->uv_alpha_alloc = uv_alpha_size; | |
| surf->raster_ctx.uv_alpha = gf_realloc(surf->raster_ctx.uv_alpha, uv_alpha_size); | |
| if (!surf->raster_ctx.uv_alpha) return GF_FALSE; | |
| #ifndef GPAC_DISABLE_THREADS | |
| for (i=0;i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| rctx->uv_alpha = gf_realloc(rctx->uv_alpha, uv_alpha_size); | |
| if (!rctx->uv_alpha) return GF_FALSE; | |
| } | |
| #endif | |
| } | |
| memset(surf->raster_ctx.uv_alpha, 0, sizeof(char)*surf->uv_alpha_alloc); | |
| #ifndef GPAC_DISABLE_THREADS | |
| for (i=0;i<surf->nb_threads; i++) { | |
| EVGRasterCtx *rctx = &surf->th_raster_ctx[i]; | |
| memset(rctx->uv_alpha, 0, sizeof(char)*surf->uv_alpha_alloc); | |
| } | |
| #endif | |
| } | |
| if (surf->yuv_type && for_3d) { | |
| surf->sten = &surf->ext3d->yuv_sten; | |
| surf->direct_yuv_3d = GF_TRUE; | |
| } | |
| if (use_const && surf->yuv_type) { | |
| u8 y, cb, cr; | |
| gf_evg_rgb_to_yuv(surf, surf->fill_col, &y, &cb, &cr); | |
| if (surf->swap_uv) { | |
| u8 t = cb; | |
| cb = cr; | |
| cr = (u8) t; | |
| surf->swap_uv = GF_FALSE; | |
| } | |
| surf->fill_col = GF_COL_ARGB(a, y, cb, cr); | |
| surf->fill_col_wide = evg_col_to_wide(surf->fill_col); | |
| } | |
| return GF_TRUE; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_set_path(GF_EVGSurface *surf, GF_Path *gp) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| surf->aa_level = 0; | |
| if (!gp || !gp->n_points) { | |
| surf->ftoutline.n_points = 0; | |
| surf->ftoutline.n_contours = 0; | |
| return GF_OK; | |
| } | |
| gf_path_flatten(gp); | |
| surf->ftoutline.n_points = gp->n_points; | |
| surf->ftoutline.n_contours = gp->n_contours; | |
| surf->ftoutline.tags = gp->tags; | |
| surf->ftoutline.contours = (s32*) gp->contours; | |
| /*store path bounds for gradient/textures*/ | |
| gf_path_get_bounds(gp, &surf->path_bounds); | |
| /*invert Y (ft uses min Y)*/ | |
| surf->path_bounds.y -= surf->path_bounds.height; | |
| surf->ftoutline.flags = 0; | |
| if (gp->flags & GF_PATH_FILL_ZERO_NONZERO) | |
| surf->ftoutline.flags |= GF_PATH_FILL_ZERO_NONZERO; | |
| if (gp->flags & GF_PATH_FILL_EVEN) | |
| surf->ftoutline.flags |= GF_PATH_FILL_EVEN; | |
| surf->ftoutline.n_points = gp->n_points; | |
| surf->ftoutline.points = gp->points; | |
| surf->mx = &surf->mat; | |
| return GF_OK; | |
| } | |
| static u32 shader_get_pix(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *rctx) | |
| { | |
| rctx->frag_param.tx_x = x; | |
| rctx->frag_param.tx_y = _this->height-y; | |
| evg_get_fragment(rctx->surf, rctx, NULL); | |
| rctx->frag_param.screen_x += 1; | |
| return rctx->fill_col; | |
| } | |
| static u64 shader_get_pix_wide(EVG_Texture *_this, u32 x, u32 y, EVGRasterCtx *rctx) | |
| { | |
| rctx->frag_param.tx_x = x; | |
| rctx->frag_param.tx_y = _this->height-y; | |
| evg_get_fragment(rctx->surf, rctx, NULL); | |
| rctx->frag_param.screen_x += 1; | |
| return rctx->fill_col_wide; | |
| } | |
| static GF_Err gf_evg_setup_stencil(GF_EVGSurface *surf, GF_EVGStencil *sten, GF_Matrix2D *mat) | |
| { | |
| GF_Rect rc; | |
| /*get path frame for texture convertion */ | |
| if (sten->type != GF_STENCIL_SOLID) { | |
| rc = surf->path_bounds; | |
| if (surf->is_shader) { | |
| EVG_Texture *_tx = (EVG_Texture *)sten; | |
| _tx->width = (u32) rc.width; | |
| _tx->height = (u32) rc.height; | |
| _tx->cmat.identity = 1; | |
| _tx->alpha = 255; | |
| gf_mx2d_init(_tx->smat); | |
| gf_mx2d_add_translation(&_tx->smat, rc.width/2, rc.height/2); | |
| gf_mx2d_add_matrix(&_tx->smat, &surf->shader_mx); | |
| // _tx->fill_run = tex_fill_run; | |
| _tx->tx_get_pixel = shader_get_pix; | |
| _tx->tx_get_pixel_wide = shader_get_pix_wide; | |
| _tx->is_wide = 1; | |
| _tx->is_yuv = surf->yuv_type ? 1 : 0; | |
| } | |
| gf_mx2d_apply_rect(mat, &rc); | |
| rc.x = rc.y = 0; | |
| /*assign target frame and matrix*/ | |
| sten->frame = rc; | |
| gf_mx2d_copy(sten->pmat, surf->mat); | |
| gf_mx2d_inverse(&sten->pmat); | |
| gf_mx2d_copy(sten->smat_bck, sten->smat); | |
| gf_mx2d_init(sten->smat); | |
| switch (sten->type) { | |
| case GF_STENCIL_TEXTURE: | |
| //in 3D mode, we only need the orginal stencil matrix | |
| if (!surf->is_3d_matrix) { | |
| if (!surf->is_shader) { | |
| EVG_Texture *texture = (EVG_Texture *) sten; | |
| if (!texture->tx_callback && ! texture->pixels) | |
| return GF_BAD_PARAM; | |
| if (texture->mod & GF_TEXTURE_FLIP_Y) { | |
| if (!surf->center_coords) gf_mx2d_add_scale(&sten->smat, FIX_ONE, -FIX_ONE); | |
| } else { | |
| if (surf->center_coords) gf_mx2d_add_scale(&sten->smat, FIX_ONE, -FIX_ONE); | |
| } | |
| } | |
| //add texture transform (normalized) | |
| gf_mx2d_add_matrix(&sten->smat, &sten->smat_bck); | |
| if (sten->auto_mx) { | |
| EVG_Texture *_tx = (EVG_Texture *)sten; | |
| //move translation to texture size | |
| sten->smat.m[2] *= _tx->width; | |
| sten->smat.m[5] *= _tx->height; | |
| //in auto mx, matrix is given inverted, as in OpenGL | |
| gf_mx2d_inverse(&sten->smat); | |
| //add texture -> untransformed path bounds matrix scale and translation | |
| gf_mx2d_add_scale(&sten->smat, surf->path_bounds.width/_tx->width, surf->path_bounds.height/_tx->height); | |
| gf_mx2d_add_translation(&sten->smat, -surf->path_bounds.width/2, surf->path_bounds.height/2); | |
| //add final path matrix | |
| gf_mx2d_add_matrix(&sten->smat, &surf->shader_mx); | |
| } | |
| //add surface matrix matrix | |
| gf_mx2d_add_matrix(&sten->smat, mat); | |
| gf_mx2d_inverse(&sten->smat); | |
| } else { | |
| if (!sten->auto_mx) { | |
| return GF_NOT_SUPPORTED; | |
| } | |
| } | |
| evg_texture_init(sten, surf); | |
| if (surf->is_shader) { | |
| EVG_Texture *_tx = (EVG_Texture *)sten; | |
| _tx->tx_get_pixel = shader_get_pix; | |
| _tx->tx_get_pixel_wide = shader_get_pix_wide; | |
| } | |
| break; | |
| case GF_STENCIL_LINEAR_GRADIENT: | |
| { | |
| EVG_LinearGradient *lin = (EVG_LinearGradient *)sten; | |
| gf_mx2d_copy(sten->smat, sten->smat_bck); | |
| if (!surf->is_3d_matrix) { | |
| if (sten->auto_mx) { | |
| //add [0,1] -> untransformed path bounds and path translation | |
| gf_mx2d_add_translation(&sten->smat, gf_divfix(surf->path_bounds.x, surf->path_bounds.width), gf_divfix(surf->path_bounds.y, surf->path_bounds.height)); | |
| gf_mx2d_add_scale(&sten->smat, surf->path_bounds.width, surf->path_bounds.height); | |
| gf_mx2d_add_matrix(&sten->smat, &surf->shader_mx); | |
| } | |
| gf_mx2d_add_matrix(&sten->smat, mat); | |
| } else { | |
| if (!sten->auto_mx) { | |
| return GF_NOT_SUPPORTED; | |
| } | |
| } | |
| gf_mx2d_inverse(&sten->smat); | |
| /*and finalize matrix in gradient coord system*/ | |
| gf_mx2d_add_matrix(&sten->smat, &lin->vecmat); | |
| gf_mx2d_add_scale(&sten->smat, INT2FIX(1<<EVGGRADIENTBITS), INT2FIX(1<<EVGGRADIENTBITS)); | |
| /*init*/ | |
| evg_gradient_precompute((EVG_BaseGradient *)lin, surf); | |
| } | |
| break; | |
| case GF_STENCIL_RADIAL_GRADIENT: | |
| { | |
| EVG_RadialGradient *rad = (EVG_RadialGradient*)sten; | |
| gf_mx2d_copy(sten->smat, sten->smat_bck); | |
| if (!surf->is_3d_matrix) { | |
| if (sten->auto_mx) { | |
| //add [0,1] -> untransformed path bounds and path translation | |
| gf_mx2d_add_translation(&sten->smat, gf_divfix(surf->path_bounds.x, surf->path_bounds.width), gf_divfix(surf->path_bounds.y, surf->path_bounds.height)); | |
| gf_mx2d_add_scale(&sten->smat, surf->path_bounds.width, surf->path_bounds.height); | |
| gf_mx2d_add_matrix(&sten->smat, &surf->shader_mx); | |
| } | |
| gf_mx2d_add_matrix(&sten->smat, mat); | |
| } else { | |
| if (!sten->auto_mx) { | |
| return GF_NOT_SUPPORTED; | |
| } | |
| } | |
| gf_mx2d_inverse(&sten->smat); | |
| gf_mx2d_add_translation(&sten->smat, -rad->center.x, -rad->center.y); | |
| gf_mx2d_add_scale(&sten->smat, gf_invfix(rad->radius.x), gf_invfix(rad->radius.y)); | |
| rad->d_f.x = gf_divfix(rad->focus.x - rad->center.x, rad->radius.x); | |
| rad->d_f.y = gf_divfix(rad->focus.y - rad->center.y, rad->radius.y); | |
| /*init*/ | |
| evg_radial_init(rad); | |
| evg_gradient_precompute((EVG_BaseGradient *)rad, surf); | |
| } | |
| break; | |
| } | |
| } else { | |
| EVG_Brush *sc = (EVG_Brush *) sten; | |
| u32 col = sc->color; | |
| if (sc->alpha < 0xFF) { | |
| u32 ca = ((u32) (GF_COL_A(col) + 1) * sc->alpha) >> 8; | |
| col = ( ((ca<<24) & 0xFF000000) ) | (col & 0x00FFFFFF); | |
| } | |
| if (surf->yuv_type) { | |
| sc->fill_col = gf_evg_argb_to_ayuv(surf, col); | |
| } else { | |
| sc->fill_col = col; | |
| } | |
| if (surf->not_8bits) | |
| sc->fill_col_wide = evg_col_to_wide(sc->fill_col); | |
| } | |
| return GF_OK; | |
| } | |
| static void gf_evg_restore_stencil(GF_EVGSurface *surf, GF_EVGStencil *sten) | |
| { | |
| /*restore stencil matrix*/ | |
| if (sten->type != GF_STENCIL_SOLID) { | |
| gf_mx2d_copy(sten->smat, sten->smat_bck); | |
| } | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_multi_fill(GF_EVGSurface *surf, GF_EVGMultiTextureMode operand, GF_EVGStencil *sten1, GF_EVGStencil *sten2, GF_EVGStencil *sten3, Float params[4]) | |
| { | |
| GF_Err e; | |
| Bool reset_aa = GF_FALSE; | |
| u32 max_gray; | |
| GF_Matrix2D mat; | |
| if (!surf || (!sten1 && !surf->frag_shader) ) return GF_BAD_PARAM; | |
| if (!surf->ftoutline.n_points) return GF_OK; | |
| surf->sten = sten1; | |
| surf->update_run = NULL; | |
| /*setup ft raster callbacks*/ | |
| if (!setup_grey_callback(surf, GF_FALSE, sten2 ? GF_TRUE : GF_FALSE)) return GF_OK; | |
| get_surface_world_matrix(surf, &mat); | |
| surf->is_shader = GF_FALSE; | |
| if (!sten1) { | |
| sten1 = (GF_EVGStencil *) &surf->shader_sten; | |
| sten1->type = GF_STENCIL_TEXTURE; | |
| surf->is_shader = GF_TRUE; | |
| surf->sten = sten1; | |
| operand = GF_EVG_OPERAND_NONE; | |
| } | |
| e = gf_evg_setup_stencil(surf, sten1, &mat); | |
| if (e) return e; | |
| if (operand) { | |
| e = gf_evg_setup_multi_texture(surf, operand, sten2, sten3, params); | |
| if (e) return e; | |
| if (sten2 && (sten2 != sten1)) { | |
| e = gf_evg_setup_stencil(surf, sten2, &mat); | |
| if (e) return e; | |
| } | |
| if (sten3 && (sten3 != sten1) && (sten3 != sten2)) { | |
| e = gf_evg_setup_stencil(surf, sten3, &mat); | |
| if (e) return e; | |
| } | |
| } | |
| if (!surf->aa_level) { | |
| //no AA | |
| if (surf->qlevel == GF_RASTER_HIGH_SPEED) surf->aa_level = 0; | |
| //skip pixles with less than 25% coverage | |
| else if (surf->qlevel == GF_RASTER_MID) surf->aa_level = 63; | |
| else surf->aa_level = 0xFF; | |
| reset_aa = GF_TRUE; | |
| } | |
| max_gray = surf->max_gray_spans; | |
| /*force complete line callback for YUV 420/422*/ | |
| if (surf->yuv_type==EVG_YUV) | |
| surf->max_gray_spans = 0xFFFFFFFF; | |
| if (surf->useClipper) { | |
| surf->clip_xMin = surf->clipper.x; | |
| surf->clip_yMin = surf->clipper.y; | |
| surf->clip_xMax = (surf->clipper.x + surf->clipper.width); | |
| surf->clip_yMax = (surf->clipper.y + surf->clipper.height); | |
| } else { | |
| surf->clip_xMin = 0; | |
| surf->clip_yMin = 0; | |
| surf->clip_xMax = (surf->width); | |
| surf->clip_yMax = (surf->height); | |
| } | |
| if (surf->mask_mode == GF_EVGMASK_DRAW) { | |
| u32 old_pitch_x = surf->pitch_x; | |
| u32 old_pitch_y = surf->pitch_y; | |
| u8 *old_pixels = surf->pixels; | |
| surf->pixels = surf->internal_mask; | |
| surf->pitch_x = 1; | |
| surf->pitch_y = surf->width; | |
| /*and call the raster*/ | |
| if (surf->is_3d_matrix) | |
| e = evg_raster_render_path_3d(surf); | |
| else | |
| e = evg_raster_render(surf); | |
| surf->pitch_x = old_pitch_x; | |
| surf->pitch_y = old_pitch_y; | |
| surf->pixels = old_pixels; | |
| } else { | |
| /*and call the raster*/ | |
| if (surf->is_3d_matrix) | |
| e = evg_raster_render_path_3d(surf); | |
| else | |
| e = evg_raster_render(surf); | |
| } | |
| if (reset_aa) surf->aa_level = 0; | |
| surf->max_gray_spans = max_gray; | |
| gf_evg_restore_stencil(surf, sten1); | |
| if (sten2) gf_evg_restore_stencil(surf, sten2); | |
| if (sten3) gf_evg_restore_stencil(surf, sten3); | |
| surf->sten = surf->sten2 = surf->sten3 = NULL; | |
| return e; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_evg_surface_fill(GF_EVGSurface *surf, GF_EVGStencil *sten) | |
| { | |
| return gf_evg_surface_multi_fill(surf, 0, sten, NULL, NULL, NULL); | |
| } | |
| void gf_evg_surface_set_composite_mode(GF_EVGSurface *surf, GF_EVGCompositeMode comp_mode) | |
| { | |
| if (surf) surf->comp_mode = comp_mode; | |
| } | |
| void gf_evg_surface_set_alpha_callback(GF_EVGSurface *surf, u8 (*get_alpha)(void *udta, u8 src_alpha, s32 x, s32 y), void *cbk) | |
| { | |
| if (surf) { | |
| surf->get_alpha = get_alpha; | |
| surf->get_alpha_udta = cbk; | |
| } | |
| } | |
| GF_Err gf_evg_surface_set_projection(GF_EVGSurface *surf, GF_Matrix *mx) | |
| { | |
| if (!surf || !surf->ext3d) return GF_BAD_PARAM; | |
| gf_mx_copy(surf->ext3d->proj, *mx); | |
| return GF_OK; | |
| } | |
| GF_Err gf_evg_surface_set_modelview(GF_EVGSurface *surf, GF_Matrix *mx) | |
| { | |
| if (!surf || !surf->ext3d) return GF_BAD_PARAM; | |
| gf_mx_copy(surf->ext3d->modelview, *mx); | |
| return GF_OK; | |
| } | |
| GF_Err evg_raster_render3d(GF_EVGSurface *surf, u32 *indices, u32 nb_idx, Float *vertices, u32 nb_vertices, u32 nb_comp, GF_EVGPrimitiveType prim_type); | |
| GF_Err gf_evg_surface_draw_array(GF_EVGSurface *surf, u32 *indices, u32 nb_idx, Float *vertices, u32 nb_vertices, u32 nb_comp, GF_EVGPrimitiveType prim_type) | |
| { | |
| GF_Err e; | |
| u32 max_gray; | |
| if (!surf || !surf->ext3d) return GF_BAD_PARAM; | |
| /*setup ft raster callbacks*/ | |
| if (!setup_grey_callback(surf, GF_TRUE, GF_FALSE)) return GF_OK; | |
| if (surf->useClipper) { | |
| surf->clip_xMin = surf->clipper.x; | |
| surf->clip_yMin = surf->clipper.y; | |
| surf->clip_xMax = (surf->clipper.x + surf->clipper.width); | |
| surf->clip_yMax = (surf->clipper.y + surf->clipper.height); | |
| } else { | |
| surf->clip_xMin = 0; | |
| surf->clip_yMin = 0; | |
| surf->clip_xMax = (surf->width); | |
| surf->clip_yMax = (surf->height); | |
| } | |
| max_gray = surf->max_gray_spans; | |
| /*force complete line callback for YUV 420/422*/ | |
| if (surf->yuv_type==EVG_YUV) | |
| surf->max_gray_spans = 0xFFFFFFFF; | |
| surf->aa_level = 0xFF; | |
| /*and call the raster*/ | |
| e = evg_raster_render3d(surf, indices, nb_idx, vertices, nb_vertices, nb_comp, prim_type); | |
| surf->max_gray_spans = max_gray; | |
| return e; | |
| } | |
| GF_Err evg_raster_render3d_path(GF_EVGSurface *surf, GF_Path *path, Float z); | |
| GF_Err gf_evg_surface_draw_path(GF_EVGSurface *surf, GF_Path *path, Float z) | |
| { | |
| GF_Err e; | |
| u32 max_gray; | |
| if (!surf || !surf->ext3d) return GF_BAD_PARAM; | |
| /*setup ft raster callbacks*/ | |
| if (!setup_grey_callback(surf, GF_TRUE, GF_FALSE)) return GF_OK; | |
| if (surf->useClipper) { | |
| surf->clip_xMin = surf->clipper.x; | |
| surf->clip_yMin = surf->clipper.y; | |
| surf->clip_xMax = (surf->clipper.x + surf->clipper.width); | |
| surf->clip_yMax = (surf->clipper.y + surf->clipper.height); | |
| } else { | |
| surf->clip_xMin = 0; | |
| surf->clip_yMin = 0; | |
| surf->clip_xMax = (surf->width); | |
| surf->clip_yMax = (surf->height); | |
| } | |
| max_gray = surf->max_gray_spans; | |
| /*force complete line callback for YUV 420/422*/ | |
| if (surf->yuv_type==EVG_YUV) | |
| surf->max_gray_spans = 0xFFFFFFFF; | |
| surf->aa_level = 0xFF; | |
| /*and call the raster*/ | |
| e = evg_raster_render3d_path(surf, path, z); | |
| surf->max_gray_spans = max_gray; | |
| return e; | |
| } | |
| GF_Err gf_evg_surface_set_mask_mode(GF_EVGSurface *surf, GF_EVGMaskMode mask_mode) | |
| { | |
| if (!surf) return GF_BAD_PARAM; | |
| if ((mask_mode==GF_EVGMASK_DRAW) | |
| || (mask_mode==GF_EVGMASK_DRAW_NO_CLEAR) | |
| || (mask_mode==GF_EVGMASK_RECORD) | |
| ) { | |
| u8 clear_val = 0; | |
| Bool clear_mask = GF_FALSE; | |
| if (!surf->internal_mask) { | |
| surf->internal_mask = gf_malloc(sizeof(u8) * surf->width * surf->height); | |
| if (!surf->internal_mask) return GF_OUT_OF_MEM; | |
| clear_mask = GF_TRUE; | |
| } | |
| if ((mask_mode==GF_EVGMASK_DRAW) && (surf->mask_mode != GF_EVGMASK_DRAW)) | |
| clear_mask = GF_TRUE; | |
| if (mask_mode==GF_EVGMASK_RECORD) { | |
| clear_mask = GF_TRUE; | |
| clear_val = 0xFF; | |
| } else { | |
| mask_mode = GF_EVGMASK_DRAW; | |
| } | |
| if (clear_mask) { | |
| memset(surf->internal_mask, clear_val, sizeof(u8) * surf->width * surf->height); | |
| } | |
| } | |
| surf->mask_mode = mask_mode; | |
| return GF_OK; | |
| } | |
| GF_EVGMaskMode gf_evg_surface_get_mask_mode(GF_EVGSurface *surf) | |
| { | |
| if (!surf) return GF_EVGMASK_NONE; | |
| return surf->mask_mode; | |
| } | |
| #endif // GPAC_DISABLE_EVG |