source: mainline/uspace/app/tetris/screen.c@ 6301a24f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6301a24f was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[79ae36dd]1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
[e9a3c52]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 *
[79ae36dd]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.
[e9a3c52]43 *
44 */
45
[b2951e2]46/** @addtogroup tetris
[ebe70f1]47 * @{
[b2951e2]48 */
49/** @file
50 */
51
[e9a3c52]52/*
53 * Tetris screen control.
54 */
55
56#include <stdio.h>
57#include <stdlib.h>
[19f857a]58#include <str.h>
[0c25c10]59#include <vfs/vfs.h>
[f1b4e74]60#include <async.h>
[3e6a98c5]61#include <stdbool.h>
[9f1362d4]62#include <io/console.h>
63#include <io/style.h>
[e9a3c52]64#include "screen.h"
65#include "tetris.h"
66
[ebe70f1]67#define STOP (B_COLS - 3)
68
69static cell curscreen[B_SIZE]; /* non-zero => standout (or otherwise marked) */
[e9a3c52]70static int curscore;
[ebe70f1]71static int isset; /* true => terminal is in game mode */
72
[9f1362d4]73static bool use_color; /* true => use colors */
[50cfa6c]74
[ebe70f1]75static const struct shape *lastshape;
[f1b4e74]76
[bd41ac52]77static usec_t timeleft = 0;
[79ae36dd]78
79console_ctrl_t *console;
80
[e9a3c52]81/*
[f1b4e74]82 * putstr() is for unpadded strings (either as in termcap(5) or
[0c25c10]83 * simply literal strings);
[e9a3c52]84 */
[a000878c]85static inline void putstr(const char *s)
[59ed572]86{
87 while (*s)
88 putchar(*(s++));
89}
[e9a3c52]90
[ebe70f1]91static void start_standout(uint32_t color)
[e9a3c52]92{
[79ae36dd]93 console_flush(console);
[7c014d1]94 console_set_rgb_color(console, use_color ? color : 0x000000,
95 0xffffff);
[f1b4e74]96}
[e9a3c52]97
[f1b4e74]98static void resume_normal(void)
99{
[79ae36dd]100 console_flush(console);
101 console_set_style(console, STYLE_NORMAL);
[e9a3c52]102}
103
[9996ed5]104void clear_screen(void)
105{
[79ae36dd]106 console_clear(console);
[0cc4313]107 moveto(0, 0);
[9996ed5]108}
109
[e9a3c52]110/*
[f1b4e74]111 * Clear the screen, forgetting the current contents in the process.
[e9a3c52]112 */
[ebe70f1]113void scr_clear(void)
[f1b4e74]114{
[d6cc453]115 resume_normal();
[79ae36dd]116 console_clear(console);
[f1b4e74]117 curscore = -1;
[ebe70f1]118 memset(curscreen, 0, sizeof(curscreen));
[f1b4e74]119}
[b917098]120
[e9a3c52]121/*
[f1b4e74]122 * Set up screen
[e9a3c52]123 */
[ebe70f1]124void scr_init(void)
[e9a3c52]125{
[79ae36dd]126 console_cursor_visibility(console, 0);
[f1b4e74]127 resume_normal();
128 scr_clear();
[e9a3c52]129}
130
[96b02eb9]131void moveto(sysarg_t r, sysarg_t c)
[f1b4e74]132{
[79ae36dd]133 console_flush(console);
134 console_set_pos(console, c, r);
[f1b4e74]135}
136
[9996ed5]137winsize_t winsize;
[f1b4e74]138
[b7fd2a0]139static errno_t get_display_size(winsize_t *ws)
[f1b4e74]140{
[79ae36dd]141 return console_get_size(console, &ws->ws_col, &ws->ws_row);
[f1b4e74]142}
[e9a3c52]143
[9f1362d4]144static bool get_display_color_sup(void)
[50cfa6c]145{
[96b02eb9]146 sysarg_t ccap;
[b7fd2a0]147 errno_t rc = console_get_color_cap(console, &ccap);
[a35b458]148
[a53ed3a]149 if (rc != EOK)
[9f1362d4]150 return false;
[a35b458]151
[7c014d1]152 return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
[50cfa6c]153}
154
[e9a3c52]155/*
156 * Set up screen mode.
157 */
[ebe70f1]158void scr_set(void)
[e9a3c52]159{
[9996ed5]160 winsize_t ws;
[a35b458]161
[ebe70f1]162 Rows = 0;
163 Cols = 0;
[a35b458]164
[f1b4e74]165 if (get_display_size(&ws) == 0) {
[e9a3c52]166 Rows = ws.ws_row;
167 Cols = ws.ws_col;
168 }
[50cfa6c]169
170 use_color = get_display_color_sup();
[a35b458]171
[ebe70f1]172 if ((Rows < MINROWS) || (Cols < MINCOLS)) {
[e9a3c52]173 char smallscr[55];
[a35b458]174
[86029498]175 snprintf(smallscr, sizeof(smallscr),
[e9a3c52]176 "the screen is too small (must be at least %dx%d)",
177 MINROWS, MINCOLS);
178 stop(smallscr);
179 }
180 isset = 1;
[a35b458]181
[e9a3c52]182 scr_clear();
183}
184
185/*
186 * End screen mode.
187 */
[ebe70f1]188void scr_end(void)
[e9a3c52]189{
[79ae36dd]190 console_cursor_visibility(console, 1);
[e9a3c52]191}
192
[a000878c]193void stop(const char *why)
[e9a3c52]194{
195 if (isset)
196 scr_end();
[a35b458]197
[f538ef3]198 fprintf(stderr, "aborting: %s", why);
199 abort();
[e9a3c52]200}
201
202/*
203 * Update the screen.
204 */
[ebe70f1]205void scr_update(void)
[e9a3c52]206{
[ebe70f1]207 cell *bp;
208 cell *sp;
209 cell so;
210 cell cur_so = 0;
211 int i;
212 int j;
213 int ccol;
[a35b458]214
[ebe70f1]215 /* Always leave cursor after last displayed point */
[e9a3c52]216 curscreen[D_LAST * B_COLS - 1] = -1;
[a35b458]217
[e9a3c52]218 if (score != curscore) {
[f1b4e74]219 moveto(0, 0);
[86029498]220 printf("Score: %d", score);
[e9a3c52]221 curscore = score;
222 }
[a35b458]223
[ebe70f1]224 /* Draw preview of next pattern */
225 if ((showpreview) && (nextshape != lastshape)) {
[e9a3c52]226 int i;
[ebe70f1]227 static int r = 5, c = 2;
[e9a3c52]228 int tr, tc, t;
[a35b458]229
[e9a3c52]230 lastshape = nextshape;
[a35b458]231
[ebe70f1]232 /* Clean */
[f1b4e74]233 resume_normal();
[ebe70f1]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(" ");
[a35b458]242
[ebe70f1]243 moveto(r - 3, c - 2);
[e9a3c52]244 putstr("Next shape:");
[a35b458]245
[ebe70f1]246 /* Draw */
247 start_standout(nextshape->color);
[e9a3c52]248 moveto(r, 2 * c);
[f1b4e74]249 putstr(" ");
[e9a3c52]250 for (i = 0; i < 3; i++) {
251 t = c + r * B_COLS;
252 t += nextshape->off[i];
[a35b458]253
[e9a3c52]254 tr = t / B_COLS;
255 tc = t % B_COLS;
[a35b458]256
[1433ecda]257 moveto(tr, 2 * tc);
[f1b4e74]258 putstr(" ");
[e9a3c52]259 }
[f1b4e74]260 resume_normal();
[e9a3c52]261 }
[a35b458]262
[e9a3c52]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;
[a35b458]270
[e9a3c52]271 *sp = so;
272 if (i != ccol) {
[86029498]273 if (cur_so) {
274 resume_normal();
275 cur_so = 0;
276 }
[e9a3c52]277 moveto(RTOD(j), CTOD(i));
278 }
[a35b458]279
[f1b4e74]280 if (so != cur_so) {
281 if (so)
[ebe70f1]282 start_standout(so);
[f1b4e74]283 else
284 resume_normal();
285 cur_so = so;
286 }
287 putstr(" ");
[a35b458]288
[e9a3c52]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 */
[a35b458]298
[ebe70f1]299 if ((i > STOP) || (sp[1] != bp[1]) || (so != bp[1]))
[e9a3c52]300 continue;
[a35b458]301
[e9a3c52]302 if (sp[2] != bp[2])
303 sp[1] = -1;
[ebe70f1]304 else if ((i < STOP) && (so == bp[2]) && (sp[3] != bp[3])) {
[e9a3c52]305 sp[2] = -1;
306 sp[1] = -1;
307 }
308 }
309 }
[a35b458]310
[86029498]311 if (cur_so)
312 resume_normal();
[a35b458]313
[79ae36dd]314 console_flush(console);
[e9a3c52]315}
316
317/*
[ebe70f1]318 * Write a message (set != 0), or clear the same message (set == 0).
[e9a3c52]319 * (We need its length in case we have to overwrite with blanks.)
320 */
[9f1362d4]321void scr_msg(char *s, bool set)
[e9a3c52]322{
[92fd52d7]323 int l = str_size(s);
[a35b458]324
[d6cc453]325 moveto(Rows - 2, ((Cols - l) >> 1) - 1);
[a35b458]326
[d6cc453]327 if (set)
328 putstr(s);
329 else
330 while (--l >= 0)
331 (void) putchar(' ');
[e9a3c52]332}
[b2951e2]333
[79ae36dd]334/** Sleep for the current turn time
335 *
336 * Eat any input that might be available.
337 *
338 */
339void tsleep(void)
340{
[bd41ac52]341 usec_t timeout = fallrate;
[a35b458]342
[79ae36dd]343 while (timeout > 0) {
[07b7c48]344 cons_event_t event;
[a35b458]345
[07b7c48]346 if (!console_get_event_timeout(console, &event, &timeout))
[79ae36dd]347 break;
348 }
349}
350
351/** Get char with timeout
352 *
353 */
354int tgetchar(void)
355{
356 /*
357 * Reset timeleft to fallrate whenever it is not positive
358 * and increase speed.
359 */
[a35b458]360
[79ae36dd]361 if (timeleft <= 0) {
362 faster();
363 timeleft = fallrate;
364 }
[a35b458]365
[79ae36dd]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 */
[a35b458]372
[79ae36dd]373 wchar_t c = 0;
[a35b458]374
[79ae36dd]375 while (c == 0) {
[07b7c48]376 cons_event_t event;
[a35b458]377
[07b7c48]378 if (!console_get_event_timeout(console, &event, &timeleft)) {
[79ae36dd]379 timeleft = 0;
380 return -1;
381 }
[a35b458]382
[07b7c48]383 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
384 c = event.ev.key.c;
[79ae36dd]385 }
[a35b458]386
[79ae36dd]387 return (int) c;
388}
389
390/** Get char without timeout
391 *
392 */
393int twait(void)
394{
395 wchar_t c = 0;
[a35b458]396
[79ae36dd]397 while (c == 0) {
[07b7c48]398 cons_event_t event;
[a35b458]399
[07b7c48]400 if (!console_get_event(console, &event))
[79ae36dd]401 return -1;
[a35b458]402
[07b7c48]403 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
404 c = event.ev.key.c;
[79ae36dd]405 }
[a35b458]406
[79ae36dd]407 return (int) c;
408}
409
[b2951e2]410/** @}
411 */
Note: See TracBrowser for help on using the repository browser.