Coverage Report

Created: 2025-08-28 06:49

/src/gpac/src/evg/raster_argb.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / software 2D rasterizer
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 *
25
 */
26
27
#include "rast_soft.h"
28
29
#ifndef GPAC_DISABLE_EVG
30
31
static GFINLINE s32
32
mul255(s32 a, s32 b)
33
0
{
34
0
  return ((a+1) * b) >> 8;
35
0
}
36
37
38
/*
39
    32 bit ARGB/BGRA/RGBA
40
*/
41
42
u32 do_composite_mode(GF_EVGCompositeMode comp_mode, s32 *srca, s32 *dsta)
43
0
{
44
0
  switch (comp_mode) {
45
0
  case GF_EVG_SRC_ATOP:
46
0
    if (*srca && *dsta) {}
47
0
    else if (*dsta) { *srca = 0; }
48
0
    else { *dsta = *srca = 0; }
49
0
    break;
50
0
  case GF_EVG_SRC_IN:
51
0
    if (*srca && *dsta) {}
52
0
    else { *dsta = *srca = 0; }
53
0
    break;
54
0
  case GF_EVG_SRC_OUT:
55
0
    if (*srca && !*dsta) {}
56
0
    else { *dsta = *srca = 0; }
57
0
    break;
58
0
  case GF_EVG_DST_ATOP:
59
0
    if (*srca && *dsta) { *srca = 0;}
60
0
    else if (*srca) { *dsta = 0; }
61
0
    else { *dsta = *srca = 0; }
62
0
    break;
63
0
  case GF_EVG_DST_IN:
64
0
    if (*srca && *dsta) { *srca = 0; }
65
0
    else { *dsta = *srca = 0; }
66
0
    break;
67
0
  case GF_EVG_DST_OUT:
68
0
    if (!*srca && *dsta) {*srca = 0;}
69
0
    else { *dsta = *srca = 0; }
70
0
    break;
71
0
  case GF_EVG_DST_OVER:
72
0
    if (*dsta) {*srca = 0;}
73
0
    else { *dsta = *srca = 0; }
74
0
    break;
75
0
  case GF_EVG_LIGHTER:
76
0
    return 1;
77
0
  case GF_EVG_COPY:
78
0
    *dsta = 0;
79
0
    break;
80
0
  case GF_EVG_XOR:
81
0
    return 2;
82
0
  case GF_EVG_SRC_OVER:
83
0
    return 0;
84
0
  }
85
0
  return 0;
86
0
}
87
88
GFINLINE static void overmask_argb(u32 src, u8 *dst, u32 alpha, GF_EVGSurface *surf)
89
0
{
90
0
  u32 cmode;
91
0
  s32 srca = GF_COL_A(src);
92
0
  s32 srcr = GF_COL_R(src);
93
0
  s32 srcg = GF_COL_G(src);
94
0
  s32 srcb = GF_COL_B(src);
95
0
  s32 dsta = dst[surf->idx_a];
96
97
0
  srca = mul255(srca, alpha);
98
99
0
  cmode = do_composite_mode(surf->comp_mode, &srca, &dsta);
100
0
  if (cmode==1) {
101
0
    u8 dstr = dst[surf->idx_r];
102
0
    u8 dstg = dst[surf->idx_g];
103
0
    u8 dstb = dst[surf->idx_b];
104
//    dsta += srca;
105
//    if (srca>0xFF) srca = 0xFF;
106
0
    dstr += srcr;
107
0
    if (dstr>0xFF) dstr = 0xFF;
108
0
    dstg += srcg;
109
0
    if (dstg>0xFF) dstg = 0xFF;
110
0
    dstb += srcb;
111
0
    if (dstb>0xFF) dstb = 0xFF;
112
0
    dst[surf->idx_a] = (u8) srca;
113
0
    dst[surf->idx_r] = (u8) dstr;
114
0
    dst[surf->idx_g] = (u8) dstg;
115
0
    dst[surf->idx_b] = (u8) dstb;
116
0
    return;
117
0
  }
118
0
  if (cmode==2) {
119
0
    u8 dstr = dst[surf->idx_r];
120
0
    u8 dstg = dst[surf->idx_g];
121
0
    u8 dstb = dst[surf->idx_b];
122
0
    dst[surf->idx_a] = (u8) srca;
123
0
    dst[surf->idx_r] = (u8) (dstr^srcr);
124
0
    dst[surf->idx_g] = (u8) (dstg^srcg);
125
0
    dst[surf->idx_b] = (u8) (dstb^srcb);
126
0
    return;
127
0
  }
128
129
  /*special case for RGBA:
130
    if dst alpha is 0, consider the surface is empty and copy pixel
131
    if source alpha is 0xFF erase the entire pixel
132
  */
133
0
  if (dsta && (srca!=0xFF) ) {
134
0
    s32 final_a;
135
0
    s32 dstr = dst[surf->idx_r];
136
0
    s32 dstg = dst[surf->idx_g];
137
0
    s32 dstb = dst[surf->idx_b];
138
139
    //do the maths , so that the result of the blend follows the same DST = SRC*apha + DST(1-alpha)
140
    //it gives a transform alpha of Fa = SRCa + DSTa - SRCa*DSTa
141
    //and an RGB Fc = (SRCa*SRCc + DSTa*DSTc - DSTc*(DSTa-SRCa)) / Fa
142
0
    final_a = dsta + srca - mul255(dsta, srca);
143
0
    if (final_a) {
144
0
      s32 res;
145
0
      dst[surf->idx_a] = final_a;
146
0
      res = (srcr*srca + dstr*(dsta-srca)) / final_a;
147
0
      if (res<0) res=0;
148
0
      dst[surf->idx_r] = (u8) (res);
149
0
      res = (srcg*srca + dstg*(dsta-srca)) / final_a;
150
0
      if (res<0) res=0;
151
0
      dst[surf->idx_g] = (u8) (res);
152
0
      res = (srcb*srca + dstb*(dsta-srca)) / final_a;
153
0
      if (res<0) res=0;
154
0
      dst[surf->idx_b] = (u8) (res);
155
0
    }
156
0
  } else {
157
0
    dst[surf->idx_a] = (u8) srca;
158
0
    dst[surf->idx_r] = (u8) srcr;
159
0
    dst[surf->idx_g] = (u8) srcg;
160
0
    dst[surf->idx_b] = (u8) srcb;
161
0
  }
162
0
}
163
164
GFINLINE static void overmask_argb_const_run(u32 src, u8 *dst, s32 dst_pitch_x, u32 count, GF_EVGSurface *surf)
165
0
{
166
0
  u8 const_srca = GF_COL_A(src);
167
0
  s32 srcr = GF_COL_R(src);
168
0
  s32 srcg = GF_COL_G(src);
169
0
  s32 srcb = GF_COL_B(src);
170
171
0
  while (count) {
172
0
    s32 srca = const_srca;
173
0
    s32 dsta = dst[surf->idx_a];
174
175
0
    do_composite_mode(surf->comp_mode, &srca, &dsta);
176
177
    /*special case for RGBA:
178
      if dst alpha is 0, consider the surface is empty and copy pixel
179
      if source alpha is 0xFF erase the entire pixel
180
    */
181
0
    if ((dsta != 0) && (srca != 0xFF)) {
182
0
      s32 final_a;
183
0
      s32 dstr = dst[surf->idx_r];
184
0
      s32 dstg = dst[surf->idx_g];
185
0
      s32 dstb = dst[surf->idx_b];
186
187
      //do the maths , so that the result of the blend follows the same DST = SRC*apha + DST(1-alpha)
188
      //it gives a transform alpha of Fa = SRCa + DSTa - SRCa*DSTa
189
      //and an RGB Fc = (SRCa*SRCc + DSTa*DSTc - DSTc*(DSTa-SRCa)) / Fa
190
0
      final_a = dsta + srca - mul255(dsta, srca);
191
0
      if (final_a) {
192
0
        s32 res;
193
0
        dst[surf->idx_a] = final_a;
194
0
        res = (srcr*srca + dstr*(dsta-srca)) / final_a;
195
0
        if (res<0) res=0;
196
0
        dst[surf->idx_r] = (u8) (res);
197
0
        res = (srcg*srca + dstg*(dsta-srca)) / final_a;
198
0
        if (res<0) res=0;
199
0
        dst[surf->idx_g] = (u8) (res);
200
0
        res = (srcb*srca + dstb*(dsta-srca)) / final_a;
201
0
        if (res<0) res=0;
202
0
        dst[surf->idx_b] = (u8) (res);
203
0
      }
204
0
    } else {
205
0
      dst[surf->idx_a] = (u8) srca;
206
0
      dst[surf->idx_r] = (u8) srcr;
207
0
      dst[surf->idx_g] = (u8) srcg;
208
0
      dst[surf->idx_b] = (u8) srcb;
209
0
    }
210
0
    dst+=dst_pitch_x;
211
0
    count--;
212
0
  }
213
0
}
214
215
void evg_argb_fill_single(s32 y, s32 x, u32 col, GF_EVGSurface *surf)
216
0
{
217
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
218
0
  overmask_argb(col, dst, 0xFF, surf);
219
0
}
220
221
void evg_argb_fill_single_a(s32 y, s32 x, u8 coverage, u32 col, GF_EVGSurface *surf)
222
0
{
223
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
224
0
  overmask_argb(col, dst, coverage, surf);
225
0
}
226
227
228
void evg_argb_fill_const(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
229
0
{
230
0
  u32 col = surf->fill_col;
231
0
  u32 col_no_a;
232
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
233
0
  s32 i;
234
235
0
  col_no_a = col & 0x00FFFFFF;
236
237
0
  for (i=0; i<count; i++) {
238
0
    u32 new_a, fin;
239
0
    u8 *p;
240
0
    u32 len;
241
0
    p = dst + spans[i].x*surf->pitch_x;
242
0
    len = spans[i].len;
243
244
0
    new_a = spans[i].coverage;
245
0
    fin = (new_a<<24) | col_no_a;
246
    //we must blend in all cases since we have to merge with the dst alpha
247
0
    overmask_argb_const_run(fin, p, surf->pitch_x, len, surf);
248
0
  }
249
0
}
250
251
void evg_argb_fill_const_a(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
252
0
{
253
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
254
0
  u32 a, fin, col_no_a;
255
0
  s32 i;
256
257
0
  a = GF_COL_A(surf->fill_col);
258
0
  col_no_a = surf->fill_col & 0x00FFFFFF;
259
0
  if (surf->get_alpha) {
260
0
    u32 j;
261
0
    for (i=0; i<count; i++) {
262
0
      for (j=0; j<spans[i].len; j++) {
263
0
        s32 x = spans[i].x+j;
264
0
        u8 aa = surf->get_alpha(surf->get_alpha_udta, a, x, y);
265
0
        fin = mul255(aa, spans[i].coverage);
266
0
        fin = (fin<<24) | col_no_a;
267
0
        overmask_argb_const_run(fin, dst + x * surf->pitch_x, surf->pitch_x, 1, surf);
268
0
      }
269
0
    }
270
0
  } else {
271
0
    for (i=0; i<count; i++) {
272
0
      fin = mul255(a, spans[i].coverage);
273
0
      fin = (fin<<24) | col_no_a;
274
0
      overmask_argb_const_run(fin, dst + spans[i].x*surf->pitch_x, surf->pitch_x, spans[i].len, surf);
275
0
    }
276
0
  }
277
0
}
278
279
void evg_argb_fill_var(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
280
0
{
281
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
282
0
  s32 i;
283
284
0
  for (i=0; i<count; i++) {
285
0
    u8 *p;
286
0
    u8 spanalpha;
287
0
    u32 len;
288
0
    u32 *col;
289
0
    p = dst + spans[i].x * surf->pitch_x;
290
0
    len = spans[i].len;
291
0
    col = surf->fill_run(surf->sten, rctx, &spans[i], y);
292
0
    spanalpha = spans[i].coverage;
293
0
    while (len--) {
294
      //we must blend in all cases since we have to merge with the dst alpha
295
0
      overmask_argb(*col, p, spanalpha, surf);
296
0
      col++;
297
0
      p += surf->pitch_x;
298
0
    }
299
0
  }
300
0
}
301
302
303
void evg_argb_fill_erase(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
304
0
{
305
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
306
0
  s32 i;
307
308
0
  for (i=0; i<count; i++) {
309
0
    u8 *p;
310
0
    u32 len;
311
0
    p = dst + spans[i].x*surf->pitch_x;
312
0
    len = spans[i].len;
313
0
    if (spans[i].coverage != 0xFF) {
314
0
    } else {
315
0
      while (len--) {
316
0
        *(u32 *)p = 0;
317
0
        p += surf->pitch_x;
318
0
      }
319
0
    }
320
0
  }
321
0
}
322
323
GF_Err evg_surface_clear_argb(GF_EVGSurface *surf, GF_IRect rc, GF_Color col)
324
0
{
325
0
  u8 *data, *o_data;
326
0
  u8 a, r, g, b;
327
0
  u32 x, y, w, h, sy;
328
0
  s32 st;
329
0
  GF_EVGSurface *_this = (GF_EVGSurface *)surf;
330
0
  st = _this->pitch_y;
331
332
0
  h = rc.height;
333
0
  w = rc.width;
334
0
  sy = rc.y;
335
336
0
  if (sy+h > _this->height) {
337
0
    h = _this->height - sy;
338
0
  }
339
0
  if (rc.x + w > _this->width) {
340
0
    w = _this->width - rc.x;
341
0
  }
342
343
0
  a = GF_COL_A(col);
344
0
  r = GF_COL_R(col);
345
0
  g = GF_COL_G(col);
346
0
  b = GF_COL_B(col);
347
348
0
  o_data = NULL;
349
0
  for (y = 0; y < h; y++) {
350
0
    data = (u8 *) _this ->pixels + (sy+y)* st + _this->pitch_x * rc.x;
351
0
    if (!y) {
352
0
      o_data = data;
353
0
      for (x = 0; x < w; x++) {
354
0
        data[surf->idx_a] = a;
355
0
        data[surf->idx_r] = r;
356
0
        data[surf->idx_g] = g;
357
0
        data[surf->idx_b] = b;
358
0
        data += 4;
359
0
      }
360
0
    } else {
361
0
      memcpy(data, o_data, w*4);
362
0
    }
363
0
  }
364
0
  return GF_OK;
365
0
}
366
367
/*
368
    32 bit RGBX/XRGB/BGRX/XBGR
369
*/
370
371
static void overmask_rgbx(u32 src, u8 *dst, u32 alpha, GF_EVGSurface *surf)
372
0
{
373
0
  s32 srca = (src >> 24) & 0xff;
374
0
  s32 srcr = (src >> 16) & 0xff;
375
0
  s32 srcg = (src >> 8) & 0xff;
376
0
  s32 srcb = (src >> 0) & 0xff;
377
378
0
  s32 dstr = dst[surf->idx_r];
379
0
  s32 dstg = dst[surf->idx_g];
380
0
  s32 dstb = dst[surf->idx_b];
381
382
0
  srca = mul255(srca, alpha);
383
0
  dst[surf->idx_r] = mul255(srca, srcr - dstr) + dstr;
384
0
  dst[surf->idx_g] = mul255(srca, srcg - dstg) + dstg;
385
0
  dst[surf->idx_b] = mul255(srca, srcb - dstb) + dstb;
386
0
}
387
388
GFINLINE static void overmask_rgbx_const_run(u32 src, u8 *dst, s32 dst_pitch_x, u32 count, GF_EVGSurface *surf)
389
0
{
390
0
  s32 srca = (src>>24) & 0xff;
391
0
  u32 srcr = mul255(srca, ((src >> 16) & 0xff)) ;
392
0
  u32 srcg = mul255(srca, ((src >> 8) & 0xff)) ;
393
0
  u32 srcb = mul255(srca, ((src) & 0xff)) ;
394
0
  while (count) {
395
0
    u32 dstc;
396
0
    dstc = dst[surf->idx_r];
397
0
    dst[surf->idx_r] = mul255(srca, srcr - dstc) + dstc;
398
0
    dstc = dst[surf->idx_g];
399
0
    dst[surf->idx_g] = mul255(srca, srcg - dstc) + dstc;
400
0
    dstc = dst[surf->idx_b];
401
0
    dst[surf->idx_b] = mul255(srca, srcb - dstc) + dstc;
402
0
    dst += dst_pitch_x;
403
0
    count--;
404
0
  }
405
0
}
406
407
408
void evg_rgbx_fill_single(s32 y, s32 x, u32 col, GF_EVGSurface *surf)
409
0
{
410
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
411
0
  u8 r = GF_COL_R(col);
412
0
  u8 g = GF_COL_G(col);
413
0
  u8 b = GF_COL_B(col);
414
0
  dst[surf->idx_r] = r;
415
0
  dst[surf->idx_g] = g;
416
0
  dst[surf->idx_b] = b;
417
0
}
418
419
void evg_rgbx_fill_single_a(s32 y, s32 x, u8 coverage, u32 col, GF_EVGSurface *surf)
420
0
{
421
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
422
0
  overmask_rgbx(col, dst, coverage, surf);
423
0
}
424
425
void evg_rgbx_fill_const(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
426
0
{
427
0
  u32 col = surf->fill_col;
428
0
  u32 fin, col_no_a, spana;
429
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
430
0
  u8 r, g, b;
431
0
  s32 i, x;
432
0
  u32 len;
433
434
0
  col_no_a = col & 0x00FFFFFF;
435
0
  r = GF_COL_R(col);
436
0
  g = GF_COL_G(col);
437
0
  b = GF_COL_B(col);
438
439
0
  for (i=0; i<count; i++) {
440
0
    spana = spans[i].coverage;
441
0
    x = spans[i].x * surf->pitch_x;
442
0
    len = spans[i].len;
443
444
0
    if (spana != 0xFF) {
445
0
      fin = (spana<<24) | col_no_a;
446
0
      overmask_rgbx_const_run(fin, dst + x, surf->pitch_x, len, surf);
447
0
    } else {
448
0
      while (len--) {
449
0
        dst[x+surf->idx_r] = r;
450
0
        dst[x+surf->idx_g] = g;
451
0
        dst[x+surf->idx_b] = b;
452
0
        x += surf->pitch_x;
453
0
      }
454
0
    }
455
0
  }
456
0
}
457
458
void evg_rgbx_fill_const_a(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
459
0
{
460
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
461
0
  u32 col = surf->fill_col;
462
0
  u32 a, fin, col_no_a;
463
0
  s32 i;
464
465
0
  a = (col>>24)&0xFF;
466
0
  col_no_a = col & 0x00FFFFFF;
467
0
  if (surf->get_alpha) {
468
0
    for (i=0; i<count; i++) {
469
0
      u32 j;
470
0
      for (j=0; j<spans[i].len; j++) {
471
0
        s32 x = spans[i].x + j;
472
0
        u8 aa = surf->get_alpha(surf->get_alpha_udta, a, x, y);
473
0
        fin = mul255(aa, spans[i].coverage);
474
0
        fin = (fin<<24) | col_no_a;
475
0
        overmask_rgbx_const_run(fin, dst + surf->pitch_x * x, surf->pitch_x, 1, surf);
476
0
      }
477
0
    }
478
0
  } else {
479
0
    for (i=0; i<count; i++) {
480
0
      fin = mul255(a, spans[i].coverage);
481
0
      fin = (fin<<24) | col_no_a;
482
0
      overmask_rgbx_const_run(fin, dst + surf->pitch_x*spans[i].x, surf->pitch_x, spans[i].len, surf);
483
0
    }
484
0
  }
485
0
}
486
487
488
void evg_rgbx_fill_var(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
489
0
{
490
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
491
0
  s32 i;
492
493
0
  for (i=0; i<count; i++) {
494
0
    u8 spanalpha, col_a;
495
0
    s32 x;
496
0
    u32 len;
497
0
    u32 *col, _col;
498
0
    len = spans[i].len;
499
0
    col = surf->fill_run(surf->sten, rctx, &spans[i], y);
500
0
    spanalpha = spans[i].coverage;
501
0
    x = spans[i].x * surf->pitch_x;
502
    
503
0
    while (len--) {
504
0
      _col = *col;
505
0
      col_a = GF_COL_A(_col);
506
0
      if (col_a) {
507
0
        if ((spanalpha!=0xFF) || (col_a != 0xFF)) {
508
0
          overmask_rgbx(*col, dst+x, spanalpha, surf);
509
0
        } else {
510
0
          dst[x+surf->idx_r] = GF_COL_R(_col);
511
0
          dst[x+surf->idx_g] = GF_COL_G(_col);
512
0
          dst[x+surf->idx_b] = GF_COL_B(_col);
513
0
        }
514
0
      }
515
0
      col++;
516
0
      x += surf->pitch_x;
517
0
    }
518
0
  }
519
0
}
520
521
GF_Err evg_surface_clear_rgbx(GF_EVGSurface *surf, GF_IRect rc, GF_Color col)
522
0
{
523
0
  u32 x, y, w, h, sx, sy;
524
0
  u8 r,g,b;
525
0
  s32 st;
526
0
  char *o_data;
527
0
  GF_EVGSurface *_this = (GF_EVGSurface *)surf;
528
0
  st = _this->pitch_x;
529
530
0
  h = rc.height;
531
0
  w = rc.width;
532
0
  sx = rc.x;
533
0
  sy = rc.y;
534
535
0
  r = GF_COL_R(col);
536
0
  g = GF_COL_G(col);
537
0
  b = GF_COL_B(col);
538
539
0
  o_data = NULL;
540
0
  for (y = 0; y < h; y++) {
541
0
    u8 *data = (u8 *) _this ->pixels + (y + sy) * _this->pitch_y + st*sx;
542
0
    if (!y) {
543
0
      o_data = data;
544
0
      for (x = 0; x < w; x++) {
545
0
        data[surf->idx_r] = r;
546
0
        data[surf->idx_g] = g;
547
0
        data[surf->idx_b] = b;
548
0
        data[surf->idx_a] = 0xFF;
549
0
        data += st;
550
0
      }
551
0
    } else {
552
0
      memcpy(data, o_data, w*4);
553
0
    }
554
0
  }
555
0
  return GF_OK;
556
0
}
557
558
559
560
561
/*
562
    alpha grey
563
*/
564
565
static void overmask_alphagrey(u32 src, u8 *dst, u32 alpha, u32 grey_type, u32 idx_g, u32 idx_a)
566
0
{
567
0
  s32 srca = (src >> 24) & 0xff;
568
0
  s32 srcc;
569
0
  s32 dsta = dst[idx_a];
570
571
0
  if (grey_type==0) srcc = (src >> 16) & 0xff;
572
0
  else if (grey_type==1) srcc = (src >> 8) & 0xff;
573
0
  else srcc = (src >> 0) & 0xff;
574
0
  srca = mul255(srca, alpha);
575
576
0
  if (dsta) {
577
0
    s32 dstc = dst[idx_g];
578
0
    dst[idx_g] = mul255(srca, srcc - dstc) + dstc;
579
0
    dst[idx_a] = mul255(srca, srca) + mul255(255-srca, dsta);
580
0
  } else {
581
0
    dst[idx_g] = srcc;
582
0
    dst[idx_a] = srca;
583
0
  }
584
0
}
585
586
static void overmask_alphagrey_const_run(u32 src_a, u32 src_c, u8 *dst, s32 dst_pitch_x, u32 count, u32 idx_g, u32 idx_a)
587
0
{
588
0
  while (count) {
589
0
    s32 dsta = dst[idx_a];
590
    /*special case : if dst alpha is 0, consider the surface is empty and copy pixel*/
591
0
    if (dsta) {
592
0
      s32 dstc = dst[idx_g];
593
0
      dst[idx_g] = mul255(src_a, src_c - dstc) + dstc;
594
0
      dst[idx_a] = mul255(src_a, src_a) + mul255(255-src_a, dsta);
595
0
    } else {
596
0
      dst[idx_g] = src_c;
597
0
      dst[idx_a] = src_a;
598
0
    }
599
0
    dst += dst_pitch_x;
600
0
    count--;
601
0
  }
602
0
}
603
604
605
void evg_alphagrey_fill_single(s32 y, s32 x, u32 col, GF_EVGSurface *surf)
606
0
{
607
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
608
0
  u8 col_c;
609
610
0
  if (surf->grey_type==0) col_c = GF_COL_R(col);
611
0
  else if (surf->grey_type==1) col_c = GF_COL_G(col);
612
0
  else col_c = GF_COL_B(col);
613
0
  dst[surf->idx_g] = col_c;
614
0
}
615
616
void evg_alphagrey_fill_single_a(s32 y, s32 x, u8 coverage, u32 col, GF_EVGSurface *surf)
617
0
{
618
0
  u8 *dst = surf->pixels + y * surf->pitch_y + x * surf->pitch_x;
619
0
  overmask_alphagrey(col, dst, coverage, surf->grey_type, surf->idx_g, surf->idx_a);
620
0
}
621
622
void evg_alphagrey_fill_const(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
623
0
{
624
0
  u32 col = surf->fill_col;
625
0
  u32 a;
626
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
627
0
  s32 i, x;
628
0
  u32 len;
629
0
  u8 col_a, col_c;
630
631
0
  col_a = GF_COL_A(col);
632
0
  if (surf->grey_type==0) col_c = GF_COL_R(col);
633
0
  else if (surf->grey_type==1) col_c = GF_COL_G(col);
634
0
  else col_c = GF_COL_B(col);
635
636
0
  for (i=0; i<count; i++) {
637
0
    x = spans[i].x * surf->pitch_x;
638
0
    len = spans[i].len;
639
640
0
    if (spans[i].coverage != 0xFF) {
641
0
      a = mul255(0xFF, spans[i].coverage);
642
0
      overmask_alphagrey_const_run(a, col_c, dst + x, surf->pitch_x, len, surf->idx_g, surf->idx_a);
643
0
    } else {
644
0
      while (len--) {
645
0
        dst[x+surf->idx_g] = col_c;
646
0
        dst[x+surf->idx_a] = col_a;
647
0
        x += surf->pitch_x;
648
0
      }
649
0
    }
650
0
  }
651
0
}
652
653
void evg_alphagrey_fill_const_a(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
654
0
{
655
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
656
0
  u32 col = surf->fill_col;
657
0
  u32 a, fin, col_c;
658
0
  s32 i;
659
660
0
  a = GF_COL_A(col);
661
0
  if (surf->grey_type==0) col_c = GF_COL_R(col);
662
0
  else if (surf->grey_type==1) col_c = GF_COL_G(col);
663
0
  else col_c = GF_COL_B(col);
664
665
0
  if (surf->get_alpha) {
666
0
    for (i=0; i<count; i++) {
667
0
      u32 j;
668
0
      for (j=0; j<spans[i].len; i++) {
669
0
        s32 x = spans[i].x+j;
670
0
        u8 aa = surf->get_alpha(surf->get_alpha_udta, a, x, y);
671
0
        fin = mul255(aa, spans[i].coverage);
672
0
        overmask_alphagrey_const_run(fin, col_c, dst + surf->pitch_x * x, surf->pitch_x, 1, surf->idx_g, surf->idx_a);
673
0
      }
674
0
    }
675
0
  } else {
676
0
    for (i=0; i<count; i++) {
677
0
      fin = mul255(a, spans[i].coverage);
678
0
      overmask_alphagrey_const_run(fin, col_c, dst + surf->pitch_x*spans[i].x, surf->pitch_x, spans[i].len, surf->idx_g, surf->idx_a);
679
0
    }
680
0
  }
681
0
}
682
683
684
void evg_alphagrey_fill_var(s32 y, s32 count, EVG_Span *spans, GF_EVGSurface *surf, EVGRasterCtx *rctx)
685
0
{
686
0
  u8 *dst = (u8 *) surf->pixels + y * surf->pitch_y;
687
0
  s32 i;
688
689
0
  for (i=0; i<count; i++) {
690
0
    u8 spanalpha, col_a;
691
0
    s32 x;
692
0
    u32 len;
693
0
    u32 *col, _col;
694
0
    len = spans[i].len;
695
0
    col = surf->fill_run(surf->sten, rctx, &spans[i], y);
696
0
    spanalpha = spans[i].coverage;
697
0
    x = spans[i].x * surf->pitch_x;
698
0
    while (len--) {
699
0
      _col = *col;
700
0
      col_a = GF_COL_A(_col);
701
0
      if (col_a) {
702
0
        if ((spanalpha!=0xFF) || (col_a != 0xFF)) {
703
0
          overmask_alphagrey(*col, (dst + x) , spanalpha, surf->grey_type, surf->idx_g, surf->idx_a);
704
0
        } else {
705
0
          u8 dstc;
706
707
0
          if (surf->grey_type==0) dstc = GF_COL_R(_col);
708
0
          else if (surf->grey_type==1) dstc = GF_COL_G(_col);
709
0
          else dstc = GF_COL_B(_col);
710
711
0
          dst[x+surf->idx_g] = dstc;
712
0
          dst[x+surf->idx_a] = col_a;
713
0
        }
714
0
      }
715
0
      col++;
716
0
      x += surf->pitch_x;
717
0
    }
718
0
  }
719
0
}
720
721
GF_Err evg_surface_clear_alphagrey(GF_EVGSurface *surf, GF_IRect rc, GF_Color col)
722
0
{
723
0
  u8 *data, *data_o;
724
0
  u8 col_a, col_c;
725
0
  u32 x, y, w, h, sx, sy;
726
0
  s32 st;
727
0
  GF_EVGSurface *_this = (GF_EVGSurface *)surf;
728
0
  st = _this->pitch_y;
729
730
0
  col_a = GF_COL_A(col);
731
0
  if (surf->grey_type==0) col_c = GF_COL_R(col);
732
0
  else if (surf->grey_type==1) col_c = GF_COL_G(col);
733
0
  else col_c = GF_COL_B(col);
734
735
0
  h = rc.height;
736
0
  w = rc.width;
737
0
  sx = rc.x;
738
0
  sy = rc.y;
739
740
0
  data_o = NULL;
741
742
0
  for (y = 0; y < h; y++) {
743
0
    data = (u8 *) _this ->pixels + (sy+y)* st + _this->pitch_x*sx;
744
0
    if (!y) {
745
0
      data_o = data;
746
0
      for (x = 0; x < w; x++) {
747
0
        data[surf->idx_a] = col_c;
748
0
        data[surf->idx_g] = col_a;
749
0
        data += _this->pitch_x;
750
0
      }
751
0
    } else {
752
0
      memcpy(data, data_o, w*_this->BPP);
753
0
    }
754
0
  }
755
0
  return GF_OK;
756
0
}
757
758
#endif //GPAC_DISABLE_EVG