GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_4bpp_simple_line_draw.c Lines: 267 267 100.0 %
Date: 2024-12-05 08:52:37 Branches: 140 140 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** GUIX Component                                                        */
16
/**                                                                       */
17
/**   Display Management (Display)                                        */
18
/**                                                                       */
19
/**************************************************************************/
20
21
#define GX_SOURCE_CODE
22
23
24
/* Include necessary system files.  */
25
26
#include "gx_api.h"
27
#include "gx_utility.h"
28
#include "gx_display.h"
29
30
/**************************************************************************/
31
/*                                                                        */
32
/*  FUNCTION                                               RELEASE        */
33
/*                                                                        */
34
/*    _gx_display_driver_4bpp_simple_line_draw            PORTABLE C      */
35
/*                                                           6.1          */
36
/*  AUTHOR                                                                */
37
/*                                                                        */
38
/*    Kenneth Maxwell, Microsoft Corporation                              */
39
/*                                                                        */
40
/*  DESCRIPTION                                                           */
41
/*                                                                        */
42
/*    Simple line draw function for the 4bpp display driver.              */
43
/*                                                                        */
44
/*  INPUT                                                                 */
45
/*                                                                        */
46
/*    context                               Drawing context               */
47
/*    xstart                                x-coord of endpoint           */
48
/*    ystart                                y-coord of endpoint           */
49
/*    xend                                  x-coord of endpoint           */
50
/*    yend                                  y-coord of endpoint           */
51
/*                                                                        */
52
/*  OUTPUT                                                                */
53
/*                                                                        */
54
/*    None                                                                */
55
/*                                                                        */
56
/*  CALLS                                                                 */
57
/*                                                                        */
58
/*    GX_ABS                                Compute the absolute value    */
59
/*    GX_SWAP_VALUE                         Swap two values               */
60
/*                                                                        */
61
/*  CALLED BY                                                             */
62
/*                                                                        */
63
/*    GUIX Internal Code                                                  */
64
/*                                                                        */
65
/*  RELEASE HISTORY                                                       */
66
/*                                                                        */
67
/*    DATE              NAME                      DESCRIPTION             */
68
/*                                                                        */
69
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
70
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
71
/*                                            resulting in version 6.1    */
72
/*                                                                        */
73
/**************************************************************************/
74
61
VOID _gx_display_driver_4bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
75
{
76
77
/**************************************************************************/
78
/* Integer non-aliased line draw. This algorithm is taken directly from   */
79
/* Roger Stevens "The C++ graphics programming handbook" pages 281-282.   */
80
/* Removed the pattern test and renamed the variables and converted from  */
81
/* C++ to C. Also modified the algorithm to draw from both ends in to     */
82
/* the middle, instead of drawing from one end to the other.              */
83
/**************************************************************************/
84
85
INT           curx;
86
INT           cury;
87
INT           x_sign;
88
INT           y_sign;
89
INT           decision;
90
INT           nextx;
91
INT           nexty;
92
INT           y_increment;
93
GX_POINT      end_point;
94
GX_POINT      mid_point;
95
GX_RECTANGLE  half_rectangle;
96
GX_RECTANGLE  half_over;
97
INT           sign;
98
INT           steps;
99
INT           pos_start;
100
INT           pos_end;
101
GX_UBYTE      start_mask;
102
GX_UBYTE      end_mask;
103
GX_UBYTE     *start_address;
104
GX_UBYTE     *put;
105
GX_UBYTE     *next_put;
106
61
GX_BOOL       clipped = GX_TRUE;
107
61
INT           dx = GX_ABS(xend - xstart);
108
61
INT           dy = GX_ABS(yend - ystart);
109
110
61
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
111
61
GX_UBYTE      linecolor = context -> gx_draw_context_brush.gx_brush_line_color & 0x0f;
112
61
GX_UBYTE      color = linecolor;
113
INT           stride;
114
115


61
    if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
116
    {
117
29
        GX_SWAP_VALS(xend, xstart);
118
29
        GX_SWAP_VALS(yend, ystart);
119
    }
120
61
    x_sign = (xend - xstart) / dx;
121
61
    y_sign = (yend - ystart) / dy;
122
123
61
    if (y_sign > 0)
124
    {
125
46
        y_increment = context -> gx_draw_context_pitch;
126
    }
127
    else
128
    {
129
15
        y_increment = 0 - context -> gx_draw_context_pitch;
130
    }
131
132
61
    stride = (context -> gx_draw_context_pitch + 1) >> 1;
133
134
61
    start_address = (GX_UBYTE *)(context -> gx_draw_context_memory);
135
61
    pos_start = ystart * (stride << 1) + xstart;
136
61
    pos_end = yend * (stride << 1) + xend;
137
138
61
    end_point.gx_point_x = (GX_VALUE)xstart;
139
61
    end_point.gx_point_y = (GX_VALUE)ystart;
140
141
61
    if (_gx_utility_rectangle_point_detect(clip, end_point))
142
    {
143
34
        end_point.gx_point_x = (GX_VALUE)xend;
144
34
        end_point.gx_point_y = (GX_VALUE)yend;
145
146
34
        if (_gx_utility_rectangle_point_detect(clip, end_point))
147
        {
148
16
            clipped = GX_FALSE;
149
        }
150
    }
151
152
61
    if (clipped)
153
    {
154
        /* here if we must do clipping in the inner loop, because one
155
           or both of the end points are outside clipping rectangle */
156
157
        /* Calculate the middle point of the line.  */
158
45
        mid_point.gx_point_x = (GX_VALUE)((xend + xstart) >> 1);
159
45
        mid_point.gx_point_y = (GX_VALUE)((yend + ystart) >> 1);
160
161
        /* Judge the clip in which side.  */
162
45
        if (_gx_utility_rectangle_point_detect(clip, mid_point))
163
        {
164
165
            /* the clip in two sides.  */
166
24
            if (dx >= dy)
167
            {
168
                /* walk out the clipping point.  */
169
271
                for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
170
259
                     curx++, decision += dy)
171
                {
172
270
                    if (decision >= dx)
173
                    {
174
149
                        decision -= dx;
175
149
                        cury += y_sign;
176
177
149
                        pos_start += y_increment;
178
                    }
179
180
270
                    if (curx >= clip -> gx_rectangle_left &&
181
263
                        cury >= clip -> gx_rectangle_top &&
182
217
                        cury <= clip -> gx_rectangle_bottom)
183
                    {
184
11
                        break;
185
                    }
186
259
                    pos_start++;
187
                }
188
463
                for (; curx <= mid_point.gx_point_x;
189
451
                     curx++, decision += dy)
190
                {
191
451
                    if (decision >= dx)
192
                    {
193
243
                        decision -= dx;
194
243
                        cury += y_sign;
195
243
                        pos_start += y_increment;
196
                    }
197
451
                    put = start_address;
198
451
                    put += pos_start >> 1;
199
451
                    if (pos_start & 0x01)
200
                    {
201
228
                        start_mask = 0x0f;
202
228
                        color = linecolor;
203
                    }
204
                    else
205
                    {
206
223
                        start_mask = 0xf0;
207
223
                        color = (GX_UBYTE)(linecolor << 4);
208
                    }
209
451
                    *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
210
451
                    pos_start++;
211
                }
212
541
                for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
213
529
                     nextx--, decision += dy)
214
                {
215
540
                    if (decision >= dx)
216
                    {
217
303
                        decision -= dx;
218
303
                        nexty -= y_sign;
219
303
                        pos_end -= y_increment;
220
                    }
221
540
                    if (nextx <= clip -> gx_rectangle_right &&
222
48
                        nexty >= clip -> gx_rectangle_top &&
223
31
                        nexty <= clip -> gx_rectangle_bottom)
224
                    {
225
11
                        break;
226
                    }
227
529
                    pos_end--;
228
                }
229
230
182
                for (; nextx > mid_point.gx_point_x;
231
170
                     nextx--, decision += dy)
232
                {
233
170
                    if (decision >= dx)
234
                    {
235
79
                        decision -= dx;
236
79
                        nexty -= y_sign;
237
79
                        pos_end -= y_increment;
238
                    }
239
170
                    next_put = start_address;
240
170
                    next_put += pos_end >> 1;
241
170
                    if (pos_end & 0x01)
242
                    {
243
84
                        end_mask = 0x0f;
244
84
                        color = linecolor;
245
                    }
246
                    else
247
                    {
248
86
                        end_mask = 0xf0;
249
86
                        color = (GX_UBYTE)(linecolor << 4);
250
                    }
251
170
                    *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
252
170
                    pos_end--;
253
                }
254
            }
255
            else
256
            {
257
561
                for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
258
549
                     nexty--, decision += dx)
259
                {
260
560
                    if (decision >= dy)
261
                    {
262
304
                        decision -= dy;
263
304
                        nextx -= x_sign;
264
304
                        pos_end -= x_sign;
265
                    }
266
560
                    if (nextx >= clip -> gx_rectangle_left &&
267
519
                        nextx <= clip -> gx_rectangle_right &&
268
313
                        nexty <= clip -> gx_rectangle_bottom)
269
                    {
270
11
                        break;
271
                    }
272
549
                    pos_end -= context -> gx_draw_context_pitch;
273
                }
274
275
211
                for (; nexty > mid_point.gx_point_y;
276
199
                     nexty--, decision += dx)
277
                {
278
199
                    if (decision >= dy)
279
                    {
280
87
                        decision -= dy;
281
87
                        nextx -= x_sign;
282
87
                        pos_end -= x_sign;
283
                    }
284
199
                    next_put = start_address;
285
199
                    next_put += pos_end >> 1;
286
199
                    if (pos_end & 0x01)
287
                    {
288
91
                        end_mask = 0x0f;
289
91
                        color = linecolor;
290
                    }
291
                    else
292
                    {
293
108
                        end_mask = 0xf0;
294
108
                        color = (GX_UBYTE)(linecolor << 4);
295
                    }
296
199
                    *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
297
199
                    pos_end -= context -> gx_draw_context_pitch;
298
                }
299
300
                /* walk out the clipping point.  */
301
272
                for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
302
260
                     cury++, decision += dx)
