PatchworkOS
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1#include <errno.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/proc.h>
9
10#define BLOCK_SIZE 32
11
12#define FIELD_PADDING 10
13#define FIELD_WIDTH 10
14#define FIELD_HEIGHT 20
15#define FIELD_LEFT (FIELD_PADDING)
16#define FIELD_TOP (FIELD_PADDING)
17#define FIELD_RIGHT (FIELD_PADDING + BLOCK_SIZE * FIELD_WIDTH)
18#define FIELD_BOTTOM (FIELD_PADDING + BLOCK_SIZE * FIELD_HEIGHT)
19
20#define SIDE_PANEL_PADDING 20
21#define SIDE_PANEL_WIDTH 220
22#define SIDE_PANEL_LEFT (FIELD_RIGHT + FIELD_PADDING)
23#define SIDE_PANEL_TOP (FIELD_TOP)
24#define SIDE_PANEL_RIGHT (SIDE_PANEL_LEFT + SIDE_PANEL_WIDTH - FIELD_PADDING)
25#define SIDE_PANEL_BOTTOM (FIELD_BOTTOM)
26#define SIDE_PANEL_TEXT_HEIGHT 42
27#define SIDE_PANEL_LABEL_HEIGHT 42
28#define SIDE_PANEL_LABEL_PADDING 40
29
30#define WINDOW_WIDTH ((FIELD_WIDTH) * BLOCK_SIZE + FIELD_PADDING * 2 + SIDE_PANEL_WIDTH)
31#define WINDOW_HEIGHT ((FIELD_HEIGHT) * BLOCK_SIZE + FIELD_PADDING * 2)
32
33#define CURRENT_SCORE_LABEL_ID 0
34#define COMPLETE_LINES_LABEL_ID 1
35#define PLAYED_BLOCKS_LABEL_ID 2
36
37#define TICK_SPEED (CLOCKS_PER_SEC)
38#define DROPPING_TICK_SPEED (CLOCKS_PER_SEC / 12)
39#define CLEARING_LINES_TICK_SPEED (CLOCKS_PER_SEC / 15)
40#define START_SCREEN_TICK_SPEED ((CLOCKS_PER_SEC / 4) * 3)
41
42#define PIECE_AMOUNT 7
43#define PIECE_WIDTH 4
44#define PIECE_HEIGHT 4
45
49
64
66
78
79static piece_t pieces[] = {
80 [PIECE_CYAN] =
81 {
86 },
87 [PIECE_BLUE] =
88 {
93 },
94 [PIECE_ORANGE] =
95 {
100 },
101 [PIECE_YELLOW] =
102 {
107 },
108 [PIECE_GREEN] =
109 {
114 },
115 [PIECE_PURPLE] =
116 {
121 },
122 [PIECE_RED] =
123 {
128 },
129};
130
133
137
141
142static bool isClearingLines;
143static bool isStarted;
144static bool isGameover;
145
148
149static struct
150{
156
157static const pixel_t normalColors[] = {
158 [BLOCK_NONE] = PIXEL_ARGB(0xFF, 0x00, 0x00, 0x00),
159 [BLOCK_CYAN] = PIXEL_ARGB(0xFF, 0x00, 0xE5, 0xFF),
160 [BLOCK_BLUE] = PIXEL_ARGB(0xFF, 0x00, 0x55, 0xFF),
161 [BLOCK_ORANGE] = PIXEL_ARGB(0xFF, 0xFF, 0x7A, 0x00),
162 [BLOCK_YELLOW] = PIXEL_ARGB(0xFF, 0xFF, 0xE1, 0x00),
163 [BLOCK_GREEN] = PIXEL_ARGB(0xFF, 0x00, 0xFF, 0x4D),
164 [BLOCK_PURPLE] = PIXEL_ARGB(0xFF, 0xD2, 0x00, 0xFF),
165 [BLOCK_RED] = PIXEL_ARGB(0xFF, 0xFF, 0x00, 0x55),
166 [BLOCK_CLEARING] = PIXEL_ARGB(0xFF, 0xFF, 0xFF, 0xFF),
167 [BLOCK_OUTLINE] = PIXEL_ARGB(0xFF, 0x00, 0x00, 0x00),
168};
169static const pixel_t highlightColors[] = {
170 [BLOCK_NONE] = PIXEL_ARGB(0xFF, 0x00, 0x00, 0x00),
171 [BLOCK_CYAN] = PIXEL_ARGB(0xFF, 0x98, 0xF5, 0xFF),
172 [BLOCK_BLUE] = PIXEL_ARGB(0xFF, 0x98, 0xB9, 0xFF),
173 [BLOCK_ORANGE] = PIXEL_ARGB(0xFF, 0xFF, 0xBF, 0x98),
174 [BLOCK_YELLOW] = PIXEL_ARGB(0xFF, 0xFF, 0xF3, 0x98),
175 [BLOCK_GREEN] = PIXEL_ARGB(0xFF, 0x98, 0xFF, 0xB3),
176 [BLOCK_PURPLE] = PIXEL_ARGB(0xFF, 0xED, 0x98, 0xFF),
177 [BLOCK_RED] = PIXEL_ARGB(0xFF, 0xFF, 0x98, 0xB9),
178 [BLOCK_CLEARING] = PIXEL_ARGB(0xFF, 0xFF, 0xFF, 0xFF),
179 [BLOCK_OUTLINE] = PIXEL_ARGB(0xFF, 0xEE, 0xEE, 0xEE),
180};
181static const pixel_t shadowColors[] = {
182 [BLOCK_NONE] = PIXEL_ARGB(0xFF, 0x00, 0x00, 0x00),
183 [BLOCK_CYAN] = PIXEL_ARGB(0xFF, 0x00, 0x7A, 0x8C),
184 [BLOCK_BLUE] = PIXEL_ARGB(0xFF, 0x00, 0x2A, 0x8C),
185 [BLOCK_ORANGE] = PIXEL_ARGB(0xFF, 0x8C, 0x46, 0x00),
186 [BLOCK_YELLOW] = PIXEL_ARGB(0xFF, 0x8C, 0x7D, 0x00),
187 [BLOCK_GREEN] = PIXEL_ARGB(0xFF, 0x00, 0x8C, 0x2A),
188 [BLOCK_PURPLE] = PIXEL_ARGB(0xFF, 0x75, 0x00, 0x8C),
189 [BLOCK_RED] = PIXEL_ARGB(0xFF, 0x8C, 0x00, 0x2A),
190 [BLOCK_CLEARING] = PIXEL_ARGB(0xFF, 0xFF, 0xFF, 0xFF),
191 [BLOCK_OUTLINE] = PIXEL_ARGB(0xFF, 0xEE, 0xEE, 0xEE),
192};
193
194static void current_piece_choose_new(void);
195static void current_piece_clear(element_t* elem, drawable_t* draw);
196static void current_piece_draw(element_t* elem, drawable_t* draw);
197
198static void block_draw(element_t* elem, drawable_t* draw, block_t block, int64_t x, int64_t y)
199{
200 if (x < 0 || y < 0 || x >= FIELD_WIDTH || y >= FIELD_HEIGHT)
201 {
202 return;
203 }
204
206
207 const theme_t* theme = element_get_theme(elem);
208
209 draw_frame(draw, &rect, theme->frameSize, highlightColors[block], shadowColors[block]);
210 RECT_SHRINK(&rect, theme->frameSize);
211 draw_rect(draw, &rect, normalColors[block]);
212 RECT_SHRINK(&rect, 5);
213 draw_frame(draw, &rect, theme->frameSize, shadowColors[block], highlightColors[block]);
214}
215
216static void side_panel_draw(element_t* elem, drawable_t* draw)
217{
219
220 const theme_t* theme = element_get_theme(elem);
221
223
224 rect_t textRect = rect;
225 textRect.bottom = textRect.top + SIDE_PANEL_TEXT_HEIGHT;
227
228 textRect.top = textRect.bottom + SIDE_PANEL_LABEL_HEIGHT;
229 textRect.bottom = textRect.top + SIDE_PANEL_TEXT_HEIGHT;
231
232 textRect.top = textRect.bottom + SIDE_PANEL_LABEL_HEIGHT;
233 textRect.bottom = textRect.top + SIDE_PANEL_TEXT_HEIGHT;
235
236 uint64_t fontHeight = font_height(largeFont);
237
238 textRect.top = rect.bottom - fontHeight * 7;
239 textRect.bottom = rect.bottom;
240 draw_text(draw, &textRect, largeFont, ALIGN_CENTER, ALIGN_CENTER, theme->view.foregroundNormal, " ASD - Move");
241 textRect.top += fontHeight;
242 textRect.bottom += fontHeight;
243 draw_text(draw, &textRect, largeFont, ALIGN_CENTER, ALIGN_CENTER, theme->view.foregroundNormal, "SPACE - Drop");
244 textRect.top += fontHeight;
245 textRect.bottom += fontHeight;
246 draw_text(draw, &textRect, largeFont, ALIGN_CENTER, ALIGN_CENTER, theme->view.foregroundNormal, " R - Spin");
247}
248
249static point_t piece_block_pos_in_field(int64_t pieceX, int64_t pieceY, int64_t blockX, int64_t blockY)
250{
251 return (point_t){.x = pieceX + blockX - PIECE_WIDTH / 2, .y = pieceY + blockY - PIECE_HEIGHT / 2};
252}
253
254static bool piece_is_out_of_bounds(const piece_t* piece, int64_t pieceX, int64_t pieceY)
255{
256 for (int64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
257 {
258 for (int64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
259 {
260 if ((*piece)[blockY][blockX] == BLOCK_NONE)
261 {
262 continue;
263 }
264
265 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
266 if (point.x < 0 || point.x >= FIELD_WIDTH ||
267 point.y >= FIELD_HEIGHT) // point.y < 0 check is left out on purpose
268 {
269 return true;
270 }
271 }
272 }
273
274 return false;
275}
276
277static void piece_clear(element_t* elem, drawable_t* draw, const piece_t* piece, uint64_t pieceX, uint64_t pieceY)
278{
279 for (int64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
280 {
281 for (int64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
282 {
283 if ((*piece)[blockY][blockX] == BLOCK_NONE)
284 {
285 continue;
286 }
287
288 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
289 block_draw(elem, draw, BLOCK_NONE, point.x, point.y);
290 }
291 }
292}
293
294static void piece_outline_draw(element_t* elem, drawable_t* draw, const piece_t* piece, uint64_t pieceX,
295 uint64_t pieceY)
296{
297 for (int64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
298 {
299 for (int64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
300 {
301 if ((*piece)[blockY][blockX] == BLOCK_NONE)
302 {
303 continue;
304 }
305
306 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
307 block_draw(elem, draw, BLOCK_OUTLINE, point.x, point.y);
308 }
309 }
310}
311
312static void piece_draw(element_t* elem, drawable_t* draw, const piece_t* piece, uint64_t pieceX, uint64_t pieceY)
313{
314 for (int64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
315 {
316 for (int64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
317 {
318 if ((*piece)[blockY][blockX] == BLOCK_NONE)
319 {
320 continue;
321 }
322
323 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
324 block_draw(elem, draw, (*piece)[blockY][blockX], point.x, point.y);
325 }
326 }
327}
328
330{
331 for (uint64_t i = 0; i < 2; i++)
332 {
333 for (uint64_t j = i; j < 4 - i - 1; j++)
334 {
335 block_t temp = (*piece)[i][j];
336 (*piece)[i][j] = (*piece)[4 - 1 - j][i];
337 (*piece)[4 - 1 - j][i] = (*piece)[4 - 1 - i][4 - 1 - j];
338 (*piece)[4 - 1 - i][4 - 1 - j] = (*piece)[j][4 - 1 - i];
339 (*piece)[j][4 - 1 - i] = temp;
340 }
341 }
342}
343
344static void field_edge_draw(element_t* elem, drawable_t* draw)
345{
346 const theme_t* theme = element_get_theme(elem);
347
349 RECT_EXPAND(&fieldRect, FIELD_PADDING);
352 draw_frame(draw, &fieldRect, theme->frameSize, theme->deco.shadow, theme->deco.highlight);
353}
354
355static void field_draw(element_t* elem, drawable_t* draw)
356{
357 for (uint64_t y = 0; y < FIELD_HEIGHT; y++)
358 {
359 for (uint64_t x = 0; x < FIELD_WIDTH; x++)
360 {
361 if (field[y][x] == oldField[y][x])
362 {
363 continue;
364 }
365 oldField[y][x] = field[y][x];
366
367 block_draw(elem, draw, field[y][x], x, y);
368 }
369 }
370}
371
372static bool field_collides(const piece_t* piece, int64_t pieceX, int64_t pieceY)
373{
374 for (int64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
375 {
376 for (int64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
377 {
378 if ((*piece)[blockY][blockX] == BLOCK_NONE)
379 {
380 continue;
381 }
382
383 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
384 if (point.x < 0 || point.x >= FIELD_WIDTH || point.y < 0 || point.y >= FIELD_HEIGHT)
385 {
386 continue;
387 }
388 if (field[point.y][point.x] != BLOCK_NONE)
389 {
390 return true;
391 }
392 }
393 }
394
395 return false;
396}
397
398static void field_add_piece(const piece_t* piece, int64_t pieceX, int64_t pieceY)
399{
400 for (uint64_t blockY = 0; blockY < PIECE_HEIGHT; blockY++)
401 {
402 for (uint64_t blockX = 0; blockX < PIECE_WIDTH; blockX++)
403 {
404 if ((*piece)[blockY][blockX] == BLOCK_NONE)
405 {
406 continue;
407 }
408
409 point_t point = piece_block_pos_in_field(pieceX, pieceY, blockX, blockY);
410 field[point.y][point.x] = currentPiece.piece[blockY][blockX];
411 }
412 }
413}
414
415static void field_move_down(uint64_t line)
416{
417 for (int64_t y = line; y >= 1; y--)
418 {
419 memcpy(&field[y], &field[y - 1], sizeof(block_t) * FIELD_WIDTH);
420 }
421
422 for (uint64_t x = 0; x < FIELD_WIDTH; x++)
423 {
424 field[0][x] = BLOCK_NONE;
425 }
426}
427
428static void field_clear_lines(element_t* elem, drawable_t* draw)
429{
430 current_piece_clear(elem, draw);
431 bool isDone = true;
432 for (uint64_t y = 0; y < FIELD_HEIGHT; y++)
433 {
434 int64_t x = 0;
435 for (; x < FIELD_WIDTH / 2; x++)
436 {
437 if (field[y][x] != BLOCK_CLEARING)
438 {
439 break;
440 }
441 }
442
443 if (x == 0)
444 {
445 continue;
446 }
447
448 field[y][x - 1] = BLOCK_NONE;
450
451 if (x == 1)
452 {
454 }
455
456 isDone = false;
457 }
458
459 if (!isDone)
460 {
461 field_draw(elem, draw);
462 }
463 else
464 {
465 isClearingLines = false;
466 }
467
468 current_piece_draw(elem, draw);
469}
470
472{
473 uint64_t foundLines = 0;
474 for (uint64_t y = 0; y < FIELD_HEIGHT; y++)
475 {
476 bool isLineComplete = true;
477 for (uint64_t x = 0; x < FIELD_WIDTH; x++)
478 {
479 if (field[y][x] == BLOCK_NONE)
480 {
481 isLineComplete = false;
482 break;
483 }
484 }
485
486 if (isLineComplete)
487 {
488 for (uint64_t x = 0; x < FIELD_WIDTH; x++)
489 {
491 }
492 isClearingLines = true;
494 foundLines++;
495 }
496 }
497
498 switch (foundLines)
499 {
500 case 1:
501 {
502 currentScore += 40;
503 }
504 break;
505 case 2:
506 {
507 currentScore += 100;
508 }
509 break;
510 case 3:
511 {
512 currentScore += 300;
513 }
514 break;
515 case 4:
516 {
517 currentScore += 1200;
518 }
519 break;
520 }
521
522 field_draw(elem, draw);
523}
524
525static void pause()
526{
527 isClearingLines = false;
528
529 for (int64_t y = 0; y < FIELD_HEIGHT; y++)
530 {
531 for (int64_t x = 0; x < FIELD_WIDTH; x++)
532 {
533 field[y][x] = BLOCK_NONE;
535 }
536 }
537
538 isStarted = false;
539 isGameover = false;
540}
541
542static void start()
543{
544 currentScore = 0;
545 completedLines = 0;
546 playedBlocks = 0;
547
548 isClearingLines = false;
549
550 for (int64_t y = 0; y < FIELD_HEIGHT; y++)
551 {
552 for (int64_t x = 0; x < FIELD_WIDTH; x++)
553 {
554 field[y][x] = BLOCK_NONE;
556 }
557 }
558
560 currentPiece.isDropping = false;
561
562 isStarted = true;
563 isGameover = false;
564}
565
567{
568 memcpy(&currentPiece.piece, &pieces[rand() % PIECE_AMOUNT + 1], sizeof(piece_t));
569 currentPiece.x = 5;
570 currentPiece.y = 0;
571
572 playedBlocks++;
573
575 {
576 pause();
577 isGameover = true;
578 }
579}
580
581static void current_piece_clear(element_t* elem, drawable_t* draw)
582{
583 int64_t outlineY = currentPiece.y;
584 while (!piece_is_out_of_bounds(&currentPiece.piece, currentPiece.x, outlineY) &&
585 !field_collides(&currentPiece.piece, currentPiece.x, outlineY))
586 {
587 outlineY++;
588 }
589 outlineY--;
590
591 piece_clear(elem, draw, &currentPiece.piece, currentPiece.x, outlineY);
592 piece_clear(elem, draw, &currentPiece.piece, currentPiece.x, currentPiece.y);
593}
594
595static void current_piece_draw(element_t* elem, drawable_t* draw)
596{
597 int64_t outlineY = currentPiece.y;
598 while (!piece_is_out_of_bounds(&currentPiece.piece, currentPiece.x, outlineY) &&
599 !field_collides(&currentPiece.piece, currentPiece.x, outlineY))
600 {
601 outlineY++;
602 }
603 outlineY--;
604
605 piece_outline_draw(elem, draw, &currentPiece.piece, currentPiece.x, outlineY);
606 piece_draw(elem, draw, &currentPiece.piece, currentPiece.x, currentPiece.y);
607}
608
610{
613 {
616 current_piece_draw(elem, draw);
617 field_check_for_lines(elem, draw);
618 }
619 else
620 {
621 current_piece_clear(elem, draw);
622 currentPiece.y++;
623 current_piece_draw(elem, draw);
624 }
625}
626
627static void current_piece_move(element_t* elem, drawable_t* draw, keycode_t code)
628{
629 uint64_t newX = currentPiece.x + (code == KBD_D) - (code == KBD_A);
630
631 if (piece_is_out_of_bounds(&currentPiece.piece, newX, currentPiece.y) ||
633 {
634 return;
635 }
636
637 current_piece_clear(elem, draw);
638 currentPiece.x = newX;
639 current_piece_draw(elem, draw);
640}
641
642static void current_piece_drop(element_t* elem, drawable_t* draw)
643{
644 current_piece_clear(elem, draw);
645
648 {
649 currentPiece.y++;
650 }
651 currentPiece.y--;
652
653 current_piece_draw(elem, draw);
654}
655
657{
658 piece_t rotatedPiece;
659 memcpy(&rotatedPiece, &currentPiece.piece, sizeof(piece_t));
660 piece_rotate(&rotatedPiece);
661
662 if (piece_is_out_of_bounds(&rotatedPiece, currentPiece.x, currentPiece.y) ||
663 field_collides(&rotatedPiece, currentPiece.x, currentPiece.y))
664 {
665 return;
666 }
667
668 current_piece_clear(elem, draw);
669 memcpy(&currentPiece.piece, &rotatedPiece, sizeof(piece_t));
670 current_piece_draw(elem, draw);
671}
672
674{
675 uint64_t totalWidth = font_width(massiveFont, "TETRIS", 6);
676
677 rect_t rect = RECT_INIT((FIELD_RIGHT + FIELD_LEFT) / 2 - totalWidth / 2 - 10, FIELD_TOP,
678 (FIELD_RIGHT + FIELD_LEFT) / 2 - totalWidth / 3 + 10, FIELD_TOP + (FIELD_BOTTOM - FIELD_TOP) / 2);
679
681 uint64_t width = font_width(massiveFont, "T", 1);
682 rect.left += width;
683 rect.right += width;
685 width = font_width(massiveFont, "E", 1);
686 rect.left += width;
687 rect.right += width;
689 width = font_width(massiveFont, "T", 1);
690 rect.left += width;
691 rect.right += width;
693 width = font_width(massiveFont, "R", 1);
694 rect.left += width - 8;
695 rect.right += width - 8;
697 width = font_width(massiveFont, "I", 1);
698 rect.left += width + 8;
699 rect.right += width + 8;
701}
702
704{
705 static bool blink = false;
706
708 draw_rect(draw, &rect, normalColors[BLOCK_NONE]);
709 if (blink)
710 {
711 const theme_t* theme = element_get_theme(elem);
712 draw_text(draw, &rect, largeFont, ALIGN_CENTER, ALIGN_CENTER, theme->deco.foregroundNormal, "PRESS SPACE");
713 }
714 blink = !blink;
715}
716
717static uint64_t procedure(window_t* win, element_t* elem, const event_t* event)
718{
719 const theme_t* theme = element_get_theme(elem);
720
721 switch (event->type)
722 {
723 case LEVENT_INIT:
724 {
725 srand(uptime());
726
727 currentScore = 0;
728 completedLines = 0;
729 playedBlocks = 0;
730
734 currentScoreLabel = label_new(elem, CURRENT_SCORE_LABEL_ID, &labelRect, "000000", ELEMENT_NONE);
738
739 labelRect.top = labelRect.bottom + SIDE_PANEL_LABEL_HEIGHT;
740 labelRect.bottom = labelRect.top + SIDE_PANEL_TEXT_HEIGHT;
745
746 labelRect.top = labelRect.bottom + SIDE_PANEL_LABEL_HEIGHT;
747 labelRect.bottom = labelRect.top + SIDE_PANEL_TEXT_HEIGHT;
748 playedBlocksLabel = label_new(elem, PLAYED_BLOCKS_LABEL_ID, &labelRect, "000000", ELEMENT_NONE);
752
753 pause();
754 }
755 break;
756 case LEVENT_QUIT:
757 {
759 }
760 break;
761 case LEVENT_REDRAW:
762 {
763 drawable_t draw;
764 element_draw_begin(elem, &draw);
765
766 field_edge_draw(elem, &draw);
767 field_draw(elem, &draw);
768 side_panel_draw(elem, &draw);
769
770 element_draw_end(elem, &draw);
771
773 }
774 break;
775 case EVENT_TIMER:
776 {
777 drawable_t draw;
778 element_draw_begin(elem, &draw);
779
780 if (!isStarted)
781 {
782 start_tetris_draw(&draw);
783 start_press_space_draw(elem, &draw);
785
786 element_draw_end(elem, &draw);
787 break;
788 }
789 else if (isClearingLines)
790 {
791 field_clear_lines(elem, &draw);
793
794 element_draw_end(elem, &draw);
795 break;
796 }
797 else if (currentPiece.isDropping)
798 {
800 }
801 else
802 {
804 }
805
806 current_piece_update(elem, &draw);
807
809 {
810 isGameover = false;
812 }
813
814 element_draw_end(elem, &draw);
815 }
816 break;
817 case EVENT_KBD:
818 {
819 if (!isStarted)
820 {
821 if (event->kbd.type == KBD_PRESS && event->kbd.code == KBD_SPACE)
822 {
823 start();
824 element_redraw(elem, false);
825 }
826
827 break;
828 }
829 else if (isClearingLines)
830 {
831 currentPiece.isDropping = false;
832 break;
833 }
834
835 drawable_t draw;
836 element_draw_begin(elem, &draw);
837
838 if (event->kbd.type == KBD_PRESS && (event->kbd.code == KBD_A || event->kbd.code == KBD_D))
839 {
840 current_piece_move(elem, &draw, event->kbd.code);
841 }
842 else if (event->kbd.type == KBD_PRESS && event->kbd.code == KBD_R)
843 {
844 current_piece_rotate(elem, &draw);
845 }
846 else if (event->kbd.type == KBD_PRESS && event->kbd.code == KBD_S)
847 {
848 currentPiece.isDropping = true;
850 }
851 else if (event->kbd.type == KBD_PRESS && event->kbd.code == KBD_SPACE)
852 {
853 current_piece_drop(elem, &draw);
855 }
856 else if (event->kbd.type == KBD_RELEASE && event->kbd.code == KBD_S)
857 {
858 currentPiece.isDropping = false;
860 }
861
862 element_draw_end(elem, &draw);
863 }
864 break;
865 }
866
868 {
869 char buffer[7];
870 sprintf(buffer, "%06d", currentScore);
873 }
875 {
876 char buffer[7];
877 sprintf(buffer, "%06d", completedLines);
880 }
882 {
883 char buffer[7];
884 sprintf(buffer, "%06d", playedBlocks);
887 }
888
892
893 return 0;
894}
895
896int main(void)
897{
898 display_t* disp = display_new();
899 if (disp == NULL)
900 {
901 return EXIT_FAILURE;
902 }
903
904 largeFont = font_new(disp, "default", "regular", 32);
905 if (largeFont == NULL)
906 {
907 display_free(disp);
908 return EXIT_FAILURE;
909 }
910 massiveFont = font_new(disp, "default", "regular", 64);
911 if (massiveFont == NULL)
912 {
914 display_free(disp);
915 return EXIT_FAILURE;
916 }
917
919 window_t* win = window_new(disp, "Tetris", &rect, SURFACE_WINDOW, WINDOW_DECO, procedure, NULL);
920 if (win == NULL)
921 {
922 return EXIT_FAILURE;
923 }
924
925 window_set_visible(win, true);
926
927 event_t event = {0};
928 while (display_next(disp, &event, CLOCKS_NEVER) != ERR)
929 {
930 display_dispatch(disp, &event);
931 }
932
933 window_free(win);
936 display_free(disp);
937 return EXIT_SUCCESS;
938}
#define CLOCKS_NEVER
Definition clock_t.h:16
@ TIMER_NONE
Definition cmd.h:76
uint64_t font_width(const font_t *font, const char *string, uint64_t length)
Definition font.c:130
void font_free(font_t *font)
Definition font.c:91
font_t * font_new(display_t *disp, const char *family, const char *weight, uint64_t size)
Definition font.c:17
uint64_t font_height(const font_t *font)
Definition font.c:158
void display_disconnect(display_t *disp)
Disconnect the display connection.
Definition display.c:161
uint64_t display_next(display_t *disp, event_t *event, clock_t timeout)
Retrieve the next event from the display connection.
Definition display.c:213
uint64_t display_dispatch(display_t *disp, const event_t *event)
Dispatch an event to the appropriate surface.
Definition display.c:440
void display_free(display_t *disp)
Free a display connection.
Definition display.c:113
display_t * display_new(void)
Create a new display connection.
Definition display.c:36
void draw_rect(drawable_t *draw, const rect_t *rect, pixel_t pixel)
Draw a filled rectangle.
Definition drawable.c:7
void draw_ridge(drawable_t *draw, const rect_t *rect, uint64_t width, pixel_t foreground, pixel_t background)
Draw a ridge effect.
Definition drawable.c:994
void draw_text(drawable_t *draw, const rect_t *rect, const font_t *font, align_t xAlign, align_t yAlign, pixel_t pixel, const char *text)
Draw text to a drawable.
Definition drawable.c:669
void draw_bezel(drawable_t *draw, const rect_t *rect, uint64_t width, pixel_t pixel)
Draw a filled border bezel just inside the given rectangle.
Definition drawable.c:339
void draw_frame(drawable_t *draw, const rect_t *rect, uint64_t width, pixel_t foreground, pixel_t background)
Draw a skeuomorphic frame.
Definition drawable.c:204
@ ALIGN_CENTER
Definition drawable.h:49
text_props_t * element_get_text_props(element_t *elem)
Get the text properties of an element.
Definition element.c:361
theme_t * element_get_theme(element_t *elem)
Get the theme of an element.
Definition element.c:401
void element_draw_end(element_t *elem, drawable_t *draw)
End drawing to an element.
Definition element.c:427
#define ELEMENT_NONE
Definition element.h:43
void element_draw_begin(element_t *elem, drawable_t *draw)
Begin drawing to an element.
Definition element.c:411
void element_redraw(element_t *elem, bool shouldPropagate)
Redraw an element.
Definition element.c:450
uint64_t element_set_text(element_t *elem, const char *text)
Set the text of an element.
Definition element.c:343
#define LEVENT_QUIT
Definition event.h:103
#define LEVENT_REDRAW
Definition event.h:101
#define LEVENT_INIT
Definition event.h:99
#define EVENT_KBD
Definition event.h:84
#define EVENT_TIMER
Definition event.h:86
@ SURFACE_WINDOW
Definition surface.h:35
element_t * label_new(element_t *parent, element_id_t id, const rect_t *rect, const char *text, element_flags_t flags)
Create a new label element.
Definition label.c:45
uint64_t window_set_visible(window_t *win, bool isVisible)
Set the visibility of the window.
Definition window.c:692
uint64_t window_set_timer(window_t *win, timer_flags_t flags, clock_t timeout)
Set the window timer.
Definition window.c:533
window_t * window_new(display_t *disp, const char *name, const rect_t *rect, surface_type_t type, window_flags_t flags, procedure_t procedure, void *private)
Allocate and initialize a new window.
Definition window.c:301
void window_free(window_t *win)
Free a window.
Definition window.c:415
display_t * window_get_display(window_t *win)
Get the display associated with the window.
Definition window.c:467
@ WINDOW_DECO
Enable decorations (titlebar, close/minimize buttons, etc).
Definition window.h:46
keycode_t
Keyboard keycode type.
Definition kbd.h:27
@ KBD_SPACE
Space key.
Definition kbd.h:74
@ KBD_R
Key R.
Definition kbd.h:49
@ KBD_S
Key S.
Definition kbd.h:50
@ KBD_D
Key D.
Definition kbd.h:35
@ KBD_A
Key A.
Definition kbd.h:32
@ KBD_RELEASE
Key release event.
Definition kbd.h:288
@ KBD_PRESS
Key press event.
Definition kbd.h:287
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
#define NULL
Pointer error value.
Definition NULL.h:23
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
uint32_t pixel_t
Definition pixel.h:11
#define PIXEL_ARGB(a, r, g, b)
Definition pixel.h:18
#define ERR
Definition main.c:44
int main()
Definition main.c:97
#define WINDOW_WIDTH
Definition main.c:20
#define WINDOW_HEIGHT
Definition main.c:21
static uint64_t procedure(window_t *win, element_t *elem, const event_t *event)
Definition main.c:46
static void current_piece_rotate(element_t *elem, drawable_t *draw)
Definition main.c:656
int64_t x
Definition main.c:152
static uint64_t oldCurrentScore
Definition main.c:138
static uint64_t oldCompletedLines
Definition main.c:139
static void field_check_for_lines(element_t *elem, drawable_t *draw)
Definition main.c:471
static element_t * playedBlocksLabel
Definition main.c:48
int64_t y
Definition main.c:153
#define PIECE_AMOUNT
Definition main.c:42
static void block_draw(element_t *elem, drawable_t *draw, block_t block, int64_t x, int64_t y)
Definition main.c:198
#define CLEARING_LINES_TICK_SPEED
Definition main.c:39
bool isDropping
Definition main.c:154
static bool isGameover
Definition main.c:144
static const pixel_t shadowColors[]
Definition main.c:181
static void current_piece_draw(element_t *elem, drawable_t *draw)
Definition main.c:595
static font_t * massiveFont
Definition main.c:147
#define FIELD_TOP
Definition main.c:16
static void pause()
Definition main.c:525
#define SIDE_PANEL_TOP
Definition main.c:23
#define FIELD_WIDTH
Definition main.c:13
#define PIECE_WIDTH
Definition main.c:43
static void side_panel_draw(element_t *elem, drawable_t *draw)
Definition main.c:216
static bool isClearingLines
Definition main.c:142
static void piece_outline_draw(element_t *elem, drawable_t *draw, const piece_t *piece, uint64_t pieceX, uint64_t pieceY)
Definition main.c:294
static uint64_t oldPlayedBlocks
Definition main.c:140
static void start()
Definition main.c:542
piece_type_t
Definition main.c:68
@ PIECE_NONE
Definition main.c:69
@ PIECE_GREEN
Definition main.c:74
@ PIECE_YELLOW
Definition main.c:73
@ PIECE_RED
Definition main.c:76
@ PIECE_PURPLE
Definition main.c:75
@ PIECE_BLUE
Definition main.c:71
@ PIECE_CYAN
Definition main.c:70
@ PIECE_ORANGE
Definition main.c:72
static block_t field[FIELD_HEIGHT][FIELD_WIDTH]
Definition main.c:131
static void piece_rotate(piece_t *piece)
Definition main.c:329
static uint64_t playedBlocks
Definition main.c:136
static void current_piece_update(element_t *elem, drawable_t *draw)
Definition main.c:609
#define DROPPING_TICK_SPEED
Definition main.c:38
static bool piece_is_out_of_bounds(const piece_t *piece, int64_t pieceX, int64_t pieceY)
Definition main.c:254
static uint64_t completedLines
Definition main.c:135
static void current_piece_clear(element_t *elem, drawable_t *draw)
Definition main.c:581
static block_t oldField[FIELD_HEIGHT][FIELD_WIDTH]
Definition main.c:132
#define START_SCREEN_TICK_SPEED
Definition main.c:40
#define SIDE_PANEL_LABEL_HEIGHT
Definition main.c:27
#define FIELD_BOTTOM
Definition main.c:18
piece_t piece
Definition main.c:151
static bool field_collides(const piece_t *piece, int64_t pieceX, int64_t pieceY)
Definition main.c:372
static void current_piece_move(element_t *elem, drawable_t *draw, keycode_t code)
Definition main.c:627
#define TICK_SPEED
Definition main.c:37
static element_t * currentScoreLabel
Definition main.c:46
static struct @30 currentPiece
static void piece_clear(element_t *elem, drawable_t *draw, const piece_t *piece, uint64_t pieceX, uint64_t pieceY)
Definition main.c:277
static const pixel_t normalColors[]
Definition main.c:157
static const pixel_t highlightColors[]
Definition main.c:169
#define FIELD_LEFT
Definition main.c:15
static void field_clear_lines(element_t *elem, drawable_t *draw)
Definition main.c:428
#define SIDE_PANEL_LABEL_PADDING
Definition main.c:28
#define FIELD_HEIGHT
Definition main.c:14
static font_t * largeFont
Definition main.c:146
static bool isStarted
Definition main.c:143
#define SIDE_PANEL_RIGHT
Definition main.c:24
static piece_t pieces[]
Definition main.c:79
static void current_piece_drop(element_t *elem, drawable_t *draw)
Definition main.c:642
static void current_piece_choose_new(void)
Definition main.c:566
#define SIDE_PANEL_LEFT
Definition main.c:22
static void field_edge_draw(element_t *elem, drawable_t *draw)
Definition main.c:344
static void field_move_down(uint64_t line)
Definition main.c:415
block_t piece_t[PIECE_HEIGHT][PIECE_WIDTH]
Definition main.c:65
#define FIELD_PADDING
Definition main.c:12
static void field_draw(element_t *elem, drawable_t *draw)
Definition main.c:355
static uint64_t currentScore
Definition main.c:134
block_t
Definition main.c:51
@ BLOCK_OUTLINE
Definition main.c:62
@ BLOCK_YELLOW
Definition main.c:57
@ BLOCK_NONE
Definition main.c:53
@ BLOCK_CLEARING
Definition main.c:61
@ BLOCK_INVAL
Definition main.c:52
@ BLOCK_BLUE
Definition main.c:55
@ BLOCK_CYAN
Definition main.c:54
@ BLOCK_PURPLE
Definition main.c:59
@ BLOCK_GREEN
Definition main.c:58
@ BLOCK_RED
Definition main.c:60
@ BLOCK_ORANGE
Definition main.c:56
#define BLOCK_SIZE
Definition main.c:10
#define PIECE_HEIGHT
Definition main.c:44
static point_t piece_block_pos_in_field(int64_t pieceX, int64_t pieceY, int64_t blockX, int64_t blockY)
Definition main.c:249
static void piece_draw(element_t *elem, drawable_t *draw, const piece_t *piece, uint64_t pieceX, uint64_t pieceY)
Definition main.c:312
static void start_press_space_draw(element_t *elem, drawable_t *draw)
Definition main.c:703
#define PLAYED_BLOCKS_LABEL_ID
Definition main.c:35
static void start_tetris_draw(drawable_t *draw)
Definition main.c:673
#define COMPLETE_LINES_LABEL_ID
Definition main.c:34
#define SIDE_PANEL_BOTTOM
Definition main.c:25
#define SIDE_PANEL_TEXT_HEIGHT
Definition main.c:26
static element_t * completeLinesLabel
Definition main.c:47
#define FIELD_RIGHT
Definition main.c:17
static void field_add_piece(const piece_t *piece, int64_t pieceX, int64_t pieceY)
Definition main.c:398
#define CURRENT_SCORE_LABEL_ID
Definition main.c:33
#define RECT_SHRINK(rect, margin)
Definition rect.h:81
#define RECT_INIT_DIM(x, y, width, height)
Definition rect.h:32
#define RECT_INIT(left, top, right, bottom)
Definition rect.h:26
#define RECT_EXPAND(rect, margin)
Definition rect.h:89
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__INT64_TYPE__ int64_t
Definition stdint.h:16
_PUBLIC int sprintf(char *_RESTRICT s, const char *_RESTRICT format,...)
Definition sprintf.c:5
_PUBLIC void srand(unsigned int seed)
_PUBLIC int rand(void)
Definition rand.c:5
#define EXIT_SUCCESS
Definition stdlib.h:46
#define EXIT_FAILURE
Definition stdlib.h:47
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
Opaque display structure.
Definition internal.h:61
Drawable structure.
Definition drawable.h:35
Opaque element structure.
Definition internal.h:23
kbd_event_type_t type
Definition event.h:139
keycode_t code
Definition event.h:141
Event structure.
Definition event.h:271
event_kbd_t kbd
Definition event.h:277
event_type_t type
Definition event.h:272
int64_t y
Definition point.h:14
int64_t x
Definition point.h:13
Definition rect.h:13
int32_t bottom
Definition rect.h:17
int32_t top
Definition rect.h:15
int32_t right
Definition rect.h:16
int32_t left
Definition rect.h:14
font_t * font
Definition element.h:66
pixel_t backgroundNormal
Definition theme.h:35
pixel_t highlight
Definition theme.h:45
pixel_t foregroundNormal
Definition theme.h:40
pixel_t shadow
Definition theme.h:46
Theme structure.
Definition theme.h:71
theme_color_set_t deco
Definition theme.h:76
theme_color_set_t view
Definition theme.h:73
int64_t frameSize
Definition theme.h:83
Opaque window structure.
Definition internal.h:44
static theme_t theme
Definition theme.c:12