Compare commits
3 Commits
93a16f520f
...
ffacff67cf
Author | SHA1 | Date |
---|---|---|
Bananymous | ffacff67cf | |
Bananymous | f43a7fdfb4 | |
Bananymous | 7bb1a3906d |
|
@ -4,6 +4,7 @@ project(libfont CXX)
|
|||
|
||||
set(LIBGUI_SOURCES
|
||||
Font.cpp
|
||||
PSF.cpp
|
||||
)
|
||||
|
||||
add_custom_target(libfont-headers
|
||||
|
|
274
LibFont/Font.cpp
274
LibFont/Font.cpp
|
@ -1,9 +1,7 @@
|
|||
#include <BAN/Debug.h>
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <BAN/UTF8.h>
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
#include <LibFont/PSF.h>
|
||||
|
||||
#if __is_kernel
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
|
@ -11,22 +9,6 @@
|
|||
|
||||
#include <fcntl.h>
|
||||
|
||||
#define PSF1_MAGIC0 0x36
|
||||
#define PSF1_MAGIC1 0x04
|
||||
#define PSF1_MODE512 0x01
|
||||
#define PSF1_MODEHASTAB 0x02
|
||||
#define PSF1_MODEHASSEQ 0x04
|
||||
#define PSF1_STARTSEQ 0xFFFE
|
||||
#define PSF1_SEPARATOR 0xFFFF
|
||||
|
||||
#define PSF2_MAGIC0 0x72
|
||||
#define PSF2_MAGIC1 0xB5
|
||||
#define PSF2_MAGIC2 0x4A
|
||||
#define PSF2_MAGIC3 0x86
|
||||
#define PSF2_HAS_UNICODE_TABLE 0x01
|
||||
#define PSF2_STARTSEQ 0xFE
|
||||
#define PSF2_SEPARATOR 0xFF
|
||||
|
||||
#if __is_kernel
|
||||
extern uint8_t _binary_font_prefs_psf_start[];
|
||||
extern uint8_t _binary_font_prefs_psf_end[];
|
||||
|
@ -39,7 +21,7 @@ namespace LibFont
|
|||
BAN::ErrorOr<Font> Font::prefs()
|
||||
{
|
||||
size_t font_data_size = _binary_font_prefs_psf_end - _binary_font_prefs_psf_start;
|
||||
return parse_psf1(BAN::ConstByteSpan(_binary_font_prefs_psf_start, font_data_size));
|
||||
return load(BAN::ConstByteSpan(_binary_font_prefs_psf_start, font_data_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -48,230 +30,48 @@ namespace LibFont
|
|||
BAN::Vector<uint8_t> file_data;
|
||||
|
||||
#if __is_kernel
|
||||
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
||||
TRY(file_data.resize(inode->size()));
|
||||
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
|
||||
#else
|
||||
char path_buffer[PATH_MAX];
|
||||
strncpy(path_buffer, path.data(), path.size());
|
||||
path_buffer[path.size()] = '\0';
|
||||
|
||||
int fd = open(path_buffer, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
BAN::ScopeGuard file_closer([fd] { close(fd); });
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
TRY(file_data.resize(st.st_size));
|
||||
|
||||
ssize_t total_read = 0;
|
||||
while (total_read < st.st_size)
|
||||
{
|
||||
ssize_t nread = read(fd, file_data.data() + total_read, st.st_size - total_read);
|
||||
if (nread == -1)
|
||||
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
||||
TRY(file_data.resize(inode->size()));
|
||||
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
|
||||
}
|
||||
#else
|
||||
{
|
||||
char path_buffer[PATH_MAX];
|
||||
strncpy(path_buffer, path.data(), path.size());
|
||||
path_buffer[path.size()] = '\0';
|
||||
|
||||
int fd = open(path_buffer, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
total_read += nread;
|
||||
BAN::ScopeGuard file_closer([fd] { close(fd); });
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
TRY(file_data.resize(st.st_size));
|
||||
|
||||
ssize_t total_read = 0;
|
||||
while (total_read < st.st_size)
|
||||
{
|
||||
ssize_t nread = read(fd, file_data.data() + total_read, st.st_size - total_read);
|
||||
if (nread == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
total_read += nread;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (file_data.size() < 4)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (file_data[0] == PSF1_MAGIC0 && file_data[1] == PSF1_MAGIC1)
|
||||
return TRY(parse_psf1(BAN::ConstByteSpan(file_data.span())));
|
||||
|
||||
if (file_data[0] == PSF2_MAGIC0 && file_data[1] == PSF2_MAGIC1 && file_data[2] == PSF2_MAGIC2 && file_data[3] == PSF2_MAGIC3)
|
||||
return TRY(parse_psf2(BAN::ConstByteSpan(file_data.span())));
|
||||
return load(BAN::ConstByteSpan(file_data.span()));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> Font::load(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (is_psf1(font_data))
|
||||
return TRY(parse_psf1(font_data));
|
||||
if (is_psf2(font_data))
|
||||
return TRY(parse_psf2(font_data));
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> Font::parse_psf1(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF1Header
|
||||
{
|
||||
uint8_t magic[2];
|
||||
uint8_t mode;
|
||||
uint8_t char_size;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF1Header>();
|
||||
|
||||
uint32_t glyph_count = header.mode & PSF1_MODE512 ? 512 : 256;
|
||||
uint32_t glyph_size = header.char_size;
|
||||
uint32_t glyph_data_size = glyph_size * glyph_count;
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + sizeof(PSF1Header), glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(glyph_count));
|
||||
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
if (header.mode & (PSF1_MODEHASTAB | PSF1_MODEHASSEQ))
|
||||
{
|
||||
uint32_t current_index = sizeof(PSF1Header) + glyph_data_size;
|
||||
|
||||
uint32_t glyph_index = 0;
|
||||
while (current_index < font_data.size())
|
||||
{
|
||||
uint16_t lo = font_data[current_index];
|
||||
uint16_t hi = font_data[current_index + 1];
|
||||
uint16_t codepoint = (hi << 8) | lo;
|
||||
|
||||
if (codepoint == PSF1_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (codepoint == PSF1_SEPARATOR)
|
||||
{
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * glyph_size));
|
||||
}
|
||||
|
||||
current_index += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * glyph_size));
|
||||
}
|
||||
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
Font result;
|
||||
result.m_glyph_offsets = BAN::move(glyph_offsets);
|
||||
result.m_glyph_data = BAN::move(glyph_data);
|
||||
result.m_width = 8;
|
||||
result.m_height = header.char_size;
|
||||
result.m_pitch = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> Font::parse_psf2(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF2Header
|
||||
{
|
||||
uint8_t magic[4];
|
||||
BAN::LittleEndian<uint32_t> version;
|
||||
BAN::LittleEndian<uint32_t> header_size;
|
||||
BAN::LittleEndian<uint32_t> flags;
|
||||
BAN::LittleEndian<uint32_t> glyph_count;
|
||||
BAN::LittleEndian<uint32_t> glyph_size;
|
||||
BAN::LittleEndian<uint32_t> height;
|
||||
BAN::LittleEndian<uint32_t> width;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF2Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF2Header>();
|
||||
|
||||
uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
|
||||
|
||||
if (font_data.size() < glyph_data_size + header.header_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + header.header_size, glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(400));
|
||||
|
||||
bool invalid_utf = false;
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
uint8_t bytes[4] {};
|
||||
uint32_t byte_index = 0;
|
||||
if (header.flags & PSF2_HAS_UNICODE_TABLE)
|
||||
{
|
||||
uint32_t glyph_index = 0;
|
||||
for (uint32_t i = glyph_data_size + header.header_size; i < font_data.size(); i++)
|
||||
{
|
||||
uint8_t byte = font_data[i];
|
||||
|
||||
if (byte == PSF2_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (byte == PSF2_SEPARATOR)
|
||||
{
|
||||
if (byte_index)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(byte_index < 4);
|
||||
bytes[byte_index++] = byte;
|
||||
|
||||
uint32_t len = BAN::UTF8::byte_length(bytes[0]);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
else if (len == byte_index)
|
||||
{
|
||||
uint32_t codepoint = BAN::UTF8::to_codepoint(bytes);
|
||||
if (codepoint == BAN::UTF8::invalid)
|
||||
invalid_utf = true;
|
||||
else if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * header.glyph_size));
|
||||
byte_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < header.glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * header.glyph_size));
|
||||
}
|
||||
|
||||
if (invalid_utf)
|
||||
dwarnln("Font contains invalid UTF-8 codepoint(s)");
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
Font result;
|
||||
result.m_glyph_offsets = BAN::move(glyph_offsets);
|
||||
result.m_glyph_data = BAN::move(glyph_data);
|
||||
result.m_width = header.width;
|
||||
result.m_height = header.height;
|
||||
result.m_pitch = header.glyph_size / header.height;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
#include <BAN/Debug.h>
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/UTF8.h>
|
||||
|
||||
#include <LibFont/PSF.h>
|
||||
|
||||
#define PSF1_MAGIC0 0x36
|
||||
#define PSF1_MAGIC1 0x04
|
||||
#define PSF1_MODE512 0x01
|
||||
#define PSF1_MODEHASTAB 0x02
|
||||
#define PSF1_MODEHASSEQ 0x04
|
||||
#define PSF1_STARTSEQ 0xFFFE
|
||||
#define PSF1_SEPARATOR 0xFFFF
|
||||
|
||||
#define PSF2_MAGIC0 0x72
|
||||
#define PSF2_MAGIC1 0xB5
|
||||
#define PSF2_MAGIC2 0x4A
|
||||
#define PSF2_MAGIC3 0x86
|
||||
#define PSF2_HAS_UNICODE_TABLE 0x01
|
||||
#define PSF2_STARTSEQ 0xFE
|
||||
#define PSF2_SEPARATOR 0xFF
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
bool is_psf1(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (font_data.size() < 2)
|
||||
return false;
|
||||
return font_data[0] == PSF1_MAGIC0 && font_data[1] == PSF1_MAGIC1;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF1Header
|
||||
{
|
||||
uint8_t magic[2];
|
||||
uint8_t mode;
|
||||
uint8_t char_size;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF1Header>();
|
||||
|
||||
uint32_t glyph_count = header.mode & PSF1_MODE512 ? 512 : 256;
|
||||
uint32_t glyph_size = header.char_size;
|
||||
uint32_t glyph_data_size = glyph_size * glyph_count;
|
||||
|
||||
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + sizeof(PSF1Header), glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(glyph_count));
|
||||
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
if (header.mode & (PSF1_MODEHASTAB | PSF1_MODEHASSEQ))
|
||||
{
|
||||
uint32_t current_index = sizeof(PSF1Header) + glyph_data_size;
|
||||
|
||||
uint32_t glyph_index = 0;
|
||||
while (current_index < font_data.size())
|
||||
{
|
||||
uint16_t lo = font_data[current_index];
|
||||
uint16_t hi = font_data[current_index + 1];
|
||||
uint16_t codepoint = (hi << 8) | lo;
|
||||
|
||||
if (codepoint == PSF1_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (codepoint == PSF1_SEPARATOR)
|
||||
{
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * glyph_size));
|
||||
}
|
||||
|
||||
current_index += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * glyph_size));
|
||||
}
|
||||
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
return Font(BAN::move(glyph_offsets), BAN::move(glyph_data), 8, header.char_size, 1);
|
||||
}
|
||||
|
||||
bool is_psf2(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
if (font_data.size() < 4)
|
||||
return false;
|
||||
return font_data[0] == PSF2_MAGIC0 && font_data[1] == PSF2_MAGIC1 && font_data[2] == PSF2_MAGIC2 && font_data[3] == PSF2_MAGIC3;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan font_data)
|
||||
{
|
||||
struct PSF2Header
|
||||
{
|
||||
uint8_t magic[4];
|
||||
BAN::LittleEndian<uint32_t> version;
|
||||
BAN::LittleEndian<uint32_t> header_size;
|
||||
BAN::LittleEndian<uint32_t> flags;
|
||||
BAN::LittleEndian<uint32_t> glyph_count;
|
||||
BAN::LittleEndian<uint32_t> glyph_size;
|
||||
BAN::LittleEndian<uint32_t> height;
|
||||
BAN::LittleEndian<uint32_t> width;
|
||||
};
|
||||
|
||||
if (font_data.size() < sizeof(PSF2Header))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const auto& header = font_data.as<const PSF2Header>();
|
||||
|
||||
uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
|
||||
|
||||
if (font_data.size() < glyph_data_size + header.header_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
BAN::Vector<uint8_t> glyph_data;
|
||||
TRY(glyph_data.resize(glyph_data_size));
|
||||
memcpy(glyph_data.data(), font_data.data() + header.header_size, glyph_data_size);
|
||||
|
||||
BAN::HashMap<uint32_t, uint32_t> glyph_offsets;
|
||||
TRY(glyph_offsets.reserve(400));
|
||||
|
||||
bool invalid_utf = false;
|
||||
bool codepoint_redef = false;
|
||||
bool codepoint_sequence = false;
|
||||
|
||||
uint8_t bytes[4] {};
|
||||
uint32_t byte_index = 0;
|
||||
if (header.flags & PSF2_HAS_UNICODE_TABLE)
|
||||
{
|
||||
uint32_t glyph_index = 0;
|
||||
for (uint32_t i = glyph_data_size + header.header_size; i < font_data.size(); i++)
|
||||
{
|
||||
uint8_t byte = font_data[i];
|
||||
|
||||
if (byte == PSF2_STARTSEQ)
|
||||
{
|
||||
codepoint_sequence = true;
|
||||
break;
|
||||
}
|
||||
else if (byte == PSF2_SEPARATOR)
|
||||
{
|
||||
if (byte_index)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
glyph_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(byte_index < 4);
|
||||
bytes[byte_index++] = byte;
|
||||
|
||||
uint32_t len = BAN::UTF8::byte_length(bytes[0]);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
}
|
||||
else if (len == byte_index)
|
||||
{
|
||||
uint32_t codepoint = BAN::UTF8::to_codepoint(bytes);
|
||||
if (codepoint == BAN::UTF8::invalid)
|
||||
invalid_utf = true;
|
||||
else if (glyph_offsets.contains(codepoint))
|
||||
codepoint_redef = true;
|
||||
else
|
||||
TRY(glyph_offsets.insert(codepoint, glyph_index * header.glyph_size));
|
||||
byte_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < header.glyph_count; i++)
|
||||
TRY(glyph_offsets.insert(i, i * header.glyph_size));
|
||||
}
|
||||
|
||||
if (invalid_utf)
|
||||
dwarnln("Font contains invalid UTF-8 codepoint(s)");
|
||||
if (codepoint_redef)
|
||||
dwarnln("Font contains multiple definitions for same codepoint(s)");
|
||||
if (codepoint_sequence)
|
||||
dwarnln("Font contains codepoint sequences (not supported)");
|
||||
|
||||
return Font(BAN::move(glyph_offsets), BAN::move(glyph_data), header.width, header.height, header.glyph_size / header.height);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
@ -10,7 +11,17 @@ namespace LibFont
|
|||
class Font
|
||||
{
|
||||
public:
|
||||
Font() = default;
|
||||
Font(BAN::HashMap<uint32_t, uint32_t>&& glyph_offsets, BAN::Vector<uint8_t>&& glyph_data, uint32_t width, uint32_t height, uint32_t pitch)
|
||||
: m_glyph_offsets(BAN::move(glyph_offsets))
|
||||
, m_glyph_data(BAN::move(glyph_data))
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
, m_pitch(pitch)
|
||||
{ }
|
||||
|
||||
static BAN::ErrorOr<Font> load(BAN::StringView path);
|
||||
static BAN::ErrorOr<Font> load(BAN::ConstByteSpan font_data);
|
||||
#if __is_kernel
|
||||
static BAN::ErrorOr<Font> prefs();
|
||||
#endif
|
||||
|
@ -28,10 +39,6 @@ namespace LibFont
|
|||
return m_glyph_data.data() + it->value;
|
||||
}
|
||||
|
||||
private:
|
||||
static BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan);
|
||||
static BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan);
|
||||
|
||||
private:
|
||||
BAN::HashMap<uint32_t, uint32_t> m_glyph_offsets;
|
||||
BAN::Vector<uint8_t> m_glyph_data;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibFont/Font.h>
|
||||
|
||||
namespace LibFont
|
||||
{
|
||||
|
||||
bool is_psf1(BAN::ConstByteSpan);
|
||||
BAN::ErrorOr<Font> parse_psf1(BAN::ConstByteSpan);
|
||||
|
||||
bool is_psf2(BAN::ConstByteSpan);
|
||||
BAN::ErrorOr<Font> parse_psf2(BAN::ConstByteSpan);
|
||||
|
||||
}
|
|
@ -60,7 +60,7 @@ Each major component and library has its own subdirectory (kernel, userspace, li
|
|||
### Needed packages
|
||||
|
||||
#### apt (tested on ubuntu 22.04)
|
||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86```
|
||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
|
||||
|
||||
#### pacman
|
||||
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
||||
|
|
|
@ -150,6 +150,7 @@ set(LIBELF_SOURCES
|
|||
|
||||
set(LIBFONT_SOURCES
|
||||
../LibFont/Font.cpp
|
||||
../LibFont/PSF.cpp
|
||||
)
|
||||
|
||||
set(LIBINPUT_SOURCE
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
From 70cb1210ba2f6e1d922922f66f32efcf7bec51e1 Mon Sep 17 00:00:00 2001
|
||||
From 0f37d9f2df042eb8ba021dd91b898c1f07d86b58 Mon Sep 17 00:00:00 2001
|
||||
From: Bananymous <bananymousosq@gmail.com>
|
||||
Date: Wed, 3 Apr 2024 17:57:11 +0300
|
||||
Date: Mon, 3 Jun 2024 20:01:40 +0300
|
||||
Subject: [PATCH] Add support for banan-os
|
||||
|
||||
Add Makefile and implement required functions.
|
||||
---
|
||||
doomgeneric/Makefile.banan_os | 58 +++++++
|
||||
doomgeneric/doomgeneric_banan_os.cpp | 224 +++++++++++++++++++++++++++
|
||||
2 files changed, 282 insertions(+)
|
||||
doomgeneric/Makefile.banan_os | 57 +++++++++++
|
||||
doomgeneric/doomgeneric_banan_os.cpp | 144 +++++++++++++++++++++++++++
|
||||
2 files changed, 200 insertions(+)
|
||||
create mode 100644 doomgeneric/Makefile.banan_os
|
||||
create mode 100644 doomgeneric/doomgeneric_banan_os.cpp
|
||||
|
||||
diff --git a/doomgeneric/Makefile.banan_os b/doomgeneric/Makefile.banan_os
|
||||
new file mode 100644
|
||||
index 0000000..453bed7
|
||||
index 0000000..0878148
|
||||
--- /dev/null
|
||||
+++ b/doomgeneric/Makefile.banan_os
|
||||
@@ -0,0 +1,58 @@
|
||||
@@ -0,0 +1,57 @@
|
||||
+################################################################
|
||||
+#
|
||||
+# $Id:$
|
||||
|
@ -32,11 +31,10 @@ index 0000000..453bed7
|
|||
+
|
||||
+CC=$(BANAN_TOOLCHAIN_PREFIX)/bin/$(BANAN_ARCH)-banan_os-gcc
|
||||
+CXX=$(BANAN_TOOLCHAIN_PREFIX)/bin/$(BANAN_ARCH)-banan_os-g++
|
||||
+CFLAGS+=-O2 -g
|
||||
+CFLAGS+=-Wall -DNORMALUNIX -DLINUX -DSNDSERV -D_DEFAULT_SOURCE
|
||||
+CFLAGS+=-O3 -Wall -DNORMALUNIX -DLINUX -DSNDSERV -D_DEFAULT_SOURCE
|
||||
+CXXFLAGS+=$(CFLAGS) --std=c++20
|
||||
+LDFLAGS+=
|
||||
+LIBS+=
|
||||
+LIBS+=-lgui -linput -lstdc++
|
||||
+
|
||||
+# subdirectory for objects
|
||||
+OBJDIR=build-$(BANAN_ARCH)
|
||||
|
@ -75,12 +73,13 @@ index 0000000..453bed7
|
|||
+
|
||||
+print:
|
||||
+ @echo OBJS: $(OBJS)
|
||||
\ No newline at end of file
|
||||
diff --git a/doomgeneric/doomgeneric_banan_os.cpp b/doomgeneric/doomgeneric_banan_os.cpp
|
||||
new file mode 100644
|
||||
index 0000000..e32c861
|
||||
index 0000000..9161771
|
||||
--- /dev/null
|
||||
+++ b/doomgeneric/doomgeneric_banan_os.cpp
|
||||
@@ -0,0 +1,224 @@
|
||||
@@ -0,0 +1,144 @@
|
||||
+extern "C"
|
||||
+{
|
||||
+#include "doomgeneric.h"
|
||||
|
@ -97,161 +96,81 @@ index 0000000..e32c861
|
|||
+#include <sys/mman.h>
|
||||
+#include <time.h>
|
||||
+
|
||||
+#include <BAN/Math.h>
|
||||
+#include <kernel/Input/KeyEvent.h>
|
||||
+#include <LibGUI/Window.h>
|
||||
+
|
||||
+extern "C"
|
||||
+{
|
||||
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
+
|
||||
+static struct framebuffer_info_t s_fb_info;
|
||||
+static uint32_t* s_framebuffer = NULL;
|
||||
+
|
||||
+static int s_input_fd;
|
||||
+static BAN::UniqPtr<LibGUI::Window> s_window;
|
||||
+
|
||||
+static constexpr size_t s_key_queue_size = 16;
|
||||
+static unsigned short s_key_queue[s_key_queue_size];
|
||||
+static size_t s_key_read_index = 0;
|
||||
+static size_t s_key_write_index = 0;
|
||||
+
|
||||
+void handle_key_input()
|
||||
+extern "C"
|
||||
+{
|
||||
+ Kernel::Input::KeyEvent event;
|
||||
+ if (read(s_input_fd, &event, sizeof(event)) <= 0)
|
||||
+ return;
|
||||
+
|
||||
+ unsigned short doom_key = 0;
|
||||
+
|
||||
+ switch (event.keycode)
|
||||
+ {
|
||||
+ case 109:
|
||||
+ doom_key = KEY_ENTER;
|
||||
+ break;
|
||||
+ case 0:
|
||||
+ doom_key = KEY_ESCAPE;
|
||||
+ break;
|
||||
+ case 193:
|
||||
+ doom_key = KEY_LEFTARROW;
|
||||
+ break;
|
||||
+ case 192:
|
||||
+ doom_key = KEY_UPARROW;
|
||||
+ break;
|
||||
+ case 195:
|
||||
+ doom_key = KEY_RIGHTARROW;
|
||||
+ break;
|
||||
+ case 194:
|
||||
+ doom_key = KEY_DOWNARROW;
|
||||
+ break;
|
||||
+ case 160:
|
||||
+ case 165:
|
||||
+ doom_key = KEY_FIRE;
|
||||
+ break;
|
||||
+ case 163:
|
||||
+ doom_key = KEY_USE;
|
||||
+ break;
|
||||
+ case 128:
|
||||
+ case 140:
|
||||
+ doom_key = KEY_RSHIFT;
|
||||
+ break;
|
||||
+
|
||||
+ case 65: doom_key = tolower('Q'); break;
|
||||
+ case 66: doom_key = tolower('W'); break;
|
||||
+ case 67: doom_key = tolower('E'); break;
|
||||
+ case 68: doom_key = tolower('R'); break;
|
||||
+ case 69: doom_key = tolower('T'); break;
|
||||
+ case 70: doom_key = tolower('Y'); break;
|
||||
+ case 71: doom_key = tolower('U'); break;
|
||||
+ case 72: doom_key = tolower('I'); break;
|
||||
+ case 73: doom_key = tolower('O'); break;
|
||||
+ case 74: doom_key = tolower('P'); break;
|
||||
+
|
||||
+ case 97: doom_key = tolower('A'); break;
|
||||
+ case 98: doom_key = tolower('S'); break;
|
||||
+ case 99: doom_key = tolower('D'); break;
|
||||
+ case 100: doom_key = tolower('F'); break;
|
||||
+ case 101: doom_key = tolower('G'); break;
|
||||
+ case 102: doom_key = tolower('H'); break;
|
||||
+ case 103: doom_key = tolower('J'); break;
|
||||
+ case 104: doom_key = tolower('K'); break;
|
||||
+ case 105: doom_key = tolower('L'); break;
|
||||
+
|
||||
+ case 130: doom_key = tolower('Z'); break;
|
||||
+ case 131: doom_key = tolower('X'); break;
|
||||
+ case 132: doom_key = tolower('C'); break;
|
||||
+ case 133: doom_key = tolower('V'); break;
|
||||
+ case 134: doom_key = tolower('B'); break;
|
||||
+ case 135: doom_key = tolower('N'); break;
|
||||
+ case 136: doom_key = tolower('M'); break;
|
||||
+ }
|
||||
+
|
||||
+ doom_key |= (int)event.pressed() << 8;
|
||||
+
|
||||
+ s_key_queue[s_key_write_index] = doom_key;
|
||||
+ s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
|
||||
+}
|
||||
+
|
||||
+void DG_Init()
|
||||
+{
|
||||
+ s_input_fd = open("/dev/input0", O_RDONLY | O_NONBLOCK);
|
||||
+ if (s_input_fd == -1)
|
||||
+ {
|
||||
+ perror("open");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ s_window = MUST(LibGUI::Window::create(DOOMGENERIC_RESX, DOOMGENERIC_RESY, "DOOM"sv));
|
||||
+ s_window->set_key_event_callback(
|
||||
+ [](LibGUI::EventPacket::KeyEvent event)
|
||||
+ {
|
||||
+ unsigned short doom_key = 0;
|
||||
+ switch (event.key)
|
||||
+ {
|
||||
+ case LibInput::Key::Enter:
|
||||
+ doom_key = KEY_ENTER;
|
||||
+ break;
|
||||
+ case LibInput::Key::Escape:
|
||||
+ doom_key = KEY_ESCAPE;
|
||||
+ break;
|
||||
+ case LibInput::Key::ArrowLeft:
|
||||
+ doom_key = KEY_LEFTARROW;
|
||||
+ break;
|
||||
+ case LibInput::Key::ArrowUp:
|
||||
+ doom_key = KEY_UPARROW;
|
||||
+ break;
|
||||
+ case LibInput::Key::ArrowRight:
|
||||
+ doom_key = KEY_RIGHTARROW;
|
||||
+ break;
|
||||
+ case LibInput::Key::ArrowDown:
|
||||
+ doom_key = KEY_DOWNARROW;
|
||||
+ break;
|
||||
+ case LibInput::Key::LeftCtrl:
|
||||
+ case LibInput::Key::RightCtrl:
|
||||
+ doom_key = KEY_FIRE;
|
||||
+ break;
|
||||
+ case LibInput::Key::Space:
|
||||
+ doom_key = KEY_USE;
|
||||
+ break;
|
||||
+ case LibInput::Key::RightShift:
|
||||
+ doom_key = KEY_RSHIFT;
|
||||
+ break;
|
||||
+ default:
|
||||
+ {
|
||||
+ const char* utf8 = LibInput::key_to_utf8(event.key, event.modifier);
|
||||
+ if (utf8 && strlen(utf8) == 1 && isalpha(*utf8))
|
||||
+ doom_key = tolower(*utf8);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ int fd = open("/dev/fb0", O_RDWR);
|
||||
+ if (fd == -1)
|
||||
+ {
|
||||
+ perror("open");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ if (doom_key == 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (pread(fd, &s_fb_info, sizeof(s_fb_info), -1) == -1)
|
||||
+ {
|
||||
+ perror("pread");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ size_t bytes = s_fb_info.width * s_fb_info.height * (BANAN_FB_BPP / 8);
|
||||
+
|
||||
+ s_framebuffer = (uint32_t*)mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
+ if (s_framebuffer == NULL)
|
||||
+ {
|
||||
+ perror("mmap");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ memset(s_framebuffer, 0, bytes);
|
||||
+ msync(s_framebuffer, bytes, MS_SYNC);
|
||||
+
|
||||
+ if (tty_ctrl(STDIN_FILENO, TTY_CMD_UNSET, TTY_FLAG_ENABLE_INPUT) == -1)
|
||||
+ {
|
||||
+ perror("tty_ctrl");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ atexit([]() { tty_ctrl(STDIN_FILENO, TTY_CMD_SET, TTY_FLAG_ENABLE_INPUT); });
|
||||
+ s_key_queue[s_key_write_index] = doom_key | (int)event.pressed() << 8;
|
||||
+ s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
|
||||
+ }
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void DG_DrawFrame()
|
||||
+{
|
||||
+ if (s_framebuffer == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ assert(BANAN_FB_BPP == 32);
|
||||
+
|
||||
+ for (size_t y = 0; y < BAN::Math::min<uint32_t>(s_fb_info.height, DOOMGENERIC_RESY); y++)
|
||||
+ {
|
||||
+ memcpy(
|
||||
+ s_framebuffer + y * s_fb_info.width,
|
||||
+ DG_ScreenBuffer + y * DOOMGENERIC_RESX,
|
||||
+ BAN::Math::min<uint32_t>(s_fb_info.width, DOOMGENERIC_RESX) * sizeof(uint32_t)
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ int ret = msync(s_framebuffer, s_fb_info.width * s_fb_info.height * 4, MS_SYNC);
|
||||
+ assert(ret != -1);
|
||||
+
|
||||
+ handle_key_input();
|
||||
+ for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
|
||||
+ for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
|
||||
+ s_window->set_pixel(x, y, DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
|
||||
+ s_window->invalidate();
|
||||
+ s_window->poll_events();
|
||||
+}
|
||||
+
|
||||
+void DG_SleepMs(uint32_t ms)
|
||||
|
@ -306,5 +225,5 @@ index 0000000..e32c861
|
|||
+
|
||||
+}
|
||||
--
|
||||
2.44.0
|
||||
2.45.2
|
||||
|
||||
|
|
|
@ -60,7 +60,11 @@ run_bochs () {
|
|||
$BANAN_SCRIPT_DIR/bochs.sh $@
|
||||
}
|
||||
|
||||
if [[ -c /dev/kvm ]]; then
|
||||
if type kvm-ok &> /dev/null; then
|
||||
if kvm-ok &> /dev/null; then
|
||||
QEMU_ACCEL="-accel kvm"
|
||||
fi
|
||||
elif [[ -c /dev/kvm ]]; then
|
||||
if [[ -r /dev/kvm ]] && [[ -w /dev/kvm ]]; then
|
||||
QEMU_ACCEL="-accel kvm"
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue