First commit.

Savegame icons are displayed on the window.
This commit is contained in:
King_DuckZ 2018-09-05 00:55:24 +01:00
commit f1ec7799af
7 changed files with 294 additions and 0 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "lib/nana"]
path = lib/nana
url = https://github.com/cnjinhao/nana.git

9
CMakeLists.txt Normal file
View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
set(NANA_CMAKE_INSTALL_INCLUDES OFF CACHE BOOL "")
set(NANA_CMAKE_ENABLE_PNG OFF CACHE BOOL "")
set(NANA_CMAKE_SHARED_LIB ON CACHE BOOL "")
set(NANA_CMAKE_ENABLE_JPEG OFF CACHE BOOL "")
add_subdirectory(lib/nana)
add_subdirectory(src/gui)

1
lib/nana Submodule

@ -0,0 +1 @@
Subproject commit dbd8a4a6910aa3b81b77989a2d1866fdb26e4f6f

10
src/gui/CMakeLists.txt Normal file
View file

@ -0,0 +1,10 @@
project(gui CXX)
add_executable(${PROJECT_NAME}
main.cpp
memorycard.cpp
)
target_link_libraries(${PROJECT_NAME}
PUBLIC nana
)

89
src/gui/main.cpp Normal file
View file

@ -0,0 +1,89 @@
#include "nana/gui.hpp"
#include "nana/gui/animation.hpp"
#include "nana/gui/widgets/panel.hpp"
#include "memorycard.hpp"
#include <iostream>
#include <cstdint>
#include <algorithm>
#include <array>
#include <vector>
#include <climits>
#include <fstream>
namespace {
// std::vector<char> make_checker_bitmap (int32_t w, int32_t h, bool inv) {
// const int32_t scanline_size = ((w * 3 * CHAR_BIT + 31) bitand ~31) / CHAR_BIT;
// std::vector<char> retval(
// sizeof(bmp::FileHeader) +
// sizeof(bmp::ImageHeader) +
// scanline_size * h
// );
//
// bmp::FileHeader fhead;
// bmp::ImageHeader ihead;
//
// uint32_t copy_offs = sizeof(bmp::FileHeader) + sizeof(bmp::ImageHeader);
//
// fhead.bfSizeHi = static_cast<uint16_t>(retval.size() >> 16);
// fhead.bfSizeLo = static_cast<uint16_t>(retval.size() & 0xFFFF);
// fhead.bfOffBitsHi = static_cast<uint16_t>(copy_offs >> 16);
// fhead.bfOffBitsLo = static_cast<uint16_t>(copy_offs & 0xFFFF);
// ihead.biWidth = w;
// ihead.biHeight = h;
//
// std::copy(reinterpret_cast<char*>(&fhead), reinterpret_cast<char*>(&fhead + 1), retval.begin());
// std::copy(reinterpret_cast<char*>(&ihead), reinterpret_cast<char*>(&ihead + 1), retval.begin() + sizeof(bmp::FileHeader));
//
// const std::array<char, 6> pixels {
// static_cast<char>(0xf1),
// static_cast<char>(0x96),
// static_cast<char>(0x96),
// static_cast<char>(0x17),
// static_cast<char>(0xc8),
// static_cast<char>(0xc6)
// };
// for (int32_t y = 0; y < h; ++y) {
// for (int32_t x = 0; x < w; ++x) {
// retval[copy_offs + x * 3 + 0] = pixels[(x bitand 1 xor inv) * 3 + 0];
// retval[copy_offs + x * 3 + 1] = pixels[(x bitand 1 xor inv) * 3 + 1];
// retval[copy_offs + x * 3 + 2] = pixels[(x bitand 1 xor inv) * 3 + 2];
// }
// copy_offs += scanline_size;
// }
//
// return retval;
// }
} //unnamed namespace
int main() {
nana::form frm;
std::cout << "Hello world\n";
frm.show();
MemoryCard mc(std::ifstream("/home/michele/emu/psx/WipEout 3 - Special Edition (Europe) (En,Fr,De,Es,It).srm", std::ios::binary));
//MemoryCard mc(std::ifstream("/run/media/michele/roms/michele_epsxe000.mcr", std::ios::binary));
//MemoryCard mc(std::ifstream("/home/michele/emu/psx/Rapid Racer (Europe) (En,Fr,De,Es,It).srm", std::ios::binary));
std::array<nana::animation, 15> icons { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
for (int z = 0; z < 15; ++z) {
nana::frameset fset;
for (const auto& frame : mc.bitmap_icon(z)) {
nana::paint::image img;
img.open(frame.data(), frame.size());
fset.push_back(img);
}
const int x = 5 + 18 * (z % 3);
const int y = 5 + 18 * (z / 3);
nana::animation& ani = icons[z];
ani.push_back(fset);
ani.output(frm, nana::point(x, y));
ani.looped(true);
ani.play();
}
nana::exec();
return 0;
}

165
src/gui/memorycard.cpp Normal file
View file

@ -0,0 +1,165 @@
#include "memorycard.hpp"
#include <algorithm>
#include <iterator>
#include <cassert>
#include <climits>
#include <iomanip>
#define FLOAT_PALETTE_CONV
namespace {
namespace bmp {
const uint16_t g_signature = 'B' bitor (static_cast<int>('M') << 8);
struct FileHeader {
uint32_t bfSize = 0;
uint16_t bfReserved1 = 0;
uint16_t bfReserved2 = 0;
uint32_t bfOffBits = 0;
};
struct ImageHeader {
uint32_t biSize = 40;
int32_t biWidth = 0;
int32_t biHeight = 0;
uint16_t biPlanes = 1;
uint16_t biBitCount = 24;
uint32_t biCompression = 0;
uint32_t biSizeImage = 0;
uint32_t biXPelsPerMeter = 0;
uint32_t biYPelsPerMeter = 0;
uint32_t biClrUsed = 0;
uint32_t biClrImportant = 0;
};
} //namespace bmp
#if defined(FLOAT_PALETTE_CONV)
uint8_t _5bit_to_8bit(int n) {
return static_cast<uint8_t>(static_cast<float>(n) / 0x1F * 255.0f + 0.5f);
}
#endif
std::vector<uint8_t> extract_palette (std::vector<uint8_t>::const_iterator b, std::vector<uint8_t>::const_iterator e) {
std::vector<uint8_t> retval;
retval.reserve(16 * 4);
{
int advance = 96;
while (b != e and advance) {
--advance;
++b;
}
if (advance)
throw std::runtime_error("Not enough data to advance and extract an icon palette");
}
int entries_left = 16;
while (b != e and entries_left) {
--entries_left;
const auto lo = *b;
++b;
if (b == e)
throw std::runtime_error("Not enough data to extract an icon palette entry of 2 bytes");
const auto hi = *b;
++b;
#if defined(FLOAT_PALETTE_CONV)
const uint16_t col = (hi << 8) | lo;
const uint8_t red = _5bit_to_8bit(col & 0x1F);
const uint8_t green = _5bit_to_8bit((col & 0x3E0) >> 5);
const uint8_t blue = _5bit_to_8bit((col & 0x7C00) >> 10);
const uint8_t black_flag = (col & 0x8000) >> 15;
#else
const uint8_t red = (lo & 0x1F) << 3;
const uint8_t green = ((hi & 0x3) << 6) | ((lo & 0xE0) >> 2);
const uint8_t blue = ((hi & 0x7C) << 1);
const uint8_t black_flag = (hi & 0x80) >> 7;
#endif
const uint8_t alpha = (blue | green | red | black_flag ? 0xFF : 0x00);
std::cout << "RGBA: " << std::setw(3) << (int)red << '\t' << (int)green << '\t' << (int)blue << '\t' << (int)alpha << '\t' << (int)black_flag << std::setw(0) << '\n';
retval.push_back(blue);
retval.push_back(green);
retval.push_back(red);
retval.push_back(alpha);
}
if (entries_left)
throw std::runtime_error("Not enough entries in the icon palette");
return retval;
}
} //unnamed namespace
MemoryCard::MemoryCard() :
m_data(8192 * 16)
{
}
MemoryCard::MemoryCard (std::istream&& raw_mc) :
MemoryCard()
{
raw_mc >> std::noskipws;
std::copy_if(
std::istream_iterator<uint8_t>(raw_mc),
std::istream_iterator<uint8_t>(),
m_data.begin(),
[count = m_data.size()](auto&&) mutable { return count && count--; }
);
assert(8192 * 16 == m_data.size());
}
MemoryCard::~MemoryCard() = default;
std::array<std::vector<char>, 3> MemoryCard::bitmap_icon (int slot) const {
const int32_t h = 16, w = 16;
assert(slot < 15);
const auto slot_begin = m_data.begin() + (slot + 1) * 8192;
const auto slot_end = m_data.begin() + (slot + 1) * 8192 + 8192;
auto palette = extract_palette(slot_begin, slot_end);
assert(palette.size() == 16 * 4);
const int32_t palette_padded_size = ((palette.size() * CHAR_BIT + 31) bitand ~31) / CHAR_BIT;
assert(palette.size() == palette_padded_size);
const int32_t bpp = 4;
const int32_t scanline_size = ((w * bpp + 31) bitand ~31) / CHAR_BIT;
const std::size_t data_offset = sizeof(bmp::g_signature) + sizeof(bmp::FileHeader) + sizeof(bmp::ImageHeader) + palette_padded_size;
const std::size_t bmp_byte_size = data_offset + scanline_size * h;
bmp::FileHeader fhead;
bmp::ImageHeader ihead;
fhead.bfSize = static_cast<uint32_t>(bmp_byte_size);
fhead.bfOffBits = static_cast<uint32_t>(data_offset);
ihead.biWidth = h;
ihead.biHeight = w;
ihead.biBitCount = static_cast<uint32_t>(bpp);
ihead.biClrUsed = static_cast<uint32_t>(palette.size() / 4);
ihead.biClrImportant = ihead.biClrUsed;
ihead.biSizeImage = scanline_size * h;
std::array<std::vector<char>, 3> retval;
int32_t icon_num = 0;
for (auto& frame : retval) {
frame.reserve(bmp_byte_size);
std::copy(reinterpret_cast<const char*>(&bmp::g_signature), reinterpret_cast<const char*>(&bmp::g_signature + 1), std::back_inserter(frame));
std::copy(reinterpret_cast<char*>(&fhead), reinterpret_cast<char*>(&fhead + 1), std::back_inserter(frame));
std::copy(reinterpret_cast<char*>(&ihead), reinterpret_cast<char*>(&ihead + 1), std::back_inserter(frame));
std::copy(palette.begin(), palette.end(), std::back_inserter(frame));
assert(palette_padded_size >= palette.size());
std::fill_n(std::back_inserter(frame), palette_padded_size - palette.size(), 0);
assert(frame.size() == data_offset);
frame.resize(data_offset + scanline_size * h);
for (int32_t y = 0; y < h; ++y) {
for (int32_t x = 0; x < w / 2; ++x) {
const uint8_t curr = *(slot_begin + 128 + (w / 2 * y) + 128 * icon_num + x);
frame[data_offset + (h - 1 - y) * scanline_size + x] =
static_cast<uint8_t>(((curr & 0x0f) << 4) | ((curr & 0xf0) >> 4));
}
//std::copy_n(slot_begin + 128 + h / 2 * y, scanline_size, frame.begin() + data_offset + (h - 1 - y) * scanline_size);
}
}
return retval;
}

17
src/gui/memorycard.hpp Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <vector>
#include <iostream>
#include <cstdint>
#include <array>
class MemoryCard {
public:
MemoryCard();
explicit MemoryCard (std::istream&& raw_mc);
~MemoryCard();
std::array<std::vector<char>, 3> bitmap_icon (int slot) const;
private:
std::vector<uint8_t> m_data;
};