Просмотр исходного кода

navigation added
added clipping for cards to avoid overdraw
added draw_box to renderbuffer
updated janky main image

Tibor Tálosi 2 лет назад
Родитель
Сommit
aa62580529
14 измененных файлов с 291 добавлено и 192 удалено
  1. 24 18
      Deck.cpp
  2. 2 2
      Deck.h
  3. 83 23
      Game.cpp
  4. 5 1
      Game.h
  5. 27 17
      TableauColumn.cpp
  6. 4 0
      TableauColumn.h
  7. 71 71
      assets.h
  8. BIN
      assets/main_image.png
  9. 9 18
      solitaire.cpp
  10. 21 26
      utils/Card.cpp
  11. 2 2
      utils/Card.h
  12. 8 0
      utils/List.h
  13. 32 12
      utils/RenderBuffer.cpp
  14. 3 2
      utils/RenderBuffer.h

+ 24 - 18
Deck.cpp

@@ -10,11 +10,13 @@ void Deck::Generate() {
     waste_pile.empty();
     stock_pile.empty();
     //generate and shuffle deck
-    uint8_t cards[52];
-    for (int i = 0; i < 52; i++) cards[i] = i;
+    int cards_count = 52 * deck_count;
+    uint8_t cards[cards_count];
+    for (int i = 0; i < cards_count; i++) cards[i] = i % 52;
     srand(DWT->CYCCNT);
-    for (int i = 0; i < 52; i++) {
-        int r = i + (rand() % (52 - i));
+
+    for (int i = 0; i < cards_count; i++) {
+        int r = i + (rand() % (cards_count - i));
         uint8_t card = cards[i];
         cards[i] = cards[r];
         cards[r] = card;
@@ -31,13 +33,12 @@ void Deck::Generate() {
 void Deck::Cycle() {
     if (stock_pile.count > 0) {
         auto *c = stock_pile.pop();
-        c->exposed= true;
+        c->exposed = true;
         waste_pile.add(c);
-    }
-    else {
+    } else {
         while (waste_pile.count > 0) {
             auto *c = waste_pile.pop();
-            c->exposed= false;
+            c->exposed = false;
             stock_pile.add(c);
         }
     }
@@ -55,22 +56,27 @@ Card *Deck::Extract() {
     return stock_pile.pop();
 }
 
-void Deck::Render(RenderBuffer *buffer) {
-    if (stock_pile.count == 0)
+void Deck::Render(RenderBuffer *buffer, bool stockpileSelect, bool wasteSelect) {
+    if (stock_pile.count == 0) {
         Card::RenderEmptyCard(1, 1, buffer);
-    else {
-        if(stock_pile.count>1) {
+        if (stockpileSelect) {
+            buffer->draw_rbox(2, 2, 17, 23, Flip);
+        }
+    } else {
+        if (stock_pile.count > 1) {
             buffer->draw_rbox_frame(1, 1, 17, 23, Black);
-            stock_pile.last()->Render(0, 0, false, buffer);
-        }else{
-            stock_pile.last()->Render(1, 1, false, buffer);
+            stock_pile.last()->Render(0, 0, stockpileSelect, buffer, 22);
+        } else {
+            stock_pile.last()->Render(1, 1, stockpileSelect, buffer, 22);
         }
     }
 
     if (waste_pile.count == 0) {
-        FURI_LOG_D("DECK", "Rendering empty card");
         Card::RenderEmptyCard(19, 1, buffer);
+        if (wasteSelect) {
+            buffer->draw_rbox(20, 2, 35, 23, Flip);
+        }
+    } else {
+        waste_pile.last()->Render(19, 1, wasteSelect, buffer, 22);
     }
-    else
-        waste_pile.last()->Render(19, 1, false, buffer);
 }

+ 2 - 2
Deck.h

@@ -10,9 +10,9 @@ class Deck {
 public:
     explicit Deck(uint8_t count);
     void Generate();
-    void Render(RenderBuffer *buffer);
+    void Render(RenderBuffer *buffer, bool stockpileSelect, bool wasteSelect);
     void Cycle();
     Card* GetLastWaste();
-    Card* Extract();
     void AddToWaste(Card* c);
+    Card* Extract();
 };

+ 83 - 23
Game.cpp

@@ -1,39 +1,51 @@
 #include "Game.h"
+#include "assets.h"
+
+static Sprite logo = Sprite(sprite_logo, BlackOnly);
+static Sprite main_image = Sprite(sprite_main_image, BlackOnly);
+static Sprite start = Sprite(sprite_start, BlackOnly);
 
 Game::~Game() {
     delete deck;
+    for (int i = 0; i < 4; i++)
+        delete piles[i];
+    delete buffer;
 }
 
 void Game::Render(Canvas *const canvas) {
     if (!buffer) return;
     if (had_change) {
-        deck->Render(buffer);
-        for (int i = 0; i < 7; i++) {
-            FURI_LOG_D("Game", "%i", i);
-            tableau[i].Render(i * 18 + 1, 25, false, 0, buffer);
-        }
-        for (int i = 0; i < 4; i++) {
-            if (piles[i])
-                piles[i]->Render(i * 18 + 55, 1, false, buffer);
-            else
-                Card::RenderEmptyCard(i * 18 + 55, 1, buffer);
-        }
+        if (state == GameStateStart) {
+            buffer->clear();
+            buffer->draw(&logo, (Vector) {60, 30}, 0);
+            buffer->draw(&main_image, (Vector) {110, 25}, 0);
+            buffer->draw(&start, (Vector) {64, 55}, 0);
 
+        } else if (state == GameStatePlay) {
+            buffer->clear();
+            if (deck)
+                deck->Render(buffer, current_row == 0 && current_column == 0, current_row == 0 && current_column == 1);
+            for (int i = 0; i < 7; i++) {
+                bool selected = current_row == 1 && current_column == i;
+                tableau[i].Render(i * 18 + 1, 25, selected, selected ? column_selection : 0, buffer);
+            }
+            for (int i = 0; i < 4; i++) {
+                bool pileSelected = current_row == 0 && (current_column - 3) == i;
+                if (piles[i]) {
+                    piles[i]->Render(i * 18 + 55, 1, pileSelected, buffer, 22);
+                } else {
+                    Card::RenderEmptyCard(i * 18 + 55, 1, buffer);
+                    if (pileSelected) {
+                        buffer->draw_rbox(i * 18 + 56, 2, i * 18 + 71, 23, Flip);
+                    }
+                }
+            }
+        }
     }
     had_change = false;
     buffer->render(canvas);
 }
 
-void Game::Press(InputKey key) {
-    if (key == InputKeyOk && state == GameStateStart) {
-        Reset();
-        NewRound();
-        return;
-    }
-    had_change = true;
-
-}
-
 Game::Game() {
     deck = new Deck(1);
     buffer = new RenderBuffer(128, 64);
@@ -52,8 +64,6 @@ void Game::Reset() {
     column_selection = -1;
 
     deck->Generate();
-    deck->Cycle();
-
     //Reset foundations
     for (int i = 0; i < 4; i++) {
         if (piles[i]) delete piles[i];
@@ -78,3 +88,53 @@ void Game::LongPress(InputKey key) {
 void Game::Update(NotificationApp *app) {
     UNUSED(app);
 }
+
+void Game::Press(InputKey key) {
+    if (key == InputKeyOk && state == GameStateStart) {
+        Reset();
+        NewRound();
+        had_change = true;
+        return;
+    }
+
+    if (key == InputKeyBack && state == GameStatePlay) {
+        state = GameStateStart;
+        had_change = true;
+        return;
+    }
+
+    if(key == InputKeyOk && current_column == 0 && current_row == 0){
+        deck->Cycle();
+        had_change = true;
+    }
+
+    if (key == InputKeyLeft && current_column > 0) {
+        current_column--;
+        had_change = true;
+    } else if (key == InputKeyRight && current_column < 6) {
+        current_column++;
+        if (current_row == 0 && current_column == 2) current_column++;
+        had_change = true;
+    }
+
+    if (key == InputKeyUp && current_row == 1) {
+        uint8_t count = tableau[current_column].Count() - 1;
+        uint8_t first_non_flipped = tableau[current_column].FirstNonFlipped();
+        if (count > first_non_flipped && (column_selection + 1) > count) {
+            column_selection++;
+        } else
+            current_row--;
+
+        had_change = true;
+    } else if (key == InputKeyDown && current_row == 0) {
+        current_row++;
+        column_selection = 0;
+        had_change = true;
+    }
+
+    //disable empty space selection
+    if (current_row == 0 && current_column == 2) {
+        current_column--;
+        had_change = true;
+    }
+}

+ 5 - 1
Game.h

@@ -19,11 +19,15 @@ class Game {
     Card *piles[4];
     TableauColumn tableau[7];
 
-    List<Card> hand;
+    TableauColumn hand;
 
     PlayState state = GameStateStart;
     uint8_t current_row;
     uint8_t current_column;
+
+    uint8_t picked_from_row;
+    uint8_t picked_from_column;
+
     int8_t column_selection;
     RenderBuffer *buffer;
     uint32_t round_start;

+ 27 - 17
TableauColumn.cpp

@@ -19,7 +19,6 @@ void TableauColumn::AddRange(List<Card> *hand) {
 
 void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selection_from_end, RenderBuffer *buffer) {
     // If the hand is empty
-    FURI_LOG_D("Tableau", "%i %i, count %li", x, y, cards->count);
     if (cards->count == 0) {
         Card::RenderEmptyCard(x, y, buffer);
         if (selected)
@@ -27,6 +26,7 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
         return;
     }
     uint8_t selection = cards->count - selection_from_end;
+    if (selected) selection--;
 
     uint8_t loop_end = cards->count;
     uint8_t loop_start = max(loop_end - 4, 0);
@@ -38,34 +38,34 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
     if (first_non_flipped <= loop_start && selection != first_non_flipped) {
         // Draw a card back if it is not the first card
         if (first_non_flipped > 0) {
-            Card::RenderBack(x,y+position, selection == first_non_flipped, buffer);
+            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer, 4);
             // Increment loop start index and position
             position += 4;
             loop_start++;
-            had_top=true;
+            had_top = true;
         }
         // Draw the front side of the first non-flipped card
-        (*cards)[first_non_flipped]->Render(x, y + position, selection == first_non_flipped, buffer);
+        (*cards)[first_non_flipped]->Render(x, y + position, selection == first_non_flipped, buffer, cards->count == 1 ? 22 : 8);
         position += 8;
         loop_start++; // Increment loop start index
     }
 
     // Draw the selected card with adjusted visibility
     if (loop_start > selection) {
-        if(!had_top && first_non_flipped>0){
-            Card::RenderBack(x,y+position, selection == first_non_flipped, buffer);
-            position+=2;
+        if (!had_top && first_non_flipped > 0) {
+            Card::RenderBack(x, y + position, selection == first_non_flipped, buffer,4);
+            position += 2;
             loop_start++;
         }
         // Draw the front side of the selected card
-        (*cards)[selection]->Render(x, y + position, true, buffer);
+        (*cards)[selection]->Render(x, y + position, true, buffer, 8);
         position += 8;
         loop_start++; // Increment loop start index
     }
 
     //Draw the rest
     for (uint8_t i = loop_start; i < loop_end; i++, position += 4) {
-        (*cards)[i]->Render(x, y + position, i == selection, buffer);
+        (*cards)[i]->Render(x, y + position, i == selection, buffer, (i+1)==loop_end ? 22 : 4);
 
         if (i == selection || i == first_non_flipped) position += 4;
     }
@@ -74,14 +74,6 @@ void TableauColumn::Render(uint8_t x, uint8_t y, bool selected, uint8_t selectio
 int8_t TableauColumn::FirstNonFlipped() {
     int8_t index = -1;
     if (cards->count > 0) {
-/*        ListItem<Card> *c = cards->start;
-        while (c){
-            index++;
-            if (c->data->exposed) {
-                break;
-            }
-            c=c->next;
-        }*/
         for (auto *card: *cards) {
             index++;
             if (card && card->exposed) {
@@ -99,3 +91,21 @@ TableauColumn::TableauColumn() {
 TableauColumn::~TableauColumn() {
     delete cards;
 }
+
+void TableauColumn::AddTo(TableauColumn *other) {
+    for (auto *item: *(other->cards)) {
+        cards->add(item);
+    }
+}
+
+Card *TableauColumn::TopCard() {
+    return (*cards)[0];
+}
+
+uint8_t TableauColumn::Count() {
+    return cards->count;
+}
+
+List<Card>* TableauColumn::ExtractEnd(uint8_t count) {
+    return cards->splice(cards->count - count, count);
+}

+ 4 - 0
TableauColumn.h

@@ -13,7 +13,11 @@ public:
     void Reset();
     void AddCard(Card *c);
     void AddRange(List<Card> *hand);
+    void AddTo(TableauColumn *other);
+    List<Card>* ExtractEnd(uint8_t count);
     void Render(uint8_t x, uint8_t y, bool selected, uint8_t selection, RenderBuffer *buffer);
+    Card* TopCard();
 
     int8_t FirstNonFlipped();
+    uint8_t Count();
 };

+ 71 - 71
assets.h

@@ -7,7 +7,7 @@
 ████████████   
          ███   
 */
-const SpriteData *sprite_4 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_4 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xc, 0xa, 0x9, 0x1f, 0x0
 }};
 /*
@@ -17,7 +17,7 @@ const SpriteData *sprite_4 = new SpriteData {.width=5, .height=5, .data=new uint
    ███         
    ███         
 */
-const SpriteData *sprite_7 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_7 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1, 0x19, 0x5, 0x3, 0x0
 }};
 /*
@@ -29,7 +29,7 @@ const SpriteData *sprite_7 = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███      
          ███         
 */
-const SpriteData *sprite_hearths = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_hearths = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0xe, 0x11, 0x22, 0x44, 0x22, 0x11, 0xe
 }};
 /*
@@ -39,7 +39,7 @@ const SpriteData *sprite_hearths = new SpriteData {.width=7, .height=7, .data=ne
 ███      ███   
 ███      ███   
 */
-const SpriteData *sprite_A = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_A = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1e, 0x5, 0x5, 0x1e, 0x0
 }};
 /*
@@ -51,7 +51,7 @@ const SpriteData *sprite_A = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███   ███
    ███   ███   ███   
 */
-const SpriteData *sprite_pattern_small = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_pattern_small = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x0, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a
 }};
 /*
@@ -77,64 +77,64 @@ const SpriteData *sprite_pattern_small = new SpriteData {.width=7, .height=7, .d
       ███            ███   ███      ███      
       ███         ███      ███   ███         
 */
-const SpriteData *sprite_pattern_big = new SpriteData {.width=15, .height=21, .data=new uint8_t[45] {
+const SpriteData sprite_pattern_big = (SpriteData) {.width=15, .height=21, .data=(uint8_t[]) {
 		0x0, 0x1e, 0x8c, 0x4c, 0x9e, 0x1e, 0x1f, 0x9e, 0xcc, 0x80, 0x88, 0x14, 0x8, 0x80, 0x0, 
 		0x0, 0xe0, 0xc0, 0xc1, 0xe0, 0xe0, 0xf3, 0xe7, 0xc7, 0x7, 0x27, 0x53, 0x23, 0x87, 0x0, 
 		0x0, 0x1, 0x18, 0x4, 0x1, 0x1, 0x11, 0xd, 0x0, 0x18, 0x0, 0x10, 0xf, 0x0, 0x0
 }};
 /*
-                                                   █████████████████████████████████████████████   
-                                                ███                                             ███
-                                             █████████████████████████████████████████████      ███
-                                          ███                                             ███   ███
-                                       █████████████████████████████████████████████      ███   ███
-                                    ███                                             ███   ███   ███
-                                    █████████████████████████████████████████████   ███   ███   ███
-                                 ███                                             ██████   ███   ███
-                                 █████████████████████████████████████████████   ██████   ███   ███
-                              ███                                             █████████   ███   ███
-                              ███   ███      ███               ███            █████████   ███   ███
-                              █████████████████████████████████████████████   █████████   ███   ███
-   █████████████████████████████████████████████                           ████████████   ███   ███
-███                                             ███         ███            ████████████   ███   ███
-███   ███      ███               ███            ███████████████████████████   █████████   ███   ███
-███   ███   ███   ███         █████████         ███                        ████████████   ███   ███
-███   ███   ███   ███      ███████████████      ███         ███            ████████████   ███   ███
-███   ███   ███   ███   █████████████████████   ████████████████████████   ████████████   ███   ███
-███   ███   ███   ███      ███████████████      ██████                  ███████████████   ███   ███
-███   ███      ███            █████████         ████████████            ███████████████   ███   ███
-███                              ███            ██████      ████████████   ████████████   ███   ███
-███                                             ██████      ███         ███████████████   ██████   
-███                                             ██████      ██████      ███████████████   ███      
-███                                             ██████      ███   ███   ██████████████████         
-███                                             █████████   ███   ███   ███████████████            
-███            ███                              ██████      ███   ███   ████████████               
-███         █████████            ███      ███   ██████      ███   ███   ████████████               
-███      ███████████████      ███   ███   ███   ██████      ███   ███   █████████                  
-███   █████████████████████   ███   ███   ███   ██████      ███   ███   █████████                  
-███      ███████████████      ███   ███   ███   ██████      ███   ███   ██████                     
-███         █████████         ███   ███   ███   ██████      ███   ███   ██████                     
-███            ███               ███      ███   ██████      ███   ███   ██████                     
-███                                             ██████      ███   ███   ██████                     
-   █████████████████████████████████████████████   ██████   ███   ███   ██████                     
-   ███         █████████         ███   ███   ███   ██████   ███   ███   ██████                     
-   ███            ███               ███      ███   ██████   ███   ███   ███                        
-   ███                                             ██████   ███   ███   ███                        
-      █████████████████████████████████████████████   ███   ███   ███   ███                        
-            ███            ███               ███      ███   ███   ███   ███                        
-            ███                                             ███   ███   ███                        
-               █████████████████████████████████████████████      ███   ███                        
+                                          █████████████████████████████████████████████            
+                                       ███                                             ███         
+                                       █████████████████████████████████████████████   ███         
+                                    ███                                             ██████         
+                                    █████████████████████████████████████████████   ██████         
+                                 ███                                             █████████         
+                                 ███   ███      ███               ███            █████████         
+                                 ███   ███   ███   ███         █████████         █████████         
+                                 █████████████████████████████████████████████   █████████         
+                              ███                                             ████████████         
+                              ███   ███      ███               ███            ████████████         
+                              ███   ███   ███   ███         █████████         ████████████         
+            ███████████████████████████████████████████████████████████████   ████████████         
+         ███                                             ███               ███████████████         
+         ███   ███      ███               ███            ██████            ███████████████         
+         ███   ███   ███   ███         █████████         █████████         ███████████████         
+         ███   ███   ███   ███      ███████████████      ███████████████   ███████████████         
+         ███   ███   ███   ███   █████████████████████   ██████         ██████████████████         
+         ███   ███   ███   ███      ███████████████      █████████      ██████████████████         
+         ███   ███      ███            █████████         █████████      ██████████████████         
+         ███                              ███            █████████      ██████████████████         
+         ███                                             ████████████   ███████████████            
+         ███                                             ████████████   ███████████████            
+         ███                                             ███████████████████████████               
+         ███                                             ███████████████████████████               
+         ███            ███                              ████████████████████████                  
+         ███         █████████            ███      ███   ████████████████████████                  
+         ███      ███████████████      ███   ███   ███   ████████████████████████                  
+         ███   █████████████████████   ███   ███   ███   ████████████████████████                  
+         ███      ███████████████      ███   ███   ███   █████████████████████                     
+         ███         █████████         ███   ███   ███   █████████████████████                     
+         ███            ███               ███      ███   █████████████████████                     
+         ███                                             █████████████████████                     
+            █████████████████████████████████████████████   ███████████████                        
+            ███                                             ███████████████                        
+               █████████████████████████████████████████████   ████████████                        
+               ███            ███               ███      ███   ████████████                        
+               ███                                             █████████                           
+                  █████████████████████████████████████████████   ██████                           
                   ███            ███               ███      ███   ██████                           
-                  ███                                             ███                              
-                     █████████████████████████████████████████████                                 
+                  ███                                             ██████                           
+                     █████████████████████████████████████████████   ███                           
+                     ███                                             ███                           
+                        █████████████████████████████████████████████                              
 */
-const SpriteData *sprite_main_image = new SpriteData {.width=33, .height=44, .data=new uint8_t[198] {
-		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x60, 0x50, 0x58, 0x54, 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0xe5, 0x5, 0xf9, 0x1, 0xfe, 
-		0xe0, 0x10, 0xd0, 0x10, 0x90, 0x50, 0x90, 0x10, 0x10, 0x10, 0x9e, 0xd9, 0x9d, 0x19, 0x19, 0x1d, 0xe9, 0x49, 0x49, 0x49, 0x69, 0x4d, 0x49, 0x49, 0x49, 0xb1, 0xfe, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, 
-		0xff, 0x0, 0xf, 0x0, 0x7, 0x8, 0x7, 0x0, 0x2, 0x7, 0xf, 0x1f, 0xf, 0x7, 0x2, 0x0, 0xff, 0xfe, 0xa, 0xa, 0xf3, 0x52, 0x92, 0x12, 0xec, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0x20, 0x1f, 
-		0xff, 0x0, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x0, 0x78, 0x84, 0x78, 0x0, 0xfc, 0x0, 0xff, 0xff, 0x1, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x1f, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 
-		0x1, 0x1e, 0x22, 0x22, 0xe2, 0x26, 0x2e, 0x26, 0x22, 0x62, 0x22, 0x26, 0x2a, 0x26, 0x22, 0x6e, 0x21, 0x1f, 0x7e, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-		0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7, 0x9, 0x9, 0x9, 0x9, 0xb, 0x9, 0x9, 0x9, 0x9, 0x9, 0xb, 0x9, 0x9, 0xa, 0x8, 0x7, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+const SpriteData sprite_main_image = (SpriteData) {.width=33, .height=44, .data=(uint8_t[]) {
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x18, 0xd6, 0x15, 0x95, 0x55, 0x95, 0x15, 0x15, 0x15, 0x95, 0xd5, 0x95, 0x15, 0x15, 0x15, 0xe5, 0xf9, 0xfe, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xe0, 0x10, 0xd0, 0x10, 0x90, 0x50, 0x90, 0x1e, 0x11, 0x1d, 0x91, 0xd9, 0x95, 0x19, 0x11, 0x11, 0xf1, 0xd9, 0x9d, 0x19, 0x11, 0x11, 0xe1, 0xfe, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xff, 0x0, 0xf, 0x0, 0x7, 0x8, 0x7, 0x0, 0x2, 0x7, 0xf, 0x1f, 0xf, 0x7, 0x2, 0x0, 0xff, 0xff, 0xfd, 0xe1, 0x81, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0xff, 0x0, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x0, 0x78, 0x84, 0x78, 0x0, 0xfc, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0x1, 0x6, 0x3a, 0xca, 0x4a, 0x4a, 0x4a, 0x5a, 0xca, 0x4a, 0x4a, 0x4a, 0x4a, 0x5a, 0xca, 0x4a, 0x59, 0xc7, 0x3f, 0xff, 0xff, 0x1f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
 }};
 /*
    ██████      
@@ -143,7 +143,7 @@ const SpriteData *sprite_main_image = new SpriteData {.width=33, .height=44, .da
 ███   ███      
    ███   ███   
 */
-const SpriteData *sprite_Q = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_Q = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xe, 0x11, 0x9, 0x16, 0x0
 }};
 /*
@@ -153,7 +153,7 @@ const SpriteData *sprite_Q = new SpriteData {.width=5, .height=5, .data=new uint
    ███         
 ████████████   
 */
-const SpriteData *sprite_2 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_2 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x12, 0x19, 0x15, 0x12, 0x0
 }};
 /*
@@ -163,7 +163,7 @@ const SpriteData *sprite_2 = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
 █████████      
 */
-const SpriteData *sprite_3 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_3 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x11, 0x15, 0x15, 0xa, 0x0
 }};
 /*
@@ -173,7 +173,7 @@ const SpriteData *sprite_3 = new SpriteData {.width=5, .height=5, .data=new uint
 ███   ███   ███
 ███      ███   
 */
-const SpriteData *sprite_10 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_10 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x0, 0xe, 0x11, 0xe
 }};
 /*
@@ -183,7 +183,7 @@ const SpriteData *sprite_10 = new SpriteData {.width=5, .height=5, .data=new uin
 ███   ███      
 ███      ███   
 */
-const SpriteData *sprite_K = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_K = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x4, 0xa, 0x11, 0x0
 }};
 /*
@@ -193,7 +193,7 @@ const SpriteData *sprite_K = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
 ████████████   
 */
-const SpriteData *sprite_5 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_5 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x17, 0x15, 0x15, 0x19, 0x0
 }};
 /*
@@ -203,7 +203,7 @@ const SpriteData *sprite_5 = new SpriteData {.width=5, .height=5, .data=new uint
 ███      ███   
    ██████      
 */
-const SpriteData *sprite_6 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_6 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0xe, 0x15, 0x15, 0x8, 0x0
 }};
 /*
@@ -213,7 +213,7 @@ const SpriteData *sprite_6 = new SpriteData {.width=5, .height=5, .data=new uint
          ███   
    ██████      
 */
