Skip to content

Commit 9d0950c

Browse files
calc84maniacmateoconlechuga
authored andcommitted
Fix and optimize clipping behavior for gfx_HorizLine and gfx_VertLine. Fixes #673
1 parent bc1ab5d commit 9d0950c

File tree

5 files changed

+199
-44
lines changed

5 files changed

+199
-44
lines changed

src/graphx/graphx.asm

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -779,13 +779,13 @@ gfx_FillRectangle_NoClip:
779779
; None
780780
ld iy, 0
781781
add iy, sp
782+
ld bc, (iy + 9) ; bc = width
783+
ld a, b
784+
or a, c
785+
ret z ; make sure width is not 0
782786
ld a, (iy + 12) ; a = height
783787
or a, a
784788
ret z ; make sure height is not 0
785-
ld bc, (iy + 9) ; bc = width
786-
sbc hl, hl
787-
adc hl, bc
788-
ret z ; make sure width is not 0
789789
ld hl, (iy + 3) ; hl = x coordinate
790790
ld e, (iy + 6) ; e = y coordinate
791791
_FillRectangle_NoClip:
@@ -894,13 +894,13 @@ gfx_Rectangle_NoClip:
894894
; None
895895
ld iy, 0
896896
add iy, sp
897+
ld bc, (iy + 9) ; bc = width
898+
ld a, b
899+
or a, c
900+
ret z ; abort if width == 0
897901
ld a, (iy + 12) ; a = height
898902
or a, a
899903
ret z ; abort if height == 0
900-
ld bc, (iy + 9) ; bc = width
901-
sbc hl, hl
902-
adc hl, bc
903-
ret z ; abort if width == 0
904904
push bc
905905
call _HorizLine_NoClip_NotDegen_StackXY ; draw top horizontal line
906906
; hl = &buf[y][x+width-1]
@@ -930,30 +930,22 @@ gfx_HorizLine:
930930
ld de, ti.lcdHeight
931931
smcWord _YMax
932932
sbc hl, de ; subtract maximum y
933-
ld de, ti.lcdHeight ; add y bounds span
933+
ld de, ti.lcdHeight
934934
smcWord _YSpan
935-
add hl, de
935+
add hl, de ; add y bounds span
936936
ret nc ; return if not within y bounds
937-
ld hl, (iy + 9)
938937
ld de, (iy + 3)
939-
add hl, de
940-
push hl
941938
ld hl, 0
942939
smcWord _XMin
943-
call _Maximum ; get minimum x
944-
ex (sp), hl
945-
ld de, ti.lcdWidth
946-
smcWord _XMax
947-
call _Minimum ; get maximum x
948-
pop de
949-
scf
950-
sbc hl, de
951-
ret c
952-
inc hl
953-
push hl
954-
pop bc ; bc = length
940+
ld bc, ti.lcdWidth
941+
smcWord _XSpan
942+
call _ClipInterval
955943
ex de, hl
956-
jr _HorizLine_NoClip_NotDegen_StackY
944+
; Check for empty interval
945+
ld a, b
946+
or a, c
947+
jr nz, _HorizLine_NoClip_NotDegen_StackY
948+
ret
957949

958950
;-------------------------------------------------------------------------------
959951
gfx_HorizLine_NoClip:
@@ -968,8 +960,8 @@ gfx_HorizLine_NoClip:
968960
add iy, sp
969961
ld bc, (iy + 9) ; bc = length
970962
_HorizLine_NoClip_StackXY:
971-
sbc hl, hl
972-
adc hl, bc
963+
ld a, b
964+
or a, c
973965
ret z ; abort if length == 0
974966
_HorizLine_NoClip_NotDegen_StackXY:
975967
ld hl, (iy + 3) ; hl = x
@@ -1015,23 +1007,14 @@ smcWord _XMax
10151007
smcWord _XSpan
10161008
add hl, de ; add x bounds span
10171009
ret nc ; return if not within x bounds
1018-
ld hl, (iy + 9)
10191010
ld de, (iy + 6)
1020-
add hl, de
1021-
push hl
10221011
ld hl, 0
10231012
smcWord _YMin
1024-
call _Maximum ; get minimum y
1025-
ex (sp), hl
1026-
ld de, ti.lcdHeight
1027-
smcWord _YMax
1028-
call _Minimum ; get maximum y
1029-
pop de
1030-
ld a, l
1031-
sub a, e
1032-
ret c ; return if not within y bounds
1033-
ld b, a
1034-
jr _VertLine_NoClip_MaybeDegen_StackX ; jump to unclipped version
1013+
ld bc, ti.lcdHeight
1014+
smcWord _YSpan
1015+
call _ClipInterval
1016+
ld b, c
1017+
jr _VertLine_NoClip_StackX ; jump to unclipped version
10351018

10361019
;-------------------------------------------------------------------------------
10371020
gfx_VertLine_NoClip:
@@ -1968,8 +1951,8 @@ gfx_FillCircle_NoClip:
19681951
lea hl, ix - 9
19691952
ld sp, hl
19701953
ld bc, (ix + 12)
1971-
sbc hl, hl
1972-
adc hl, bc ; carry won't be set since HL is zero here
1954+
ld a, c
1955+
or a, a
19731956
jr z, _FillCircle_NoClip.ResetStack
19741957
ld (ix - 6), bc
19751958
sbc hl, hl
@@ -6647,6 +6630,65 @@ _Minimum:
66476630
add hl, de
66486631
ret
66496632