303
                {
304
271
                    if (decision >= dy)
305
                    {
306
149
                        decision -= dy;
307
149
                        curx += x_sign;
308
149
                        pos_start += x_sign;
309
                    }
310
311
271
                    if (curx >= clip -> gx_rectangle_left &&
312
253
                        curx <= clip -> gx_rectangle_right &&
313
47
                        cury >= clip -> gx_rectangle_top)
314
                    {
315
11
                        break;
316
                    }
317
260
                    pos_start += context -> gx_draw_context_pitch;
318
                }
319
509
                for (; cury <= mid_point.gx_point_y;
320
497
                     cury++, decision += dx)
321
                {
322
497
                    if (decision >= dy)
323
                    {
324
250
                        decision -= dy;
325
250
                        curx += x_sign;
326
250
                        pos_start += x_sign;
327
                    }
328
497
                    put = start_address;
329
497
                    put += pos_start >> 1;
330
497
                    if (pos_start & 0x01)
331
                    {
332
241
                        start_mask = 0x0f;
333
241
                        color = linecolor;
334
                    }
335
                    else
336
                    {
337
256
                        start_mask = 0xf0;
338
256
                        color = (GX_UBYTE)(linecolor << 4);
339
                    }
340
497
                    *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
341
497
                    pos_start += context -> gx_draw_context_pitch;
342
                }