-const SpriteData *sprite_9 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_9 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x2, 0x15, 0x15, 0xe, 0x0
 }};
 /*
@@ -225,7 +225,7 @@ const SpriteData *sprite_9 = new SpriteData {.width=5, .height=5, .data=new uint
       ███   ███      
          ███         
 */
-const SpriteData *sprite_diamonds = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_diamonds = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x8, 0x14, 0x22, 0x41, 0x22, 0x14, 0x8
 }};
 /*
@@ -235,7 +235,7 @@ const SpriteData *sprite_diamonds = new SpriteData {.width=7, .height=7, .data=n
 ███      ███   
 ████████████   
 */
-const SpriteData *sprite_8 = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_8 = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x1f, 0x15, 0x15, 0x1f, 0x0
 }};
 /*
@@ -245,7 +245,7 @@ const SpriteData *sprite_8 = new SpriteData {.width=5, .height=5, .data=new uint
 ███      ███   
    ██████      
 */
-const SpriteData *sprite_J = new SpriteData {.width=5, .height=5, .data=new uint8_t[5] {
+const SpriteData sprite_J = (SpriteData) {.width=5, .height=5, .data=(uint8_t[]) {
 		0x8, 0x10, 0x10, 0xf, 0x0
 }};
 /*
@@ -257,7 +257,7 @@ const SpriteData *sprite_J = new SpriteData {.width=5, .height=5, .data=new uint
          ███         
       █████████      
 */
-const SpriteData *sprite_spades = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_spades = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x18, 0x1c, 0x4e, 0x7f, 0x4e, 0x1c, 0x18
 }};
 /*
@@ -270,7 +270,7 @@ const SpriteData *sprite_spades = new SpriteData {.width=7, .height=7, .data=new
    ██████████████████         ███            ███   ███      ███      ██████   ███         ███   
       ████████████               ████████████      ██████   █████████   ███   ███         ██████
 */