6633+
;-------------------------------------------------------------------------------
6634+
_ClipInterval:
6635+
; Clips an interval represented as start, length
6636+
; Inputs:
6637+
; HL : Start of the clip region
6638+
; DE : Start of the interval to clip
6639+
; BC : Length of the clip region
6640+
; (IY+9) : Length of the interval to clip
6641+
; Carry flag is set
6642+
; Outputs:
6643+
; DE : Start of the clipped interval
6644+
; BC : Size of the clipped interval (less than or equal to input BC)
6645+
; Returns to the caller's caller if the interval is culled,
6646+
; but may return an empty interval in edge cases
6647+
; Reject negative-length intervals
6648+
bit 7, (iy + 11)
6649+
jr nz, .cull
6650+
; Check if the interval starts in the clip region [start, end),
6651+
; and calculate the length until the end of the clip region
6652+
; Carry flag is set
6653+
sbc hl, de
6654+
add hl, bc
6655+
inc hl
6656+
jr nc, .clip_start
6657+
ld bc, (iy + 9)
6658+
.clip_end:
6659+
; DE : clipped interval start
6660+
; BC : unclipped interval length
6661+
; HL : length until the end of the clip region
6662+
; Return the minimum of the two lengths in BC
6663+
or a, a
6664+
sbc hl, bc
6665+
ret nc
6666+
add hl, bc
6667+
push hl
6668+
pop bc
6669+
ret
6670+
6671+
.clip_start:
6672+
; Restore the original coordinates and swap them
6673+
; Carry flag is clear
6674+
sbc hl, bc
6675+
add hl, de
6676+
ex de, hl
6677+
; Check if the clip region starts inside the interval (start, end],
6678+
; and calculate the length until the end of the interval
6679+
or a, a
6680+
sbc hl, de
6681+
push bc
6682+
ld bc, (iy + 9)
6683+
add hl, bc
6684+
pop bc
6685+
jr c, .clip_end
6686+
.cull:
6687+
; Return to the caller's caller
6688+
pop bc
6689+
ret
6690+
6691+
66506692
;-------------------------------------------------------------------------------
66516693
_ClipRegion:
66526694
; Calculates the new coordinates given the clip and inputs

test/issues/673/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
obj/
2+
bin/
3+
src/gfx/*.c
4+
src/gfx/*.h
5+
src/gfx/*.8xv
6+
.DS_Store
7+
convimg.yaml.lst

test/issues/673/autotest.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"transfer_files":
3+
[
4+
"bin/DEMO.8xp"
5+
],
6+
"target":
7+
{
8+
"name": "DEMO",
9+
"isASM": true
10+
},
11+
"sequence":
12+
[
13+
"action|launch",
14+
"delay|100",
15+
"hashWait|1",
16+
"key|enter",
17+
"hashWait|2"
18+
],
19+
"hashes":
20+
{
21+
"1":
22+
{
23+
"description": "Test line clipping",
24+
"start": "vram_start",
25+
"size": "vram_16_size",
26+
"expected_CRCs": [ "045155B1" ]
27+
},
28+
"2":
29+
{
30+
"description": "Test program exit",
31+
"start": "vram_start",
32+
"size": "vram_16_size",
33+
"expected_CRCs": [ "FFAF89BA", "101734A5", "9DA19F44", "A32840C8", "349F4775" ]
34+
}
35+
}
36+
}

test/issues/673/makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ----------------------------
2+
# Makefile Options
3+
# ----------------------------
4+
5+
NAME = DEMO
6+
ICON = icon.png
7+
DESCRIPTION = "CE C Toolchain Demo"
8+
COMPRESSED = NO
9+
10+
CFLAGS = -Wall -Wextra -Oz
11+
CXXFLAGS = -Wall -Wextra -Oz
12+
13+
# ----------------------------
14+
15+
include $(shell cedev-config --makefile)

test/issues/673/src/main.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <ti/getcsc.h>
2+
#include <graphx.h>
3+
#include <limits.h>
4+
5+
static const int test_params[][2] =
6+
{
7+
{ 0, 200 },
8+
{ 50, 256 },
9+
{ 100, 220 },
10+
{ -1, 201 },
11+
{ 100, 221 },
12+
{ 150, INT_MAX },
13+
{ -20, INT_MAX },
14+
{ -40, 20 },
15+
{ -40, 40 },
16+
{ -40, 41 },
17+
{ -40, 400 },
18+
{ 320, 50 },
19+
{ 319, 51 },
20+
{ -1, 0 },
21+
{ 0, 0 },
22+
{ 319, 0 },
23+
{ 320, 0 },
24+
{ 50, -1 },
25+
{ 100, INT_MIN },
26+
};
27+
28+
static const int clip_regions[4][2] = {
29+
{ 0, 320 },
30+
{ 80, 220 },
31+
{ 50, 101 },
32+
{ 149, 319 },
33+
};
34+
35+
int main(void)
36+
{
37+
gfx_Begin();
38+
39+
for (int j = 0; j < 4; j++)
40+
{
41+
gfx_SetClipRegion(clip_regions[j][0], 0, clip_regions[j][1], 240);
42+
43+
for (int i = 0; i < (int)(sizeof(test_params) / sizeof(test_params[0])); i++)
44+
{
45+
gfx_SetColor(i);
46+
gfx_HorizLine(test_params[i][0], j * 60 + i * 2 + 1, test_params[i][1]);
47+
}
48+
}
49+
50+
while (!os_GetCSC());
51+
52+
gfx_End();
53+
54+
return 0;
55+
}

0 commit comments

Comments
 (0)