1 /*  DreamChess
2 **
3 **  DreamChess is the legal property of its developers, whose names are too
4 **  numerous to list here. Please refer to the AUTHORS.txt file distributed
5 **  with this source distribution.
6 **
7 **  This program is free software: you can redistribute it and/or modify
8 **  it under the terms of the GNU General Public License as published by
9 **  the Free Software Foundation, either version 3 of the License, or
10 **  (at your option) any later version.
11 **
12 **  This program is distributed in the hope that it will be useful,
13 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **  GNU General Public License for more details.
16 **
17 **  You should have received a copy of the GNU General Public License
18 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <gamegui/clipping.h>
26 #include <gamegui/signal.h>
27 #include <gamegui/system.h>
28 #include <gamegui/widget.h>
29 
30 static int classes = 0;
31 static gg_class_id *parent_class = NULL;
32 static gg_driver_t *driver;
33 
gg_register_class(gg_class_id parent)34 gg_class_id gg_register_class(gg_class_id parent) {
35 	parent_class = realloc(parent_class, (classes + 1) * sizeof(gg_class_id));
36 
37 	parent_class[classes] = parent;
38 
39 	return classes++;
40 }
41 
gg_is_parent(gg_class_id parent,gg_class_id child)42 int gg_is_parent(gg_class_id parent, gg_class_id child) {
43 	child = parent_class[child];
44 
45 	while ((child != GG_CLASS_ID_NONE) && (parent != child))
46 		child = parent_class[child];
47 
48 	if (child == GG_CLASS_ID_NONE)
49 		return 0;
50 
51 	return 1;
52 }
53 
gg_check_cast(gg_widget_t * widget,gg_class_id id,char * file,int line,char * type)54 gg_widget_t *gg_check_cast(gg_widget_t *widget, gg_class_id id, char *file, int line, char *type) {
55 	if (!widget) {
56 		fprintf(stderr, "Fatal error (%s:L%d): Widget is NULL.\n", file, line);
57 		exit(1);
58 	}
59 
60 	if ((widget->id != id) && !gg_is_parent(id, widget->id)) {
61 		fprintf(stderr, "Fatal error (%s:L%d): Widget is not of type %s.\n", file, line, type);
62 		exit(1);
63 	}
64 
65 	return widget;
66 }
67 
gg_system_init(gg_driver_t * d)68 void gg_system_init(gg_driver_t *d) {
69 	driver = d;
70 	gg_signal_init();
71 }
72 
73 /* FIXME */
74 void gg_dialog_close_all(void);
75 void gg_dialog_cleanup(void);
76 
gg_system_exit(void)77 void gg_system_exit(void) {
78 	gg_dialog_close_all();
79 	gg_dialog_cleanup();
80 
81 	gg_signal_exit();
82 
83 	if (parent_class)
84 		free(parent_class);
85 }
86 
gg_system_get_ticks(void)87 unsigned int gg_system_get_ticks(void) {
88 	return driver->get_ticks();
89 }
90 
gg_system_get_screen_width(void)91 float gg_system_get_screen_width(void) {
92 	return driver->get_screen_width();
93 }
94 
gg_system_draw_rect(int x,int y,int width,int height,gg_colour_t * colour)95 void gg_system_draw_rect(int x, int y, int width, int height, gg_colour_t *colour) {
96 	gg_rect_t dest;
97 	dest.x = x;
98 	dest.y = y;
99 	dest.width = width;
100 	dest.height = 1;
101 	gg_system_draw_filled_rect(dest.x, dest.y, dest.width, dest.height, colour);
102 	dest.y += height - 1;
103 	gg_system_draw_filled_rect(dest.x, dest.y, dest.width, dest.height, colour);
104 	dest.y = y + 1;
105 	dest.width = 1;
106 	dest.height = height - 2;
107 	gg_system_draw_filled_rect(dest.x, dest.y, dest.width, dest.height, colour);
108 	dest.x += width - 1;
109 	gg_system_draw_filled_rect(dest.x, dest.y, dest.width, dest.height, colour);
110 }
111 
gg_system_draw_filled_rect(int x,int y,int width,int height,gg_colour_t * colour)112 void gg_system_draw_filled_rect(int x, int y, int width, int height, gg_colour_t *colour) {
113 	gg_rect_t *clip = gg_clipping_get();
114 
115 	if (clip) {
116 		gg_rect_t dest, dest_c;
117 		dest.x = x;
118 		dest.y = y;
119 		dest.width = width;
120 		dest.height = height;
121 		dest_c = gg_clipping_rect(&dest, clip);
122 		driver->draw_filled_rect(dest_c.x, dest_c.y, dest_c.width, dest_c.height, colour);
123 	} else
124 		driver->draw_filled_rect(x, y, width, height, colour);
125 }
126 
gg_system_draw_gradient_rect(int x,int y,int width,int height,gg_colour_t * top_left,gg_colour_t * top_right,gg_colour_t * bottom_left,gg_colour_t * bottom_right)127 void gg_system_draw_gradient_rect(int x, int y, int width, int height, gg_colour_t *top_left, gg_colour_t *top_right,
128 								  gg_colour_t *bottom_left, gg_colour_t *bottom_right) {
129 	gg_rect_t *clip = gg_clipping_get();
130 
131 	if (clip) {
132 		gg_rect_t dest, dest_c;
133 		dest.x = x;
134 		dest.y = y;
135 		dest.width = width;
136 		dest.height = height;
137 		dest_c = gg_clipping_rect(&dest, clip);
138 		driver->draw_gradient_rect(dest_c.x, dest_c.y, dest_c.width, dest_c.height, top_left, top_right, bottom_left,
139 								   bottom_right);
140 	} else
141 		driver->draw_gradient_rect(x, y, width, height, top_left, top_right, bottom_left, bottom_right);
142 }
143 
gg_system_draw_image(void * image,gg_rect_t source,gg_rect_t dest,int mode_h,int mode_v,gg_colour_t * colour)144 void gg_system_draw_image(void *image, gg_rect_t source, gg_rect_t dest, int mode_h, int mode_v, gg_colour_t *colour) {
145 	gg_rect_t *clip = gg_clipping_get();
146 
147 	if (clip) {
148 		gg_rect_t dest_c;
149 		gg_rect_t source_c;
150 		int x_offset;
151 		int y_offset;
152 
153 		dest_c = gg_clipping_rect(&dest, clip);
154 		x_offset = dest_c.x - dest.x;
155 		y_offset = dest.y + dest.height - dest_c.y - dest_c.height;
156 
157 		if (mode_h == GG_MODE_SCALE) {
158 			/* Magnification factor. */
159 			float x_mag = dest.width / (float)source.width;
160 
161 			source_c.x = source.x + x_offset / x_mag;
162 			source_c.width = dest_c.width / x_mag;
163 		} else {
164 			source_c.x = source.x + x_offset % source.width;
165 			/* Width is undefined for GG_MODE_TILE. */
166 		}
167 
168 		if (mode_v == GG_MODE_SCALE) {
169 			/* Magnification factor. */
170 			float y_mag = dest.height / (float)source.height;
171 
172 			source_c.y = source.y + y_offset / y_mag;
173 			source_c.height = dest_c.height / y_mag;
174 		} else {
175 			source_c.y = source.y + y_offset % source.height;
176 			/* Height is undefined for GG_MODE_TILE. */
177 		}
178 
179 		driver->draw_image(image, source_c, dest_c, mode_h, mode_v, colour);
180 	} else
181 		driver->draw_image(image, source, dest, mode_h, mode_v, colour);
182 }
183 
gg_system_draw_char(int c,int x,int y,gg_colour_t * colour)184 void gg_system_draw_char(int c, int x, int y, gg_colour_t *colour) {
185 	driver->draw_char(c, x, y, colour);
186 }
187 
gg_system_get_image_size(void * image,int * width,int * height)188 void gg_system_get_image_size(void *image, int *width, int *height) {
189 	driver->get_image_size(image, width, height);
190 }
191 
gg_system_get_char_size(int c,int * width,int * height)192 void gg_system_get_char_size(int c, int *width, int *height) {
193 	driver->get_char_size(c, width, height);
194 }
195 
gg_system_get_string_size(char * s,int * width,int * height)196 void gg_system_get_string_size(char *s, int *width, int *height) {
197 	int i;
198 
199 	if (width)
200 		*width = 0;
201 	if (height)
202 		*height = 0;
203 
204 	for (i = 0; i < strlen(s); i++) {
205 		int c_width, c_height;
206 		driver->get_char_size(s[i], &c_width, &c_height);
207 
208 		if (width)
209 			*width += c_width;
210 		if (height && (c_height > *height))
211 			*height = c_height;
212 	}
213 }
214 
gg_system_draw_string(char * s,int x,int y,gg_colour_t * colour,int bounce,float align)215 void gg_system_draw_string(char *s, int x, int y, gg_colour_t *colour, int bounce, float align) {
216 	int i;
217 	unsigned int ticks = gg_system_get_ticks();
218 	gg_rect_t rect_d;
219 	rect_d.x = x;
220 
221 	if (align != 0.0f) {
222 		int width;
223 
224 		gg_system_get_string_size(s, &width, NULL);
225 
226 		rect_d.x -= width * align;
227 	}
228 
229 	for (i = 0; i < strlen((char *)s); i++) {
230 		int y_off = 0;
231 		void *image = driver->get_char_image(s[i]);
232 		gg_rect_t rect_s = {0, 0};
233 		gg_colour_t col_black = {0.0f, 0.0f, 0.0f, 1.0f};
234 
235 		if (bounce) {
236 			float phase = ((ticks % (1000 / GG_BOUNCE_SPEED)) / (float)(1000 / GG_BOUNCE_SPEED));
237 
238 			if (phase < 0.5)
239 				y_off = phase * 2 * (GG_BOUNCE_AMP + 1);
240 			else
241 				y_off = ((1.0 - phase) * 2) * (GG_BOUNCE_AMP + 1);
242 		}
243 
244 		gg_system_get_image_size(image, &rect_s.width, &rect_s.height);
245 		rect_d.width = rect_s.width;
246 		rect_d.height = rect_s.height;
247 		rect_d.y = y + y_off;
248 
249 		/* FIXME */
250 		rect_d.x += 1;
251 		rect_d.y -= 1;
252 
253 		/* FIXME  Magic alpha value to turn off shadow */
254 		if (colour->a != 2.0f)
255 			gg_system_draw_image(image, rect_s, rect_d, GG_MODE_SCALE, GG_MODE_SCALE, &col_black);
256 		rect_d.x -= 1;
257 		rect_d.y += 1;
258 
259 		gg_system_draw_image(image, rect_s, rect_d, GG_MODE_SCALE, GG_MODE_SCALE, colour);
260 
261 		rect_d.x += rect_s.width;
262 
263 		ticks += 1000 / GG_BOUNCE_SPEED / GG_BOUNCE_LEN;
264 	}
265 }
266 
gg_colour(float r,float g,float b,float a)267 gg_colour_t gg_colour(float r, float g, float b, float a) {
268 	gg_colour_t col;
269 
270 	col.r = r;
271 	col.g = g;
272 	col.b = b;
273 	col.a = a;
274 
275 	return col;
276 }
277 
gg_rect(int x,int y,int w,int h)278 gg_rect_t gg_rect(int x, int y, int w, int h) {
279 	gg_rect_t rect;
280 
281 	rect.x = x;
282 	rect.y = y;
283 	rect.width = w;
284 	rect.height = h;
285 
286 	return rect;
287 }
288