-const SpriteData *sprite_start = new SpriteData {.width=32, .height=8, .data=new uint8_t[32] {
+const SpriteData sprite_start = (SpriteData) {.width=32, .height=8, .data=(uint8_t[]) {
 		0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x0, 0x0, 0x46, 0x89, 0x89, 0x91, 0x91, 0x62, 0x4, 0xff, 0x84, 0x0, 0xe8, 0x94, 0x94, 0x54, 0xf8, 0x0, 0xfc, 0x8, 0x4, 0x4, 0xff, 0x84
 }};
 /*
@@ -282,7 +282,7 @@ const SpriteData *sprite_start = new SpriteData {.width=32, .height=8, .data=new
          ███         
       █████████      
 */
-const SpriteData *sprite_clubs = new SpriteData {.width=7, .height=7, .data=new uint8_t[7] {
+const SpriteData sprite_clubs = (SpriteData) {.width=7, .height=7, .data=(uint8_t[]) {
 		0x1c, 0x1c, 0x4b, 0x7f, 0x4b, 0x1c, 0x1c
 }};
 /*
@@ -316,7 +316,7 @@ const SpriteData *sprite_clubs = new SpriteData {.width=7, .height=7, .data=new
                                                                                                       ███                                                                                          ███            
                                                                                                       ████████████████████████████████████████████████████████████████████████████████████████████████            
 */
-const SpriteData *sprite_logo = new SpriteData {.width=70, .height=29, .data=new uint8_t[280] {
+const SpriteData sprite_logo = (SpriteData) {.width=70, .height=29, .data=(uint8_t[]) {
 		0xff, 0x1, 0x1, 0x1, 0xe1, 0xf1, 0x39, 0x19, 0x19, 0x19, 0x39, 0x71, 0x61, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0xf9, 0xf9, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x81, 0xf1, 0xf9, 0x81, 0x81, 0x1, 0x1, 0x81, 0x81, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0xb9, 0xb9, 0x1, 0x1, 0x1, 0x81, 0x81, 0x1, 0x81, 0x81, 0x1, 0x1, 0x1, 0x81, 0x81, 0x81, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff, 
 		0xff, 0x0, 0x0, 0x0, 0x71, 0xf3, 0xc3, 0x86, 0x86, 0x86, 0xcc, 0xfc, 0x78, 0x0, 0x7e, 0xff, 0xc3, 0x81, 0x81, 0xc3, 0xff, 0x7e, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x1, 0xff, 0xff, 0x81, 0x81, 0x0, 0xe2, 0xf3, 0xb1, 0x99, 0x99, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x1, 0x1, 0x1, 0x0, 0x7e, 0xff, 0x99, 0x99, 0x99, 0xdf, 0x5e, 0x0, 0x0, 0x0, 0xff, 
 		0xf, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0xf8, 0x9, 0xc9, 0x89, 0x8, 0x8, 0x89, 0x9, 0x89, 0x8, 0x9, 0xc9, 0x48, 0x48, 0x89, 0x9, 0x8, 0x88, 0x8, 0x9, 0x9, 0x88, 0x8, 0x88, 0xc8, 0xa8, 0x8, 0x89, 0x9, 0x89, 0x8, 0xf8, 0x8, 0x8, 0x8, 0xf, 

BIN
assets/main_image.png


+ 9 - 18
solitaire.cpp

@@ -29,7 +29,7 @@ static void update_timer_callback(FuriMessageQueue *event_queue) {
 
 static void render_callback(Canvas *const canvas, void *ctx) {
     Game *g = (Game *) ctx;
-    auto status = furi_mutex_acquire(mutex, 25);
+    auto status = furi_mutex_acquire(mutex, 150);
     if (g == nullptr || status != FuriStatusOk) return;
     g->Render(canvas);
     UNUSED(canvas);
@@ -43,15 +43,13 @@ extern "C"
 #endif
 int32_t solitaire_app(void *p) {
     UNUSED(p);
+    FURI_LOG_D("MEMORY", "Free %i", memmgr_get_free_heap());
     int32_t return_code = 0;
+    size_t start = memmgr_get_free_heap();
     Game *game = new Game;
-    FURI_LOG_D("LOAD", "START");
     FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(AppEvent));
-    FURI_LOG_D("LOAD", "QUEUE");
-    FURI_LOG_D("LOAD", "GAME");
     mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     if (mutex) {
-        FURI_LOG_D("LOAD", "ALLOC");
         bool processing = true;
         auto *notification = static_cast<NotificationApp *>(furi_record_open(RECORD_NOTIFICATION));
 
@@ -62,7 +60,7 @@ int32_t solitaire_app(void *p) {
         view_port_input_callback_set(view_port, input_callback, event_queue);
 
         FuriTimer *timer = furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue);
-        furi_timer_start(timer, furi_kernel_get_tick_frequency() / 30);
+        furi_timer_start(timer, furi_kernel_get_tick_frequency() / 20);
 
         auto gui = static_cast<Gui *>(furi_record_open("gui"));
         gui_add_view_port(gui, view_port, GuiLayerFullscreen);
@@ -72,7 +70,7 @@ int32_t solitaire_app(void *p) {
 //        game->NewRound();
 
         while (processing) {
-            FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150);
+            FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
             furi_mutex_acquire(mutex, FuriWaitForever);
 
             if (event_status == FuriStatusOk) {
@@ -93,17 +91,7 @@ int32_t solitaire_app(void *p) {
                                 break;
                         }
                     } else if (event.input->type == InputTypePress) {
-                        switch (event.input->key) {
-                            case InputKeyUp:
-                            case InputKeyDown:
-                            case InputKeyRight:
-                            case InputKeyLeft:
-                            case InputKeyOk:
-                                game->Press(event.input->key);
-                                break;
-                            default:
-                                break;
-                        }
+                        game->Press(event.input->key);
                     }
                 } else if (event.type == EventTypeTick) {
                     game->Update(notification);
@@ -131,6 +119,9 @@ int32_t solitaire_app(void *p) {
     delete game;
     furi_mutex_free(mutex);
     furi_message_queue_free(event_queue);
+    start = memmgr_get_free_heap()-start;
+    if(start!=0)
+        FURI_LOG_E("MEMORY", "Leak detected %i", start);
     return return_code;
 }
 

+ 21 - 26
utils/Card.cpp

@@ -2,11 +2,6 @@
 #include "RenderBuffer.h"
 #include "../assets.h"
 
-#define CARD_HEIGHT 23
-#define CARD_HALF_HEIGHT 11
-#define CARD_WIDTH 17
-#define CARD_HALF_WIDTH 8
-
 static Sprite letters[] = {
         Sprite(sprite_2, BlackOnly),
         Sprite(sprite_3, BlackOnly),
@@ -32,38 +27,38 @@ static Sprite suits[] = {
 
 static Sprite backSide = Sprite(sprite_pattern_big, BlackOnly);
 
-void Card::Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer) {
-
+void Card::Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
+    uint8_t height = y + fmin(size_limit, 22);
     if (exposed) {
-        buffer->draw_rbox(x, y, x + 16, y + 22, White);
-        buffer->draw_rbox_frame(x, y, x + 16, y + 22, Black);
-//        buffer->draw_line(x+15, y, x+15, y+22, White);
-
-            buffer->draw(&(letters[value]), (Vector) {(float) x + 5, (float) y + 6}, 0);
-           buffer->draw(&(suits[suit]), (Vector) {(float) x + 12, (float) y + 6}, 0);
+        buffer->draw_rbox(x, y, x + 16, height, White);
+        buffer->draw_rbox_frame(x, y, x + 16, height, Black);
+        buffer->draw(&(letters[value]), (Vector) {(float) x + 5, (float) y + 6}, 0);
+        buffer->draw(&(suits[suit]), (Vector) {(float) x + 12, (float) y + 6}, 0);
 
-          buffer->draw(&(letters[value]), (Vector) {(float) x + 12, (float) y + 17}, M_PI);
-           buffer->draw(&(suits[suit]), (Vector) {(float) x + 5, (float) y + 17}, M_PI);
+        if (size_limit > 8) {
+            buffer->draw(&(letters[value]), (Vector) {(float) x + 12, (float) y + 17}, M_PI);
+            buffer->draw(&(suits[suit]), (Vector) {(float) x + 5, (float) y + 17}, M_PI);
+        }
         if (selected) {
-            buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
+            buffer->draw_box(x + 1, y + 1, x + 16, height, Flip);
         }
     } else {
-        RenderBack(x, y, selected, buffer);
-//        buffer->draw(&backSide, (Vector) {(float) x + 8, (float) y + 11}, 0);
+        RenderBack(x, y, selected, buffer, size_limit);
     }
-
 }
 
 void Card::RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer) {
-    buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
-    buffer->draw_rbox_frame(x + 2, y + 2, x + 14, y + 20, Flip);
+    buffer->draw_rbox(x, y, x + 17, y + 23, Black);
+    buffer->draw_rbox_frame(x + 2, y + 2, x + 14, y + 20, White);
 }
 
-void Card::RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer) {
-    buffer->draw_rbox(x + 1, y + 1, x + 16, y + 22, White);
-    buffer->draw_rbox_frame(x, y, x + 16, y + 22, Black);
-    buffer->draw(&backSide, (Vector) {(float) x + 9, (float) y + 12}, 0);
+void Card::RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
+    uint8_t height = y + fmin(size_limit, 22);
+
+    buffer->draw_box(x + 1, y + 1, x + 16, height, White);
+    buffer->draw_rbox_frame(x, y, x + 16, height, Black);
+    buffer->draw(&backSide, (Vector) {(float) x + 9, (float) y + 12}, 15, fmin(size_limit, 22), 0);
     if (selected) {
-        buffer->draw_rbox(x, y, x + 17, y + 23, Flip);
+        buffer->draw_box(x + 1, y + 1, x + 16, height, Flip);
     }
 }

+ 2 - 2
utils/Card.h

@@ -11,7 +11,7 @@ struct Card {
 
     Card(uint8_t s, uint8_t v) : suit(s), value(v) {}
 
-    void Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer);
+    void Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit);
     static void RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer);
-    static void RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer);
+    static void RenderBack(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit);
 };

+ 8 - 0
utils/List.h

@@ -110,6 +110,14 @@ struct List {
         }
     }
 
+    void add_front(T *data) {
+        count++;
+        ListItem<T> *c = start;
+        start = new ListItem<T>();
+        start->data = data;
+        start->next = c;
+    }
+
     void remove(T *data) {
         if (!start || !data) return;
 

+ 32 - 12
utils/RenderBuffer.cpp

@@ -9,17 +9,21 @@ RenderBuffer::RenderBuffer(uint8_t w, uint8_t h) : Buffer(w, h) {
 }
 
 void RenderBuffer::reset() {
+    int size = width() * (height() / 8);
+    for (int i = 0; i < size; i++) {
+        data[i] = 0;
+    }
 }
 
 void RenderBuffer::render(Canvas *const canvas) {
-    canvas_clear(canvas);
+//    canvas_clear(canvas);
     for (uint8_t x = 0; x < width(); x++) {
         for (uint8_t y = 0; y < height(); y++) {
             if (test_pixel(x, y))
                 canvas_draw_dot(canvas, x, y);
         }
     }
-    canvas_commit(canvas);
+//    canvas_commit(canvas);
 }
 
 void RenderBuffer::draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode) {
@@ -70,40 +74,48 @@ void RenderBuffer::draw_circle(int x, int y, int r, PixelColor color) {
 }
 
 void RenderBuffer::draw(Sprite *const sprite, Vector position, float rotation) {
+    draw(sprite, position, sprite->width(), sprite->height(), rotation);
+}
+
+
+void RenderBuffer::draw(Sprite *const sprite, Vector position, uint8_t x_cap, uint8_t y_cap, float rotation) {
     switch (sprite->draw_mode) {
         default:
         case BlackOnly:
-            draw_sprite(sprite, true, Black, position, rotation);
+            draw_sprite(sprite, true, Black, position, x_cap, y_cap, rotation);
             break;
         case WhiteOnly:
-            draw_sprite(sprite, false, White, position, rotation);
+            draw_sprite(sprite, false, White, position, x_cap, y_cap, rotation);
             break;
         case WhiteAsBlack:
-            draw_sprite(sprite, false, Black, position, rotation);
+            draw_sprite(sprite, false, Black, position, x_cap, y_cap, rotation);
             break;
         case BlackAsWhite:
-            draw_sprite(sprite, true, White, position, rotation);
+            draw_sprite(sprite, true, White, position, x_cap, y_cap, rotation);
             break;
         case WhiteAsInverted:
-            draw_sprite(sprite, false, Flip, position, rotation);
+            draw_sprite(sprite, false, Flip, position, x_cap, y_cap, rotation);
             break;
         case BlackAsInverted:
-            draw_sprite(sprite, true, Flip, position, rotation);
+            draw_sprite(sprite, true, Flip, position, x_cap, y_cap, rotation);
             break;
     }
 }
 
 //TODO: proper scaling
 void
-RenderBuffer::draw_sprite(Sprite *const sprite, bool is_black, PixelColor draw_color, const Vector& position, float rotation) {
+RenderBuffer::draw_sprite(Sprite *const sprite, bool is_black, PixelColor draw_color, const Vector &position,
+                          uint8_t x_cap, uint8_t y_cap, float rotation) {
     Vector anchor = sprite->get_offset();
     float cosTheta = cos(rotation/* + M_PI_2*/);
     float sinTheta = sin(rotation/* + M_PI_2*/);
     float transformedX, transformedY, rotatedX, rotatedY;
+    int max_w = fmin(sprite->width(), x_cap);
+    int max_h = fmin(sprite->height(), y_cap);
     bool isOn;
     int16_t finalX, finalY;
-    for (int y = 0; y < sprite->height(); y++) {
-        for (int x = 0; x < sprite->width(); x++) {
+    for (int y = 0; y < max_h; y++) {
+        for (int x = 0; x < max_w; x++) {
             transformedX = (x - anchor.x);
             transformedY = (y - anchor.y);
             rotatedX = transformedX * cosTheta - transformedY * sinTheta;
@@ -128,7 +140,7 @@ RenderBuffer::~RenderBuffer() {
 void RenderBuffer::draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode) {
     for (int16_t x = x0; x < x1; x++) {
         for (int16_t y = y0; y < y1; y++) {
-            if (((x == x0 || x == x1-1) && (y == y0 || y == y1-1)) || !test_coordinate(x,y)) continue;
+            if (((x == x0 || x == x1 - 1) && (y == y0 || y == y1 - 1)) || !test_coordinate(x, y)) continue;
             set_pixel(x, y, draw_mode);
         }
     }
@@ -141,3 +153,11 @@ void RenderBuffer::draw_rbox_frame(int16_t x0, int16_t y0, int16_t x1, int16_t y
     draw_line(x0, y0 + 1, x0, y1 - 1, draw_mode);
     draw_line(x1, y0 + 1, x1, y1 - 1, draw_mode);
 }
+
+void RenderBuffer::draw_box(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode) {
+    for (int16_t x = x0; x < x1; x++) {
+        for (int16_t y = y0; y < y1; y++) {
+            set_pixel(x, y, draw_mode);
+        }
+    }
+}

+ 3 - 2
utils/RenderBuffer.h

@@ -7,7 +7,7 @@ struct Vector;
 class Sprite;
 class RenderBuffer : public Buffer {
     void draw_sprite(Sprite *const sprite, bool is_black,
-                     PixelColor draw_color, const Vector& position, float rotation);
+                     PixelColor draw_color, const Vector& position, uint8_t x_cap, uint8_t y_cap, float rotation);
 
 public:
     explicit RenderBuffer(uint8_t w, uint8_t h);
@@ -20,10 +20,11 @@ public:
 
     void draw_line(int x0, int y0, int x1, int y1, PixelColor draw_mode);
     void draw_rbox(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
+    void draw_box(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
     void draw_rbox_frame(int16_t x0, int16_t y0, int16_t x1, int16_t y1, PixelColor draw_mode);
 
     void draw_circle(int x, int y, int r, PixelColor draw_mode);
 
+    void draw(Sprite *const sprite, Vector position, uint8_t x_cap, uint8_t y_cap, float rotation);
     void draw(Sprite *const sprite, Vector position, float rotation);
-
 };