Get rid of sys/time.h
[helenos.git] / uspace / app / tetris / screen.c
blob0efac61e5cef0b50a03bc7ded577c98c8ad36c31
1 /*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** Attributations
31 * screen.c 8.1 (Berkeley) 5/31/93
32 * NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft
33 * OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray
35 * Based upon BSD Tetris
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California.
39 * Distributed under BSD license.
41 * This code is derived from software contributed to Berkeley by
42 * Chris Torek and Darren F. Provine.
46 /** @addtogroup tetris
47 * @{
49 /** @file
53 * Tetris screen control.
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <str.h>
59 #include <vfs/vfs.h>
60 #include <async.h>
61 #include <stdbool.h>
62 #include <io/console.h>
63 #include <io/style.h>
64 #include "screen.h"
65 #include "tetris.h"
67 #define STOP (B_COLS - 3)
69 static cell curscreen[B_SIZE]; /* non-zero => standout (or otherwise marked) */
70 static int curscore;
71 static int isset; /* true => terminal is in game mode */
73 static bool use_color; /* true => use colors */
75 static const struct shape *lastshape;
77 static usec_t timeleft = 0;
79 console_ctrl_t *console;
83 * putstr() is for unpadded strings (either as in termcap(5) or
84 * simply literal strings);
86 static inline void putstr(const char *s)
88 while (*s)
89 putchar(*(s++));
92 static void start_standout(uint32_t color)
94 console_flush(console);
95 console_set_rgb_color(console, use_color ? color : 0x000000,
96 0xffffff);
99 static void resume_normal(void)
101 console_flush(console);
102 console_set_style(console, STYLE_NORMAL);
105 void clear_screen(void)
107 console_clear(console);
108 moveto(0, 0);
112 * Clear the screen, forgetting the current contents in the process.
114 void scr_clear(void)
116 resume_normal();
117 console_clear(console);
118 curscore = -1;
119 memset(curscreen, 0, sizeof(curscreen));
123 * Set up screen
125 void scr_init(void)
127 console_cursor_visibility(console, 0);
128 resume_normal();
129 scr_clear();
132 void moveto(sysarg_t r, sysarg_t c)
134 console_flush(console);
135 console_set_pos(console, c, r);
138 winsize_t winsize;
140 static errno_t get_display_size(winsize_t *ws)
142 return console_get_size(console, &ws->ws_col, &ws->ws_row);
145 static bool get_display_color_sup(void)
147 sysarg_t ccap;
148 errno_t rc = console_get_color_cap(console, &ccap);
150 if (rc != EOK)
151 return false;
153 return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
157 * Set up screen mode.
159 void scr_set(void)
161 winsize_t ws;
163 Rows = 0;
164 Cols = 0;
166 if (get_display_size(&ws) == 0) {
167 Rows = ws.ws_row;
168 Cols = ws.ws_col;
171 use_color = get_display_color_sup();
173 if ((Rows < MINROWS) || (Cols < MINCOLS)) {
174 char smallscr[55];
176 snprintf(smallscr, sizeof(smallscr),
177 "the screen is too small (must be at least %dx%d)",
178 MINROWS, MINCOLS);
179 stop(smallscr);
181 isset = 1;
183 scr_clear();
187 * End screen mode.
189 void scr_end(void)
191 console_cursor_visibility(console, 1);
194 void stop(const char *why)
196 if (isset)
197 scr_end();
199 fprintf(stderr, "aborting: %s", why);
200 abort();
204 * Update the screen.
206 void scr_update(void)
208 cell *bp;
209 cell *sp;
210 cell so;
211 cell cur_so = 0;
212 int i;
213 int j;
214 int ccol;
216 /* Always leave cursor after last displayed point */
217 curscreen[D_LAST * B_COLS - 1] = -1;
219 if (score != curscore) {
220 moveto(0, 0);
221 printf("Score: %d", score);
222 curscore = score;
225 /* Draw preview of next pattern */
226 if ((showpreview) && (nextshape != lastshape)) {
227 int i;
228 static int r = 5, c = 2;
229 int tr, tc, t;
231 lastshape = nextshape;
233 /* Clean */
234 resume_normal();
235 moveto(r - 1, c - 1);
236 putstr(" ");
237 moveto(r, c - 1);
238 putstr(" ");
239 moveto(r + 1, c - 1);
240 putstr(" ");
241 moveto(r + 2, c - 1);
242 putstr(" ");
244 moveto(r - 3, c - 2);
245 putstr("Next shape:");
247 /* Draw */
248 start_standout(nextshape->color);
249 moveto(r, 2 * c);
250 putstr(" ");
251 for (i = 0; i < 3; i++) {
252 t = c + r * B_COLS;
253 t += nextshape->off[i];
255 tr = t / B_COLS;
256 tc = t % B_COLS;
258 moveto(tr, 2 * tc);
259 putstr(" ");
261 resume_normal();
264 bp = &board[D_FIRST * B_COLS];
265 sp = &curscreen[D_FIRST * B_COLS];
266 for (j = D_FIRST; j < D_LAST; j++) {
267 ccol = -1;
268 for (i = 0; i < B_COLS; bp++, sp++, i++) {
269 if (*sp == (so = *bp))
270 continue;
272 *sp = so;
273 if (i != ccol) {
274 if (cur_so) {
275 resume_normal();
276 cur_so = 0;
278 moveto(RTOD(j), CTOD(i));
281 if (so != cur_so) {
282 if (so)
283 start_standout(so);
284 else
285 resume_normal();
286 cur_so = so;
288 putstr(" ");
290 ccol = i + 1;
292 * Look ahead a bit, to avoid extra motion if
293 * we will be redrawing the cell after the next.
294 * Motion probably takes four or more characters,
295 * so we save even if we rewrite two cells
296 * `unnecessarily'. Skip it all, though, if
297 * the next cell is a different color.
300 if ((i > STOP) || (sp[1] != bp[1]) || (so != bp[1]))
301 continue;
303 if (sp[2] != bp[2])
304 sp[1] = -1;
305 else if ((i < STOP) && (so == bp[2]) && (sp[3] != bp[3])) {
306 sp[2] = -1;
307 sp[1] = -1;
312 if (cur_so)
313 resume_normal();
315 console_flush(console);
319 * Write a message (set != 0), or clear the same message (set == 0).
320 * (We need its length in case we have to overwrite with blanks.)
322 void scr_msg(char *s, bool set)
324 int l = str_size(s);
326 moveto(Rows - 2, ((Cols - l) >> 1) - 1);
328 if (set)
329 putstr(s);
330 else
331 while (--l >= 0)
332 (void) putchar(' ');
335 /** Sleep for the current turn time
337 * Eat any input that might be available.
340 void tsleep(void)
342 usec_t timeout = fallrate;
344 while (timeout > 0) {
345 cons_event_t event;
347 if (!console_get_event_timeout(console, &event, &timeout))
348 break;
352 /** Get char with timeout
355 int tgetchar(void)
358 * Reset timeleft to fallrate whenever it is not positive
359 * and increase speed.
362 if (timeleft <= 0) {
363 faster();
364 timeleft = fallrate;
368 * Wait to see if there is any input. If so, take it and
369 * update timeleft so that the next call to tgetchar()
370 * will not wait as long. If there is no input,
371 * make timeleft zero and return -1.
374 wchar_t c = 0;
376 while (c == 0) {
377 cons_event_t event;
379 if (!console_get_event_timeout(console, &event, &timeleft)) {
380 timeleft = 0;
381 return -1;
384 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
385 c = event.ev.key.c;
388 return (int) c;
391 /** Get char without timeout
394 int twait(void)
396 wchar_t c = 0;
398 while (c == 0) {
399 cons_event_t event;
401 if (!console_get_event(console, &event))
402 return -1;
404 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
405 c = event.ev.key.c;
408 return (int) c;
411 /** @}