diff --git a/examples/graphics.cpp b/examples/graphics.cpp index 0b6040a..5b53996 100644 --- a/examples/graphics.cpp +++ b/examples/graphics.cpp @@ -2,21 +2,17 @@ #include #include #include -#include #include +#include #include #include "chargen.hpp" enum Colors : uint8_t { WHITE = 0x01 }; -static volatile uint8_t &memory_loc(const uint16_t loc) { - return *reinterpret_cast(loc); -} +static volatile uint8_t &memory_loc(const uint16_t loc) { return *reinterpret_cast(loc); } -static void poke(const uint16_t loc, const uint8_t value) { - memory_loc(loc) = value; -} +static void poke(const uint16_t loc, const uint8_t value) { memory_loc(loc) = value; } static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); } @@ -29,64 +25,46 @@ struct Joystick { std::uint8_t state{}; - constexpr bool up() const noexcept { - return (state & 1) == 0; - } - constexpr bool left() const noexcept { - return (state & 4) == 0; - } - constexpr bool fire() const noexcept { - return (state & 16) == 0; - } - constexpr bool right() const noexcept { - return (state & 8) == 0; - } - constexpr bool down() const noexcept { - return (state & 2) == 0; - } + constexpr bool up() const noexcept { return (state & 1) == 0; } + constexpr bool left() const noexcept { return (state & 4) == 0; } + constexpr bool fire() const noexcept { return (state & 16) == 0; } + constexpr bool right() const noexcept { return (state & 8) == 0; } + constexpr bool down() const noexcept { return (state & 2) == 0; } }; -static bool joystick_down() { +static bool joystick_down() +{ uint8_t joystick_state = peek(0xDC00); return (joystick_state & 2) == 0; } void use_data(std::array &data); -static void puts(uint8_t x, uint8_t y, std::string_view str) { +static void puts(uint8_t x, uint8_t y, std::string_view str) +{ const auto start = 0x400 + (y * 40 + x); - std::memcpy(const_cast(&memory_loc(start)), str.data(), - str.size()); + std::memcpy(const_cast(&memory_loc(start)), str.data(), str.size()); } - -template -struct Graphic +template struct Graphic { std::array data{}; - static constexpr auto width() noexcept { - return Width; - } + static constexpr auto width() noexcept { return Width; } - static constexpr auto height() noexcept { - return Height; - } + static constexpr auto height() noexcept { return Height; } constexpr Graphic() = default; constexpr Graphic(std::array data_) noexcept : data(data_) {} - constexpr Graphic(std::initializer_list data_) noexcept { - std::copy(begin(data_), end(data_), begin(data)); - } + constexpr Graphic(std::initializer_list data_) noexcept { std::copy(begin(data_), end(data_), begin(data)); } - constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept { - return data[y * Width + x]; - } + constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept { return data[y * Width + x]; } - constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept { + constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept + { return data[y * Width + x]; } @@ -95,9 +73,7 @@ struct Graphic std::size_t count = 0; for (std::uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) { for (std::uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) { - if (graphic(cur_x, cur_y) == (*this)(cur_x + x, cur_y + y)) { - ++count; - } + if (graphic(cur_x, cur_y) == (*this)(cur_x + x, cur_y + y)) { ++count; } } } @@ -109,19 +85,18 @@ struct Graphic { return match_count(graphic, x, y) == (graphic.width() * graphic.height()); } - - }; -static constexpr auto load_charset(const std::span &bits) { - std::array, 256> results{}; - +static constexpr auto load_charset(const std::span &bits) +{ + std::array, 256> results{}; + for (std::size_t idx = 0; idx < 256; ++idx) { - Graphic<8,8> glyph{}; + Graphic<8, 8> glyph{}; for (std::uint8_t row = 0; row < 8; ++row) { - const auto input_row = bits[idx*8+row]; + const auto input_row = bits[idx * 8 + row]; glyph(0, row) = (0b1000'0000 & input_row) == 0 ? 0 : 1; glyph(1, row) = (0b0100'0000 & input_row) == 0 ? 0 : 1; glyph(2, row) = (0b0010'0000 & input_row) == 0 ? 0 : 1; @@ -138,104 +113,91 @@ static constexpr auto load_charset(const std::span &b return results; } - template - static constexpr auto from_pixels_to_petscii(const Graphic &pixels) { - Graphic result{}; +template +static constexpr auto from_pixels_to_petscii(const Graphic &pixels) +{ + Graphic result{}; - constexpr auto charset = load_charset(uppercase); + constexpr auto charset = load_charset(uppercase); - for (uint8_t x = 0; x < pixels.width(); x += 8) { - for (uint8_t y = 0; y < pixels.height(); y += 8) { - std::uint8_t best_match = 32; - std::size_t match_count = 0; + for (uint8_t x = 0; x < pixels.width(); x += 8) { + for (uint8_t y = 0; y < pixels.height(); y += 8) { + std::uint8_t best_match = 32; + std::size_t match_count = 0; - std::uint8_t cur_char = 0; - for (const auto &glyph : charset) { + std::uint8_t cur_char = 0; + for (const auto &glyph : charset) { - const auto count = pixels.match_count(glyph, x, y); - if (count > match_count) { - best_match = cur_char; - match_count = count; - } - - ++cur_char; + const auto count = pixels.match_count(glyph, x, y); + if (count > match_count) { + best_match = cur_char; + match_count = count; } - result(x/8, y/8) = best_match; + ++cur_char; } - } - return result; + result(x / 8, y / 8) = best_match; + } } - - template - static constexpr auto from_pixels_to_2x2(const Graphic &pixels) { - Graphic result{}; - - using GlyphType = std::pair, std::uint8_t>; - constexpr std::array lookup_map { - GlyphType{ {0,0, - 0,0}, 32 }, - GlyphType{ {1,0, - 0,0}, 126 }, - GlyphType{ {0,1, - 0,0}, 124 }, - GlyphType{ {1,1, - 0,0}, 226 }, - GlyphType{ {0,0, - 1,0}, 123 }, - GlyphType{ {1,0, - 1,0}, 97 }, - GlyphType{ {0,1, - 1,0}, 255 }, - GlyphType{ {1,1, - 1,0}, 236 }, - GlyphType{ {0,0, - 0,1}, 108 }, - GlyphType{ {1,0, - 0,1}, 127 }, - GlyphType{ {0,1, - 0,1}, 225 }, - GlyphType{ {1,1, - 0,1}, 251 }, - GlyphType{ {0,0, - 1,1}, 98 }, - GlyphType{ {1,0, - 1,1}, 252 }, - GlyphType{ {0,1, - 1,1}, 254 }, - GlyphType{ {1,1, - 1,1}, 160 } - }; + return result; +} - for (uint8_t x = 0; x < pixels.width(); x += 2) { - for (uint8_t y = 0; y < pixels.height(); y += 2) { - for (const auto &glyph : lookup_map) { - if (pixels.match(glyph.first, x, y)) { - result(x/2, y/2) = glyph.second; - break; // go to next Y, we found our match - } +template +static constexpr auto from_pixels_to_2x2(const Graphic &pixels) +{ + Graphic result{}; + + using GlyphType = std::pair, std::uint8_t>; + constexpr std::array lookup_map{ GlyphType{ { 0, 0, 0, 0 }, 32 }, + GlyphType{ { 1, 0, 0, 0 }, 126 }, + GlyphType{ { 0, 1, 0, 0 }, 124 }, + GlyphType{ { 1, 1, 0, 0 }, 226 }, + GlyphType{ { 0, 0, 1, 0 }, 123 }, + GlyphType{ { 1, 0, 1, 0 }, 97 }, + GlyphType{ { 0, 1, 1, 0 }, 255 }, + GlyphType{ { 1, 1, 1, 0 }, 236 }, + GlyphType{ { 0, 0, 0, 1 }, 108 }, + GlyphType{ { 1, 0, 0, 1 }, 127 }, + GlyphType{ { 0, 1, 0, 1 }, 225 }, + GlyphType{ { 1, 1, 0, 1 }, 251 }, + GlyphType{ { 0, 0, 1, 1 }, 98 }, + GlyphType{ { 1, 0, 1, 1 }, 252 }, + GlyphType{ { 0, 1, 1, 1 }, 254 }, + GlyphType{ { 1, 1, 1, 1 }, 160 } }; + + + for (uint8_t x = 0; x < pixels.width(); x += 2) { + for (uint8_t y = 0; y < pixels.height(); y += 2) { + for (const auto &glyph : lookup_map) { + if (pixels.match(glyph.first, x, y)) { + result(x / 2, y / 2) = glyph.second; + break;// go to next Y, we found our match } } } - - return result; } -static void putc(uint8_t x, uint8_t y, uint8_t c) { + return result; +} + +static void putc(uint8_t x, uint8_t y, uint8_t c) +{ const auto start = 0x400 + (y * 40 + x); poke(start, c); } -static std::uint8_t loadc(uint8_t x, uint8_t y) { +static std::uint8_t loadc(uint8_t x, uint8_t y) +{ const auto start = 0x400 + (y * 40 + x); return peek(start); } -static void put_hex(uint8_t x, uint8_t y, uint8_t value) { +static void put_hex(uint8_t x, uint8_t y, uint8_t value) +{ const auto put_nibble = [](auto x, auto y, uint8_t nibble) { if (nibble <= 9) { putc(x, y, nibble + 48); @@ -248,31 +210,31 @@ static void put_hex(uint8_t x, uint8_t y, uint8_t value) { put_nibble(x, y, 0xF & (value >> 4)); } -static void put_hex(uint8_t x, uint8_t y, uint16_t value) { - put_hex(x+2,y, static_cast(0xFF & value)); - put_hex(x,y, static_cast(0xFF & (value >> 8))); +static void put_hex(uint8_t x, uint8_t y, uint16_t value) +{ + put_hex(x + 2, y, static_cast(0xFF & value)); + put_hex(x, y, static_cast(0xFF & (value >> 8))); } static void put_graphic(uint8_t x, uint8_t y, const auto &graphic) { for (uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) { - for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) { - putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y)); - } + for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) { putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y)); } } } -struct Clock { +struct Clock +{ using milliseconds = std::chrono::duration; // return elapsed time since last restart - [[nodiscard]] milliseconds restart() noexcept { + [[nodiscard]] milliseconds restart() noexcept + { // stop Timer A poke(0xDC0E, 0b00000000); // last value - const auto previous_value = static_cast( - peek(0xDC04) | (static_cast(peek(0xDC05)) << 8)); + const auto previous_value = static_cast(peek(0xDC04) | (static_cast(peek(0xDC05)) << 8)); // reset timer poke(0xDC04, 0xFF); @@ -281,20 +243,18 @@ struct Clock { // restart timer A poke(0xDC0E, 0b00010001); - return milliseconds{0xFFFF - previous_value}; + return milliseconds{ 0xFFFF - previous_value }; } Clock() noexcept { [[maybe_unused]] const auto value = restart(); } }; -static void cls() { - for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) { - poke(i, 32); - } +static void cls() +{ + for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) { poke(i, 32); } } -template -struct SimpleSprite +template struct SimpleSprite { std::uint8_t x = 0; std::uint8_t y = 0; @@ -302,32 +262,30 @@ struct SimpleSprite Graphic graphic; Graphic saved_background{}; - constexpr SimpleSprite(std::initializer_list data_) noexcept - : graphic(data_) - { - } + constexpr SimpleSprite(std::initializer_list data_) noexcept : graphic(data_) {} }; // helper type for the visitor #4 -template struct overloaded : Ts... { using Ts::operator()...; }; +template struct overloaded : Ts... +{ + using Ts::operator()...; +}; // explicit deduction guide (not needed as of C++20) template overloaded(Ts...) -> overloaded; struct Screen { - void load(std::uint8_t x, std::uint8_t y, auto &s) { + void load(std::uint8_t x, std::uint8_t y, auto &s) + { for (std::uint8_t cur_y = 0; cur_y < s.height(); ++cur_y) { - for (std::uint8_t cur_x = 0; cur_x < s.width(); ++cur_x) { - s(cur_x, cur_y) = loadc(cur_x + x, cur_y + y); - } + for (std::uint8_t cur_x = 0; cur_x < s.width(); ++cur_x) { s(cur_x, cur_y) = loadc(cur_x + x, cur_y + y); } } } - void show(std::uint8_t x, std::uint8_t y, auto &s) { - if (s.is_shown) { - put_graphic(s.x, s.y, s.saved_background); - } + void show(std::uint8_t x, std::uint8_t y, auto &s) + { + if (s.is_shown) { put_graphic(s.x, s.y, s.saved_background); } s.is_shown = true; @@ -335,189 +293,228 @@ struct Screen s.y = y; load(x, y, s.saved_background); - put_graphic(x,y,s.graphic); + put_graphic(x, y, s.graphic); } }; -int main() { - //static constexpr auto charset = load_charset(uppercase); +template +struct Map; - static constexpr auto town = - Graphic<4,4> { - 85,67,67,73, - 93,233,223,93, - 93,160,160,93, - 74,67,67,75}; +struct GameState +{ - static constexpr auto mountain = - Graphic<4,4> { - 32,78,77,32, - 32,32,78,77, - 78,77,32,32, - 32,78,77,32 - }; + std::uint8_t endurance{ 10 }; + std::uint8_t stamina{ max_stamina() }; + std::uint16_t cash{ 100 }; + std::uint8_t x = 20; + std::uint8_t y = 12; + + Clock game_clock{}; + + Map<10, 5> const *current_map = nullptr; + + constexpr void execute_actions(const auto &character) noexcept + { + if (current_map) { + for (auto &action : current_map->actions) { + action.execute_if_collision(x,y,character.width(), character.height(), *this); + } + } + } + + constexpr std::uint8_t max_stamina() const noexcept { return endurance * 5; } + + struct JoyStick1StateChanged + { + Joystick state; + }; - auto character = - SimpleSprite<2,3> { - 32,87, - 78,79, - 78,77 - }; + struct JoyStick2StateChanged + { + Joystick state; + }; + + struct TimeElapsed + { + Clock::milliseconds us; + }; + + using Event = std::variant; + + std::uint8_t last_joystick_2_state = peek(0xDC00); + + Event next_event() noexcept + { + const auto new_joystick_2_state = peek(0xDC00); + + if (new_joystick_2_state != last_joystick_2_state) { + last_joystick_2_state = new_joystick_2_state; + return JoyStick2StateChanged{ Joystick{ new_joystick_2_state } }; + } + + return TimeElapsed{ game_clock.restart() }; + } +}; + +struct Map_Action +{ + std::uint8_t x{}; + std::uint8_t y{}; + + std::uint8_t width{}; + std::uint8_t height{}; + + using Action_Func = void (*)(GameState &); + Action_Func action = nullptr; + + constexpr void execute_if_collision(std::uint8_t obj_x, std::uint8_t obj_y, std::uint8_t obj_width, std::uint8_t obj_height, GameState &game) const { + if (action == nullptr) { + return; + } + + const std::uint8_t rect1_x1 = x; + const std::uint8_t rect1_x2 = x + width - 1; + const std::uint8_t rect1_y1 = y; + const std::uint8_t rect1_y2 = y + height - 1; + + const std::uint8_t rect2_x1 = obj_x; + const std::uint8_t rect2_x2 = obj_x + obj_width - 1; + const std::uint8_t rect2_y1 = obj_y; + const std::uint8_t rect2_y2 = obj_y + obj_height - 1; + + if (rect1_x1 < rect2_x2 && rect1_x2 > rect2_x1 && + rect1_y1 < rect2_y2 && rect1_y2 > rect2_y1) { + action(game); + } + } +}; - static constexpr auto overview_map = - Graphic<10, 5> { - 3,1,1,0,3,0,0,0,0,0, - 0,0,1,1,0,0,0,0,3,0, - 0,0,1,0,0,0,0,0,0,0, - 0,3,0,0,0,0,0,0,0,0, - 0,1,1,1,0,0,3,0,0,0, - }; +template +struct Map { + Graphic layout; - + std::span actions; +}; + +int main() +{ + // static constexpr auto charset = load_charset(uppercase); + + static constexpr auto town = Graphic<4, 4>{ + 85, 67, 67, 73, + 93, 233, 223, 93, + 93, 160, 160, 93, + 74, 67, 67, 75 }; + + static constexpr auto mountain = Graphic<4, 4>{ + 32, 78, 77, 32, + 32, 32, 78, 77, + 78, 77, 32, 32, + 32, 78, 77, 32 }; + + + auto character = SimpleSprite<2, 3>{ + 32, 87, + 78, 79, + 78, 77 }; + + static constexpr auto overview_actions = std::array { + Map_Action { 12,0,4,4, [](GameState &g) { g.x = 30; g.y=5; } } + }; + + static constexpr auto overview_map = Map<10, 5>{ + { + 3, 1, 1, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 3, 0, 0, 0, + }, + std::span(begin(overview_actions), end(overview_actions)) + }; cls(); - poke(53280,0); - poke(53281,0); + poke(53280, 0); + poke(53281, 0); static constexpr std::array tile_types{ [](std::uint8_t x, std::uint8_t y) { /* do nothing for 0th */ }, - [](std::uint8_t x, std::uint8_t y) { - put_graphic(x,y,mountain); - }, + [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, mountain); }, [](std::uint8_t x, std::uint8_t y) { /* do nothing for 2 */ }, - [](std::uint8_t x, std::uint8_t y) { - put_graphic(x,y,town); - }, + [](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, town); }, }; const auto draw_map = [](const auto &map) { for (std::size_t tile = 0; tile < tile_types.size(); ++tile) { - for (std::uint8_t map_large_y =0; map_large_y < map.height(); ++map_large_y) { + for (std::uint8_t map_large_y = 0; map_large_y < map.height(); ++map_large_y) { for (std::uint8_t map_large_x = 0; map_large_x < map.width(); ++map_large_x) { - if (map(map_large_x,map_large_y) == tile) { - tile_types[tile](map_large_x*4,map_large_y*4); - } + if (map(map_large_x, map_large_y) == tile) { tile_types[tile](map_large_x * 4, map_large_y * 4); } } } } }; constexpr auto draw_box = [](uint8_t x, uint8_t y, uint8_t width, uint8_t height) { - putc(x,y, 85); - putc(x+width-1,y, 73); - putc(x+width-1,y+height-1,75); - putc(x,y+height-1,74); + putc(x, y, 85); + putc(x + width - 1, y, 73); + putc(x + width - 1, y + height - 1, 75); + putc(x, y + height - 1, 74); - for (uint8_t cur_x = x+1; cur_x < x+width-1; ++cur_x) { + for (uint8_t cur_x = x + 1; cur_x < x + width - 1; ++cur_x) { putc(cur_x, y, 67); - putc(cur_x, y+height-1, 67); + putc(cur_x, y + height - 1, 67); } - for (uint8_t cur_y = y+1; cur_y < y+height-1; ++cur_y) { + for (uint8_t cur_y = y + 1; cur_y < y + height - 1; ++cur_y) { putc(x, cur_y, 93); - putc(x+width-1, cur_y, 93); + putc(x + width - 1, cur_y, 93); } }; - struct GameState { - - std::uint8_t endurance{10}; - std::uint8_t stamina{max_stamina()}; - std::uint16_t cash{100}; - - Clock game_clock{}; - - constexpr std::uint8_t max_stamina() const noexcept { - return endurance * 5; - } - - struct JoyStick1StateChanged - { - Joystick state; - }; - - - struct JoyStick2StateChanged - { - Joystick state; - }; - - struct TimeElapsed - { - Clock::milliseconds us; - }; - - using Event = std::variant; - - std::uint8_t last_joystick_2_state = peek(0xDC00); - - Event next_event() noexcept { - const auto new_joystick_2_state = peek(0xDC00); - - if (new_joystick_2_state != last_joystick_2_state) { - last_joystick_2_state = new_joystick_2_state; - return JoyStick2StateChanged{Joystick{new_joystick_2_state}}; - } - - return TimeElapsed{game_clock.restart()}; - } - }; - GameState game; + game.current_map = &overview_map; -// draw_map(map1); - draw_map(overview_map); - draw_box(0,20,40,5); + // draw_map(map1); + draw_map(game.current_map->layout); + draw_box(0, 20, 40, 5); constexpr auto show_stats = [](const auto &cur_game) { puts(1, 21, "stamina:"); put_hex(12, 21, cur_game.stamina); put_hex(15, 21, cur_game.max_stamina()); - puts(14,21, "/"); + puts(14, 21, "/"); puts(1, 22, "endurance:"); - put_hex(12,22, cur_game.endurance); - puts(1,23, "cash: "); - put_hex(12,23, cur_game.cash); + put_hex(12, 22, cur_game.endurance); + puts(1, 23, "cash: "); + put_hex(12, 23, cur_game.cash); }; Screen screen; show_stats(game); - std::uint8_t x = 20; - std::uint8_t y = 12; + auto eventHandler = overloaded{ [&](const GameState::JoyStick2StateChanged &e) { + if (e.state.up()) { --game.y; } + if (e.state.down()) { ++game.y; } + if (e.state.left()) { --game.x; } + if (e.state.right()) { ++game.x; } - auto eventHandler = overloaded { - [&](const GameState::JoyStick2StateChanged &e) { - if (e.state.up()) { - --y; - } - if (e.state.down()) { - ++y; - } - if (e.state.left()) { - --x; - } - if (e.state.right()) { - ++x; - } - screen.show(x, y, character); + game.execute_actions(character.graphic); - put_hex(36, 1, e.state.state); - }, - [](const GameState::TimeElapsed &e) { - put_hex(36, 0, e.us.count()); - } - }; + screen.show(game.x, game.y, character); + + put_hex(36, 1, e.state.state); + }, + [](const GameState::TimeElapsed &e) { put_hex(36, 0, e.us.count()); } }; while (true) { std::visit(eventHandler, game.next_event()); diff --git a/src/6502-c++.cpp b/src/6502-c++.cpp index dce34f9..f8c187b 100644 --- a/src/6502-c++.cpp +++ b/src/6502-c++.cpp @@ -815,7 +815,8 @@ void to_mos6502(const Personality &personality, const AVR &from_instruction, std const auto matched_gs = results.get<1>().to_string(); instructions.emplace_back(ASMLine::Type::Directive, ".word " + matched_gs); } else { - spdlog::warn("Unknown .word directive"); + instructions.emplace_back(ASMLine::Type::Directive, ".word " + from_instruction.text.substr(6)); + // spdlog::warn("Unknown .word directive '{}'", from_instruction.text); } } else if (from_instruction.text.starts_with(".byte")) {