source: mainline/uspace/app/tetris/screen.c@ 901b302

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 901b302 was e116461, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Fix EGA color support in Tetris

  • Property mode set to 100644
File size: 8.5 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 <errno.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_rgb; /* true => use RGB colors */
75static bool use_color; /* true => use indexed colors */
76
77static const struct shape *lastshape;
78
79static usec_t timeleft = 0;
80
81console_ctrl_t *console;
82
83/*
84 * putstr() is for unpadded strings (either as in termcap(5) or
85 * simply literal strings);
86 */
87static inline void putstr(const char *s)
88{
89 while (*s)
90 putchar(*(s++));
91}
92
93static void start_standout(uint32_t color)
94{
95 uint8_t bg;
96 uint8_t attr;
97
98 console_flush(console);
99 if (use_rgb) {
100 console_set_rgb_color(console, color, 0xffffff);
101 } else if (use_color) {
102 bg = 0x00;
103 attr = 0;
104 if ((color & 0xff0000) != 0)
105 bg |= 0x4;
106 if ((color & 0x00ff00) != 0)
107 bg |= 0x2;
108 if ((color & 0x0000ff) != 0)
109 bg |= 0x1;
110 console_set_color(console, bg, 0x00, attr);
111 }
112}
113
114static void resume_normal(void)
115{
116 console_flush(console);
117 console_set_style(console, STYLE_NORMAL);
118}
119
120void clear_screen(void)
121{
122 console_clear(console);
123 moveto(0, 0);
124}
125
126/*
127 * Clear the screen, forgetting the current contents in the process.
128 */
129void scr_clear(void)
130{
131 resume_normal();
132 console_clear(console);
133 curscore = -1;
134 memset(curscreen, 0, sizeof(curscreen));
135}
136
137/*
138 * Set up screen
139 */
140void scr_init(void)
141{
142 console_cursor_visibility(console, 0);
143 resume_normal();
144 scr_clear();
145}
146
147void moveto(sysarg_t r, sysarg_t c)
148{
149 console_flush(console);
150 console_set_pos(console, c, r);
151}
152
153winsize_t winsize;
154
155static errno_t get_display_size(winsize_t *ws)
156{
157 return console_get_size(console, &ws->ws_col, &ws->ws_row);
158}
159
160static void get_display_color_sup(bool *rgb, bool *color)
161{
162 sysarg_t ccap;
163 errno_t rc = console_get_color_cap(console, &ccap);
164
165 if (rc != EOK) {
166 *rgb = false;
167 *color = false;
168 return;
169 }
170
171 *rgb = ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
172 *color = ((ccap & CONSOLE_CAP_INDEXED) == CONSOLE_CAP_INDEXED);
173}
174
175/*
176 * Set up screen mode.
177 */
178void scr_set(void)
179{
180 winsize_t ws;
181
182 Rows = 0;
183 Cols = 0;
184
185 if (get_display_size(&ws) == 0) {
186 Rows = ws.ws_row;
187 Cols = ws.ws_col;
188 }
189
190 get_display_color_sup(&use_rgb, &use_color);
191
192 if ((Rows < MINROWS) || (Cols < MINCOLS)) {
193 char smallscr[55];
194
195 snprintf(smallscr, sizeof(smallscr),
196 "the screen is too small (must be at least %dx%d)",
197 MINROWS, MINCOLS);
198 stop(smallscr);
199 }
200 isset = 1;
201
202 scr_clear();
203}
204
205/*
206 * End screen mode.
207 */
208void scr_end(void)
209{
210 console_cursor_visibility(console, 1);
211}
212
213void stop(const char *why)
214{
215 if (isset)
216 scr_end();
217
218 fprintf(stderr, "aborting: %s", why);
219 abort();
220}
221
222/*
223 * Update the screen.
224 */
225void scr_update(void)
226{
227 cell *bp;
228 cell *sp;
229 cell so;
230 cell cur_so = 0;
231 int i;
232 int j;
233 int ccol;
234
235 /* Always leave cursor after last displayed point */
236 curscreen[D_LAST * B_COLS - 1] = -1;
237
238 if (score != curscore) {
239 moveto(0, 0);
240 printf("Score: %d", score);
241 curscore = score;
242 }
243
244 /* Draw preview of next pattern */
245 if ((showpreview) && (nextshape != lastshape)) {
246 int i;
247 static int r = 5, c = 2;
248 int tr, tc, t;
249
250 lastshape = nextshape;
251
252 /* Clean */
253 resume_normal();
254 moveto(r - 1, c - 1);
255 putstr(" ");
256 moveto(r, c - 1);
257 putstr(" ");
258 moveto(r + 1, c - 1);
259 putstr(" ");
260 moveto(r + 2, c - 1);
261 putstr(" ");
262
263 moveto(r - 3, c - 2);
264 putstr("Next shape:");
265
266 /* Draw */
267 start_standout(nextshape->color);
268 moveto(r, 2 * c);
269 putstr(" ");
270 for (i = 0; i < 3; i++) {
271 t = c + r * B_COLS;
272 t += nextshape->off[i];
273
274 tr = t / B_COLS;
275 tc = t % B_COLS;
276
277 moveto(tr, 2 * tc);
278 putstr(" ");
279 }
280 resume_normal();
281 }
282
283 bp = &board[D_FIRST * B_COLS];
284 sp = &curscreen[D_FIRST * B_COLS];
285 for (j = D_FIRST; j < D_LAST; j++) {
286 ccol = -1;
287 for (i = 0; i < B_COLS; bp++, sp++, i++) {
288 if (*sp == (so = *bp))
289 continue;
290
291 *sp = so;
292 if (i != ccol) {
293 if (cur_so) {
294 resume_normal();
295 cur_so = 0;
296 }
297 moveto(RTOD(j), CTOD(i));
298 }
299
300 if (so != cur_so) {
301 if (so)
302 start_standout(so);
303 else
304 resume_normal();
305 cur_so = so;
306 }
307 putstr(" ");
308
309 ccol = i + 1;
310 /*
311 * Look ahead a bit, to avoid extra motion if
312 * we will be redrawing the cell after the next.
313 * Motion probably takes four or more characters,
314 * so we save even if we rewrite two cells
315 * `unnecessarily'. Skip it all, though, if
316 * the next cell is a different color.
317 */
318
319 if ((i > STOP) || (sp[1] != bp[1]) || (so != bp[1]))
320 continue;
321
322 if (sp[2] != bp[2])
323 sp[1] = -1;
324 else if ((i < STOP) && (so == bp[2]) && (sp[3] != bp[3])) {
325 sp[2] = -1;
326 sp[1] = -1;
327 }
328 }
329 }
330
331 if (cur_so)
332 resume_normal();
333
334 console_flush(console);
335}
336
337/*
338 * Write a message (set != 0), or clear the same message (set == 0).
339 * (We need its length in case we have to overwrite with blanks.)
340 */
341void scr_msg(char *s, bool set)
342{
343 int l = str_size(s);
344
345 moveto(Rows - 2, ((Cols - l) >> 1) - 1);
346
347 if (set)
348 putstr(s);
349 else
350 while (--l >= 0)
351 (void) putchar(' ');
352}
353
354/** Sleep for the current turn time
355 *
356 * Eat any input that might be available.
357 *
358 */
359void tsleep(void)
360{
361 usec_t timeout = fallrate;
362 errno_t rc;
363
364 while (timeout > 0) {
365 cons_event_t event;
366
367 rc = console_get_event_timeout(console, &event, &timeout);
368 if (rc == ETIMEOUT)
369 break;
370 if (rc != EOK)
371 exit(1);
372 }
373}
374
375/** Get char with timeout
376 *
377 */
378int tgetchar(void)
379{
380 errno_t rc;
381
382 /*
383 * Reset timeleft to fallrate whenever it is not positive
384 * and increase speed.
385 */
386
387 if (timeleft <= 0) {
388 faster();
389 timeleft = fallrate;
390 }
391
392 /*
393 * Wait to see if there is any input. If so, take it and
394 * update timeleft so that the next call to tgetchar()
395 * will not wait as long. If there is no input,
396 * make timeleft zero and return -1.
397 */
398
399 char32_t c = 0;
400
401 while (c == 0) {
402 cons_event_t event;
403
404 rc = console_get_event_timeout(console, &event, &timeleft);
405 if (rc == ETIMEOUT) {
406 timeleft = 0;
407 return -1;
408 }
409 if (rc != EOK)
410 exit(1);
411
412 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
413 c = event.ev.key.c;
414 }
415
416 return (int) c;
417}
418
419/** Get char without timeout
420 *
421 */
422int twait(void)
423{
424 char32_t c = 0;
425 errno_t rc;
426
427 while (c == 0) {
428 cons_event_t event;
429
430 rc = console_get_event(console, &event);
431 if (rc == ETIMEOUT)
432 return -1;
433 if (rc != EOK)
434 exit(1);
435
436 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
437 c = event.ev.key.c;
438 }
439
440 return (int) c;
441}
442
443/** @}
444 */
Note: See TracBrowser for help on using the repository browser.