1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../../SDL_internal.h" |
22 | |
23 | #if SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED |
24 | |
25 | #include "SDL_draw.h" |
26 | #include "SDL_drawline.h" |
27 | #include "SDL_drawpoint.h" |
28 | |
29 | |
30 | static void |
31 | SDL_DrawLine1(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color, |
32 | SDL_bool draw_end) |
33 | { |
34 | if (y1 == y2) { |
35 | int length; |
36 | int pitch = (dst->pitch / dst->format->BytesPerPixel); |
37 | Uint8 *pixel; |
38 | if (x1 <= x2) { |
39 | pixel = (Uint8 *)dst->pixels + y1 * pitch + x1; |
40 | length = draw_end ? (x2-x1+1) : (x2-x1); |
41 | } else { |
42 | pixel = (Uint8 *)dst->pixels + y1 * pitch + x2; |
43 | if (!draw_end) { |
44 | ++pixel; |
45 | } |
46 | length = draw_end ? (x1-x2+1) : (x1-x2); |
47 | } |
48 | SDL_memset(pixel, color, length); |
49 | } else if (x1 == x2) { |
50 | VLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end); |
51 | } else if (ABS(x1 - x2) == ABS(y1 - y2)) { |
52 | DLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end); |
53 | } else { |
54 | BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end); |
55 | } |
56 | } |
57 | |
58 | static void |
59 | SDL_DrawLine2(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color, |
60 | SDL_bool draw_end) |
61 | { |
62 | if (y1 == y2) { |
63 | HLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); |
64 | } else if (x1 == x2) { |
65 | VLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); |
66 | } else if (ABS(x1 - x2) == ABS(y1 - y2)) { |
67 | DLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); |
68 | } else { |
69 | Uint8 _r, _g, _b, _a; |
70 | const SDL_PixelFormat * fmt = dst->format; |
71 | SDL_GetRGBA(color, fmt, &_r, &_g, &_b, &_a); |
72 | if (fmt->Rmask == 0x7C00) { |
73 | AALINE(x1, y1, x2, y2, |
74 | DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB555, |
75 | draw_end); |
76 | } else if (fmt->Rmask == 0xF800) { |
77 | AALINE(x1, y1, x2, y2, |
78 | DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565, |
79 | draw_end); |
80 | } else { |
81 | AALINE(x1, y1, x2, y2, |
82 | DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY2_BLEND_RGB, |
83 | draw_end); |
84 | } |
85 | } |
86 | } |
87 | |
88 | static void |
89 | SDL_DrawLine4(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color, |
90 | SDL_bool draw_end) |
91 | { |
92 | if (y1 == y2) { |
93 | HLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); |
94 | } else if (x1 == x2) { |
95 | VLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); |
96 | } else if (ABS(x1 - x2) == ABS(y1 - y2)) { |
97 | DLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); |
98 | } else { |
99 | Uint8 _r, _g, _b, _a; |
100 | const SDL_PixelFormat * fmt = dst->format; |
101 | SDL_GetRGBA(color, fmt, &_r, &_g, &_b, &_a); |
102 | if (fmt->Rmask == 0x00FF0000) { |
103 | if (!fmt->Amask) { |
104 | AALINE(x1, y1, x2, y2, |
105 | DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_RGB888, |
106 | draw_end); |
107 | } else { |
108 | AALINE(x1, y1, x2, y2, |
109 | DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888, |
110 | draw_end); |
111 | } |
112 | } else { |
113 | AALINE(x1, y1, x2, y2, |
114 | DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY4_BLEND_RGB, |
115 | draw_end); |
116 | } |
117 | } |
118 | } |
119 | |
120 | typedef void (*DrawLineFunc) (SDL_Surface * dst, |
121 | int x1, int y1, int x2, int y2, |
122 | Uint32 color, SDL_bool draw_end); |
123 | |
124 | static DrawLineFunc |
125 | SDL_CalculateDrawLineFunc(const SDL_PixelFormat * fmt) |
126 | { |
127 | switch (fmt->BytesPerPixel) { |
128 | case 1: |
129 | if (fmt->BitsPerPixel < 8) { |
130 | break; |
131 | } |
132 | return SDL_DrawLine1; |
133 | case 2: |
134 | return SDL_DrawLine2; |
135 | case 4: |
136 | return SDL_DrawLine4; |
137 | } |
138 | return NULL; |
139 | } |
140 | |
141 | int |
142 | SDL_DrawLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color) |
143 | { |
144 | DrawLineFunc func; |
145 | |
146 | if (!dst) { |
147 | return SDL_SetError("SDL_DrawLine(): Passed NULL destination surface" ); |
148 | } |
149 | |
150 | func = SDL_CalculateDrawLineFunc(dst->format); |
151 | if (!func) { |
152 | return SDL_SetError("SDL_DrawLine(): Unsupported surface format" ); |
153 | } |
154 | |
155 | /* Perform clipping */ |
156 | /* FIXME: We don't actually want to clip, as it may change line slope */ |
157 | if (!SDL_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) { |
158 | return 0; |
159 | } |
160 | |
161 | func(dst, x1, y1, x2, y2, color, SDL_TRUE); |
162 | return 0; |
163 | } |
164 | |
165 | int |
166 | SDL_DrawLines(SDL_Surface * dst, const SDL_Point * points, int count, |
167 | Uint32 color) |
168 | { |
169 | int i; |
170 | int x1, y1; |
171 | int x2, y2; |
172 | SDL_bool draw_end; |
173 | DrawLineFunc func; |
174 | |
175 | if (!dst) { |
176 | return SDL_SetError("SDL_DrawLines(): Passed NULL destination surface" ); |
177 | } |
178 | |
179 | func = SDL_CalculateDrawLineFunc(dst->format); |
180 | if (!func) { |
181 | return SDL_SetError("SDL_DrawLines(): Unsupported surface format" ); |
182 | } |
183 | |
184 | for (i = 1; i < count; ++i) { |
185 | x1 = points[i-1].x; |
186 | y1 = points[i-1].y; |
187 | x2 = points[i].x; |
188 | y2 = points[i].y; |
189 | |
190 | /* Perform clipping */ |
191 | /* FIXME: We don't actually want to clip, as it may change line slope */ |
192 | if (!SDL_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) { |
193 | continue; |
194 | } |
195 | |
196 | /* Draw the end if it was clipped */ |
197 | draw_end = (x2 != points[i].x || y2 != points[i].y); |
198 | |
199 | func(dst, x1, y1, x2, y2, color, draw_end); |
200 | } |
201 | if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) { |
202 | SDL_DrawPoint(dst, points[count-1].x, points[count-1].y, color); |
203 | } |
204 | return 0; |
205 | } |
206 | |
207 | #endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ |
208 | |
209 | /* vi: set ts=4 sw=4 expandtab: */ |
210 | |