343
            }
344
        }
345
        else
346
        {
347
            /* The clip stay at one side.  */
348
21
            if (dx >= dy)
349
            {
350
11
                half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
351
11
                half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
352
11
                if (y_sign == 1)
353
                {
354
5
                    half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
355
5
                    half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
356
                }
357
                else
358
                {
359
6
                    half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
360
6
                    half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
361
                }
362
363
11
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
364
                {
365
7
                    curx = xstart;
366
7
                    cury = ystart;
367
7
                    steps = mid_point.gx_point_x - curx + 1;
368
7
                    sign = 1;
369
                }
370
                else
371
                {
372
4
                    curx = xend;
373
4
                    cury = yend;
374
4
                    steps = xend - mid_point.gx_point_x;
375
4
                    sign = -1;
376
4
                    y_increment = 0 - y_increment;
377
4
                    y_sign = 0 - y_sign;
378
4
                    pos_start = pos_end;
379
                }
380
951
                for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
381
                {
382
940
                    if (decision >= dx)
383
                    {
384
426
                        decision -= dx;
385
426
                        cury += y_sign;
386
426
                        pos_start += y_increment;
387
                    }
388
389
940
                    if (curx >= clip -> gx_rectangle_left &&
390
934
                        curx <= clip -> gx_rectangle_right &&
391
458
                        cury >= clip -> gx_rectangle_top &&
392
415
                        cury <= clip -> gx_rectangle_bottom)
393
                    {
394
399
                        put = start_address;
395
399
                        put += pos_start >> 1;
396
399
                        if (pos_start & 0x01)
397
                        {
398
198
                            start_mask = 0x0f;
399
198
                            color = linecolor;
400
                        }
401
                        else
402
                        {
403
201
                            start_mask = 0xf0;
404
201
                            color = (GX_UBYTE)(linecolor << 4);
405
                        }
406
399
                        *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
407
                    }
408
940
                    pos_start += sign;
409
                }
410
            }
411
            else
412
            {
413
10
                half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
414
10
                half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
415
10
                if (x_sign == 1)
416
                {
417
5
                    half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
418
5
                    half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
419
                }
420
                else
421
                {
422
5
                    half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
423
5
                    half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
424
                }
425
426
10
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
427
                {
428
5
                    curx = xstart;
429
5
                    cury = ystart;
430
5
                    steps = mid_point.gx_point_y - cury + 1;
431
5
                    y_increment = context -> gx_draw_context_pitch;
432
5
                    sign = 1;
433
                }
434
                else
435
                {
436
5
                    curx = xend;
437
5
                    cury = yend;
438
5
                    steps = yend - mid_point.gx_point_y;
439
5
                    sign = -1;
440
5
                    y_increment = 0 - context -> gx_draw_context_pitch;
441
5
                    x_sign = 0 - x_sign;
442
5
                    pos_start = pos_end;
443
                }
444
445
769
                for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
446
                {
447
759
                    if (decision >= dy)
448
                    {
449
402
                        decision -= dy;
450
402
                        curx += x_sign;
451
402
                        pos_start += x_sign;
452
                    }
453
759
                    if (curx >= clip -> gx_rectangle_left &&
454
754
                        curx <= clip -> gx_rectangle_right &&
455
650
                        cury >= clip -> gx_rectangle_top &&
456
614
                        cury <= clip -> gx_rectangle_bottom)
457
                    {
458
336
                        put = start_address;
459
336
                        put += pos_start >> 1;
460
336
                        if (pos_start & 0x01)
461
                        {
462
160
                            start_mask = 0x0f;
463
160
                            color = linecolor;
464
                        }
465
                        else
466
                        {
467
176
                            start_mask = 0xf0;
468
176
                            color = (GX_UBYTE)(linecolor << 4);
469
                        }
470
336
                        *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
471
                    }
472
759
                    pos_start += y_increment;
473
                }
474
            }
475
        }
