source: mainline/uspace/dist/src/c/demos/tetris/screen.c@ 1d2f85e

Last change on this file since 1d2f85e was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29/** Attributations
30 *
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
34 *
35 * Based upon BSD Tetris
36 *
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California.
39 * Distributed under BSD license.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * Chris Torek and Darren F. Provine.
43 *
44 */
45
46/** @addtogroup tetris
47 * @{
48 */
49/** @file
50 */
51
52/*
53 * Tetris screen control.
54 */
55
56#include <err.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <str.h>
60#include <vfs/vfs.h>
61#include <async.h>
62#include <stdbool.h>
63#include <io/console.h>
64#include <io/style.h>
65#include "screen.h"
66#include "tetris.h"
67
68#define STOP (B_COLS - 3)
69
70static cell curscreen[B_SIZE]; /* non-zero => standout (or otherwise marked) */
71static int curscore;
72static int isset; /* true => terminal is in game mode */
73
74static bool use_color; /* true => use colors */
75
76static const struct shape *lastshape;
77
78static suseconds_t timeleft = 0;
79
80console_ctrl_t *console;
81
82/*
83 * putstr() is for unpadded strings (either as in termcap(5) or
84 * simply literal strings);
85 */
86static inline void putstr(const char *s)
87{
88 while (*s)
89 putchar(*(s++));
90}
91
92static void start_standout(uint32_t color)
93{
94 console_flush(console);
95 console_set_rgb_color(console, use_color ? color : 0x000000,
96 0xffffff);
97}
98
99static void resume_normal(void)
100{
101 console_flush(console);
102 console_set_style(console, STYLE_NORMAL);
103}
104
105void clear_screen(void)
106{
107 console_clear(console);
108 moveto(0, 0);
109}
110
111/*
112 * Clear the screen, forgetting the current contents in the process.
113 */
114void scr_clear(void)
115{
116 resume_normal();
117 console_clear(console);
118 curscore = -1;
119 memset(curscreen, 0, sizeof(curscreen));
120}
121
122/*
123 * Set up screen
124 */
125void scr_init(void)
126{
127 console_cursor_visibility(console, 0);
128 resume_normal();
129 scr_clear();
130}
131
132void moveto(sysarg_t r, sysarg_t c)
133{
134 console_flush(console);
135 console_set_pos(console, c, r);
136}
137
138winsize_t winsize;
139
140static int get_display_size(winsize_t *ws)
141{
142 return console_get_size(console, &ws->ws_col, &ws->ws_row);
143}
144
145static bool get_display_color_sup(void)
146{
147 sysarg_t ccap;
148 errno_t rc = console_get_color_cap(console, &ccap);
149
150 if (rc != EOK)
151 return false;
152
153 return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
154}
155
156/*
157 * Set up screen mode.
158 */
159void scr_set(void)
160{
161 winsize_t ws;
162
163 Rows = 0;
164 Cols = 0;
165
166 if (get_display_size(&ws) == 0) {
167 Rows = ws.ws_row;
168 Cols = ws.ws_col;
169 }
170
171 use_color = get_display_color_sup();
172
173 if ((Rows < MINROWS) || (Cols < MINCOLS)) {
174 char smallscr[55];
175
176 snprintf(smallscr, sizeof(smallscr),
177 "the screen is too small (must be at least %dx%d)",
178 MINROWS, MINCOLS);
179 stop(smallscr);
180 }
181 isset = 1;
182
183 scr_clear();
184}
185
186/*
187 * End screen mode.
188 */
189void scr_end(void)
190{
191 console_cursor_visibility(console, 1);
192}
193
194void stop(const char *why)
195{
196 if (isset)
197 scr_end();
198
199 errx(1, "aborting: %s", why);
200}
201
202/*
203 * Update the screen.
204 */
205void scr_update(void)
206{
207 cell *bp;
208 cell *sp;
209 cell so;
210 cell cur_so = 0;
211 int i;
212 int j;
213 int ccol;
214
215 /* Always leave cursor after last displayed point */
216 curscreen[D_LAST * B_COLS - 1] = -1;
217
218 if (score != curscore) {
219 moveto(0, 0);
220 printf("Score: %d", score);
221 curscore = score;
222 }
223
224 /* Draw preview of next pattern */
225 if ((showpreview) && (nextshape != lastshape)) {
226 int i;
227 static int r = 5, c = 2;
228 int tr, tc, t;
229
230 lastshape = nextshape;
231
232 /* Clean */
233 resume_normal();
234 moveto(r - 1, c - 1);
235 putstr(" ");
236 moveto(r, c - 1);
237 putstr(" ");
238 moveto(r + 1, c - 1);
239 putstr(" ");
240 moveto(r + 2, c - 1);
241 putstr(" ");
242
243 moveto(r - 3, c - 2);
244 putstr("Next shape:");
245
246 /* Draw */
247 start_standout(nextshape->color);
248 moveto(r, 2 * c);
249 putstr(" ");
250 for (i = 0; i < 3; i++) {
251 t = c + r * B_COLS;
252 t += nextshape->off[i];
253
254 tr = t / B_COLS;
255 tc = t % B_COLS;
256
257 moveto(tr, 2 * tc);
258 putstr(" ");
259 }
260 resume_normal();
261 }
262
263 bp = &board[D_FIRST * B_COLS];
264 sp = &curscreen[D_FIRST * B_COLS];
265 for (j = D_FIRST; j < D_LAST; j++) {
266 ccol = -1;
267 for (i = 0; i < B_COLS; bp++, sp++, i++) {
268 if (*sp == (so = *bp))
269 continue;
270
271 *sp = so;
272 if (i != ccol) {
273 if (cur_so) {
274 resume_normal();
275 cur_so = 0;
276 }
277 moveto(RTOD(j), CTOD(i));
278 }
279
280 if (so != cur_so) {
281 if (so)
282 start_standout(so);
283 else
284 resume_normal();
285 cur_so = so;
286 }
287 putstr(" ");
288
289 ccol = i + 1;
290 /*
291 * Look ahead a bit, to avoid extra motion if
292 * we will be redrawing the cell after the next.
293 * Motion probably takes four or more characters,
294 * so we save even if we rewrite two cells
295 * `unnecessarily'. Skip it all, though, if
296 * the next cell is a different color.
297 */
298
299 if ((i > STOP) || (sp[1] != bp[1]) || (so != bp[1]))
300 continue;
301
302 if (sp[2] != bp[2])
303 sp[1] = -1;
304 else if ((i < STOP) && (so == bp[2]) && (sp[3] != bp[3])) {
305 sp[2] = -1;
306 sp[1] = -1;
307 }
308 }
309 }
310
311 if (cur_so)
312 resume_normal();
313
314 console_flush(console);
315}
316
317/*
318 * Write a message (set != 0), or clear the same message (set == 0).
319 * (We need its length in case we have to overwrite with blanks.)
320 */
321void scr_msg(char *s, bool set)
322{
323 int l = str_bytes(s);
324
325 moveto(Rows - 2, ((Cols - l) >> 1) - 1);
326
327 if (set)
328 putstr(s);
329 else
330 while (--l >= 0)
331 (void) putchar(' ');
332}
333
334/** Sleep for the current turn time
335 *
336 * Eat any input that might be available.
337 *
338 */
339void tsleep(void)
340{
341 suseconds_t timeout = fallrate;
342
343 while (timeout > 0) {
344 cons_event_t event;
345
346 if (!console_get_event_timeout(console, &event, &timeout))
347 break;
348 }
349}
350
351/** Get char with timeout
352 *
353 */
354errno_t tgetchar(void)
355{
356 /*
357 * Reset timeleft to fallrate whenever it is not positive
358 * and increase speed.
359 */
360
361 if (timeleft <= 0) {
362 faster();
363 timeleft = fallrate;
364 }
365
366 /*
367 * Wait to see if there is any input. If so, take it and
368 * update timeleft so that the next call to tgetchar()
369 * will not wait as long. If there is no input,
370 * make timeleft zero and return -1.
371 */
372
373 wchar_t c = 0;
374
375 while (c == 0) {
376 cons_event_t event;
377
378 if (!console_get_event_timeout(console, &event, &timeleft)) {
379 timeleft = 0;
380 return -1;
381 }
382
383 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
384 c = event.ev.key.c;
385 }
386
387 return (int) c;
388}
389
390/** Get char without timeout
391 *
392 */
393errno_t twait(void)
394{
395 wchar_t c = 0;
396
397 while (c == 0) {
398 cons_event_t event;
399
400 if (!console_get_event(console, &event))
401 return -1;
402
403 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
404 c = event.ev.key.c;
405 }
406
407 return (int) c;
408}
409
410/** @}
411 */
Note: See TracBrowser for help on using the repository browser.