Merge pull request #310 from Daft-Freak/buttons

Button API improvements
diff --git a/32blit-stm32/Src/32blit.c b/32blit-stm32/Src/32blit.c
index eaae73d..1a0ee0f 100644
--- a/32blit-stm32/Src/32blit.c
+++ b/32blit-stm32/Src/32blit.c
@@ -72,7 +72,9 @@
 

 static void init_api_shared() {

   // Reset button state, this prevents the user app immediately seeing the last button transition used to launch the game

-  api.buttons = 0;

+  api.buttons.state = 0;

+  api.buttons.pressed = 0;

+  api.buttons.released = 0;

 

   // reset shared outputs

   api.vibration = 0.0f;

@@ -421,16 +423,14 @@
 Rect menu_item_frame (MenuItem item, float screen_width) { return Rect (0, item * 10 + 19, screen_width, 9); }

 

 void blit_menu_update(uint32_t time) {

-  static uint32_t last_buttons = 0;

-  uint32_t changed_buttons = blit::buttons ^ last_buttons;

-  if(blit::buttons & changed_buttons & blit::Button::DPAD_UP) {

+  if(blit::buttons.pressed & blit::Button::DPAD_UP) {

     menu_item --;

     

-  } else if (blit::buttons & changed_buttons & blit::Button::DPAD_DOWN) {

+  } else if (blit::buttons.pressed & blit::Button::DPAD_DOWN) {

     menu_item ++;

     

   } else {

-    bool button_a = blit::buttons & changed_buttons & blit::Button::A;

+    bool button_a = blit::buttons.pressed & blit::Button::A;

     switch(menu_item) {

       case BACKLIGHT:

         if (blit::buttons & blit::Button::DPAD_LEFT) {

@@ -468,8 +468,6 @@
         break;

     }

   }

-

-  last_buttons = blit::buttons;

 }

 

 void blit_menu_render(uint32_t time) {

diff --git a/32blit/engine/api.cpp b/32blit/engine/api.cpp
index b2c44cf..3bb72d8 100644
--- a/32blit/engine/api.cpp
+++ b/32blit/engine/api.cpp
@@ -15,7 +15,7 @@
 

   static_assert(sizeof(API) < 2048);

 

-  uint32_t &buttons = api.buttons;

+  ButtonState &buttons = api.buttons;

   float &hack_left = api.hack_left;

   float &hack_right = api.hack_right;

   float &vibration = api.vibration;

diff --git a/32blit/engine/api.hpp b/32blit/engine/api.hpp
index 31a380b..52f65ce 100644
--- a/32blit/engine/api.hpp
+++ b/32blit/engine/api.hpp
@@ -7,7 +7,7 @@
 #include "../types/vec3.hpp"

 

 namespace blit {

-  extern uint32_t &buttons;

+  extern ButtonState &buttons;

   extern float &hack_left;

   extern float &hack_right;

   extern float &vibration;

diff --git a/32blit/engine/api_private.hpp b/32blit/engine/api_private.hpp
index b06db14..2814e39 100644
--- a/32blit/engine/api_private.hpp
+++ b/32blit/engine/api_private.hpp
@@ -6,6 +6,7 @@
 #include "engine.hpp"
 #include "file.hpp"
 #include "../audio/audio.hpp"
+#include "../engine/input.hpp"
 #include "../graphics/jpeg.hpp"
 #include "../graphics/surface.hpp"
 #include "../types/vec2.hpp"
@@ -14,7 +15,7 @@
 namespace blit {
   #pragma pack(push, 4)
   struct API {
-    uint32_t buttons;
+    ButtonState buttons;
     float hack_left;
     float hack_right;
     float vibration;
diff --git a/32blit/engine/engine.cpp b/32blit/engine/engine.cpp
index 3fd7d98..0d3bed0 100644
--- a/32blit/engine/engine.cpp
+++ b/32blit/engine/engine.cpp
@@ -68,6 +68,8 @@
     while (pending_update_time >= update_rate_ms) {
       update(time - pending_update_time); // create fake timestamp that would have been accurate for the update event
       pending_update_time -= update_rate_ms;
+
+      api.buttons.pressed = api.buttons.released = 0;
     }
 
     last_tick_time = time;
diff --git a/32blit/engine/input.cpp b/32blit/engine/input.cpp
index a3a6519..d963d77 100644
--- a/32blit/engine/input.cpp
+++ b/32blit/engine/input.cpp
@@ -13,7 +13,7 @@
    * \return `true` for pressed, `false` for released.

    */

   bool pressed(uint32_t button) {

-    return buttons & button;

+    return buttons.state & button;

   }

 

 }
\ No newline at end of file
diff --git a/32blit/engine/input.hpp b/32blit/engine/input.hpp
index 488f776..b82dae5 100644
--- a/32blit/engine/input.hpp
+++ b/32blit/engine/input.hpp
@@ -19,6 +19,25 @@
     JOYSTICK = 1024

   };

 

-  extern bool pressed(uint32_t button);

+  struct ButtonState {

+    ButtonState &operator=(uint32_t v) {

+      uint32_t changed = state ^ v;

 

+      pressed |= changed & v;

+      released |= changed & state;

+

+      state = v;

+

+      return *this;

+    }

+

+    operator uint32_t() const {

+      return state;

+    }

+

+    uint32_t state;

+    uint32_t pressed, released; // state change since last update

+  };

+

+  extern bool pressed(uint32_t button);

 }

diff --git a/examples/profiler-test/profiler-test.cpp b/examples/profiler-test/profiler-test.cpp
index 93af4e3..66df80e 100644
--- a/examples/profiler-test/profiler-test.cpp
+++ b/examples/profiler-test/profiler-test.cpp
@@ -83,24 +83,21 @@
 void render(uint32_t time)
 {
 	static Point    ptMiddle(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
-	static uint32_t lastButtons = 0;
 
 	//static ProfilerProbe *pAwayRenderProbe = g_profiler.AddProbe("AwayFromRender");
 
 
 	//pAwayRenderProbe->StoreElapsedUs(true);
 
-	uint32_t changedButtons = buttons ^ lastButtons;
-
-	bool button_a = buttons & changedButtons & Button::A;
-	bool button_b = buttons & changedButtons & Button::B;
-	bool button_x = buttons & changedButtons & Button::X;
-	bool button_y = buttons & changedButtons & Button::Y;
-	bool button_up = buttons & changedButtons & Button::DPAD_UP;
-	bool button_down = buttons & changedButtons & Button::DPAD_DOWN;
-	bool button_left = buttons & changedButtons & Button::DPAD_LEFT;
-	bool button_right = buttons & changedButtons & Button::DPAD_RIGHT;
-	bool button_home = buttons & changedButtons & Button::HOME;
+	bool button_a = buttons.pressed & Button::A;
+	bool button_b = buttons.pressed & Button::B;
+	bool button_x = buttons.pressed & Button::X;
+	bool button_y = buttons.pressed & Button::Y;
+	bool button_up = buttons.pressed & Button::DPAD_UP;
+	bool button_down = buttons.pressed & Button::DPAD_DOWN;
+	bool button_left = buttons.pressed & Button::DPAD_LEFT;
+	bool button_right = buttons.pressed & Button::DPAD_RIGHT;
+	bool button_home = buttons.pressed & Button::HOME;
 
 	if(button_up && (g_uRows>1))
 	{
@@ -158,8 +155,6 @@
 		g_profiler.log_probes();
 	}
 
-	lastButtons = buttons;
-
 	g_pRenderProbe->start();
 
 	// clear screen
diff --git a/examples/scrolly-tile/scrolly-tile.cpp b/examples/scrolly-tile/scrolly-tile.cpp
index 1a08302..4fedac6 100644
--- a/examples/scrolly-tile/scrolly-tile.cpp
+++ b/examples/scrolly-tile/scrolly-tile.cpp
@@ -492,11 +492,6 @@
 }

 

 void update(uint32_t time_ms) {

-    static uint16_t last_buttons = 0;

-    uint16_t changed = buttons ^ last_buttons;

-    uint16_t pressed = changed & buttons;

-    uint16_t released = changed & ~buttons;

-

     int32_t water_dist = player_position.y - (SCREEN_H - water_level);

     if (water_dist < 0) {

         water_dist = 0;

@@ -506,38 +501,36 @@
 #endif

 

     if (game_state == enum_state::menu) {

-        if(pressed & Button::B) {

+        if(buttons.pressed & Button::B) {

             new_game();

         }

-        else if(pressed & Button::DPAD_UP) {

+        else if(buttons.pressed & Button::DPAD_UP) {

             current_random_source = RANDOM_TYPE_PRNG;

             new_level();

         }

-        else if(pressed & Button::DPAD_DOWN) {

+        else if(buttons.pressed & Button::DPAD_DOWN) {

             current_random_source = RANDOM_TYPE_HRNG;

             new_level();

         }

-        else if(pressed & Button::DPAD_RIGHT) {

+        else if(buttons.pressed & Button::DPAD_RIGHT) {

             if(current_random_source == RANDOM_TYPE_PRNG) {

                 current_random_seed++;

                 new_level();

             }

         }

-        else if(pressed & Button::DPAD_LEFT) {

+        else if(buttons.pressed & Button::DPAD_LEFT) {

             if(current_random_source == RANDOM_TYPE_PRNG) {

                 current_random_seed--;

                 new_level();

             }

         }

-        last_buttons = buttons;

         return;

     }

 

     if(game_state == enum_state::dead){

-        if(pressed & Button::B) {

+        if(buttons.pressed & Button::B) {

             game_state = enum_state::menu;

         }

-        last_buttons = buttons;

         return;

     }

 

@@ -583,7 +576,7 @@
         }

 

         if(player_jump_count){

-            if(pressed & Button::A) {

+            if(buttons.pressed & Button::A) {

                 if(player_state == wall_left

                 || player_state == wall_right

                 || player_state == near_wall_left

@@ -668,8 +661,6 @@
         }

         for_each_tile(collide_player_ud, (void *)&tile_offset);

     }

-

-    last_buttons = buttons;

 }

 

 void render_summary() {

diff --git a/examples/text/text.cpp b/examples/text/text.cpp
index 7771895..80dfc33 100644
--- a/examples/text/text.cpp
+++ b/examples/text/text.cpp
@@ -3,7 +3,6 @@
 using namespace blit;
 
 bool variable_width = true;
-uint32_t prev_buttons = buttons;
 TextAlign alignment = TextAlign::top_left;
 
 std::string alignment_to_string(TextAlign alignment) {
@@ -77,7 +76,7 @@
 }
 
 void update(uint32_t time) {
-    if ((prev_buttons & Button::A) && !(buttons & Button::A))
+    if (buttons.released & Button::A)
         variable_width = !variable_width;
 
     alignment = TextAlign::top_left;
@@ -95,6 +94,4 @@
 	else if (!(buttons & Button::DPAD_LEFT)) {
 		alignment = (TextAlign)(alignment | TextAlign::center_h);
 	}
-
-    prev_buttons = buttons;
 }
diff --git a/examples/voxel/voxel.cpp b/examples/voxel/voxel.cpp
index 5464c73..ced7c47 100644
--- a/examples/voxel/voxel.cpp
+++ b/examples/voxel/voxel.cpp
@@ -233,7 +233,6 @@
 
 void update(uint32_t time_ms) {
   static uint16_t tick = 0;
-  static uint32_t last_buttons = 0;
   
   tick++;
 
@@ -283,13 +282,11 @@
     }
   }
 
-  if(!(buttons & A) && (last_buttons & A)) {
+  if(buttons.released & A) {
     terrain_index++;
     if(terrain_index > 4) {
       terrain_index = 1;
     }
     load_map();
   }
-
-  last_buttons = buttons;
 }
\ No newline at end of file
diff --git a/firmware/flash-loader/flash-loader.cpp b/firmware/flash-loader/flash-loader.cpp
index 01803af..95813b7 100644
--- a/firmware/flash-loader/flash-loader.cpp
+++ b/firmware/flash-loader/flash-loader.cpp
@@ -260,21 +260,18 @@
 void FlashLoader::RenderFlashFile(uint32_t time)
 {
 	static uint32_t lastRepeat = 0;
-	static uint32_t lastButtons = 0;
 
 	if(!m_bFsInit)
 		FSInit();
 
-	uint32_t changedButtons = buttons ^ lastButtons;
+	bool button_a = buttons.pressed & Button::A;
+	bool button_x = buttons.pressed & Button::X;
+	bool button_y = buttons.pressed & Button::Y;
 
-	bool button_a = buttons & changedButtons & Button::A;
-	bool button_x = buttons & changedButtons & Button::X;
-	bool button_y = buttons & changedButtons & Button::Y;
+	bool button_up = buttons.pressed & Button::DPAD_UP;
+	bool button_down = buttons.pressed & Button::DPAD_DOWN;
 
-	bool button_up = buttons & changedButtons & Button::DPAD_UP;
-	bool button_down = buttons & changedButtons & Button::DPAD_DOWN;
-
-	bool button_home = buttons & changedButtons & Button::HOME;
+	bool button_home = buttons.pressed & Button::HOME;
 
 	if(time - lastRepeat > 150 || button_up || button_down) {
 		button_up = buttons & Button::DPAD_UP;
@@ -282,8 +279,6 @@
 		lastRepeat = time;
 	}
 
-	lastButtons = buttons;
-
 	screen.pen = Pen(0,0,0);
 	screen.rectangle(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
 	screen.pen = Pen(255, 255, 255);