476
    }
477
    else
478
    {
479
        /* here if both line ends lie within clipping rectangle, we can
480
           run a faster inner loop */
481
16
        if (dx >= dy)
482
        {
483
12
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
484
704
                 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
485
692
                 decision += dy)
486
            {
487
488
692
                if (decision >= dx)
489
                {
490
676
                    decision -= dx;
491
676
                    cury += y_sign;
492
676
                    nexty -= y_sign;
493
494
676
                    pos_start += y_increment;
495
676
                    pos_end -= y_increment;
496
                }
497
692
                put = start_address;
498
692
                put += pos_start >> 1;
499
692
                if (pos_start & 0x01)
500
                {
501
348
                    start_mask = 0x0f;
502
348
                    color = linecolor;
503
                }
504
                else
505
                {
506
344
                    start_mask = 0xf0;
507
344
                    color = (GX_UBYTE)(linecolor << 4);
508
                }
509
692
                *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
510
692
                next_put = start_address;
511
692
                next_put += pos_end >> 1;
512
692
                if (pos_end & 0x01)
513
                {
514
348
                    end_mask = 0x0f;
515
348
                    color = linecolor;
516
                }
517
                else
518
                {
519
344
                    end_mask = 0xf0;
520
344
                    color = (GX_UBYTE)(linecolor << 4);
521
                }
522
692
                *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
523
692
                pos_start++;
524
692
                pos_end--;
525
            }
526
        }
527
        else
528
        {
529
4
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
530
236
                 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
531
232
                 decision += dx)
532
            {
533
232
                if (decision >= dy)
534
                {
535
224
                    decision -= dy;
536
224
                    curx += x_sign;
537
224
                    nextx -= x_sign;
538
539
224
                    pos_start += x_sign;
540
224
                    pos_end -= x_sign;
541
                }
542
232
                put = start_address;
543
232
                put += pos_start >> 1;
544
232
                if (pos_start & 0x01)
545
                {
546
120
                    start_mask = 0x0f;
547
120
                    color = linecolor;
548
                }
549
                else
550
                {
551
112
                    start_mask = 0xf0;
552
112
                    color = (GX_UBYTE)(linecolor << 4);
553
                }
554
232
                *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
555
232
                next_put = start_address;
556
232
                next_put += pos_end >> 1;
557
232
                if (pos_end & 0x01)
558
                {
559
120
                    end_mask = 0x0f;
560
120
                    color = linecolor;
561
                }
562
                else
563
                {
564
112
                    end_mask = 0xf0;
565
112
                    color = (GX_UBYTE)(linecolor << 4);
566
                }
567
232
                *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
568
569
232
                pos_start += context -> gx_draw_context_pitch;
570
232
                pos_end -= context -> gx_draw_context_pitch;
571
            }
572
        }
573
    }
574
61
}
575