Compare commits

...

8 Commits

Author SHA1 Message Date
Bananymous 06015d006d ports/binutils: Fix compilation when zstd is installed
binutils uses pkg-config to find zstd for the host when building. If our
zstd port is installed, it finds it instead and ends up including our
own sysroot which is incompatible with host's.

unsetting pkg-config related variables fixes this and allows binutils to
build fine even when zstd is installed. We can now make it a dependency.
2025-08-11 03:45:38 +03:00
Bananymous 0dbfd8ac66 ports/quake2: Use SDL2 instead of our own frontend 2025-08-11 03:45:38 +03:00
Bananymous 58c1fd36b9 ports/tinygb: Use SDL2 instead of our own frontend 2025-08-11 03:45:38 +03:00
Bananymous 2f725848f4 ports/doom: Use SDL2 instead of our own frontend
This allows doom to play sounds!
2025-08-11 03:45:38 +03:00
Bananymous 6250710bbd ports: Add SDL2_mixer port
This allows some ports to use audio :D

I did not port any audio libraries so loading sounds probably doesn't
work :D
2025-08-11 03:45:38 +03:00
Bananymous 028024b0da ports: Add timidity port 2025-08-11 03:45:38 +03:00
Bananymous 4f61230506 init: Start AudioServer on boot 2025-08-11 03:45:38 +03:00
Bananymous 309ec660b6 Kernel/LibC: Implement chroot 2025-08-11 03:45:38 +03:00
31 changed files with 350 additions and 1299 deletions

View File

@ -20,6 +20,6 @@ namespace Kernel::ELF
BAN::Vector<BAN::UniqPtr<MemoryRegion>> regions;
};
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode>, const Credentials&, PageTable&);
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> root, BAN::RefPtr<Inode> inode, const Credentials&, PageTable&);
}

View File

@ -71,13 +71,13 @@ namespace Kernel
File root_file()
{
return File(root_inode(), "/"_sv);
return File { root_inode(), "/"_sv };
}
BAN::ErrorOr<File> file_from_relative_path(const File& parent, const Credentials&, BAN::StringView, int);
BAN::ErrorOr<File> file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags)
BAN::ErrorOr<File> file_from_relative_path(BAN::RefPtr<Inode> root_inode, const File& parent, const Credentials&, BAN::StringView, int);
BAN::ErrorOr<File> file_from_absolute_path(BAN::RefPtr<Inode> root_inode, const Credentials& credentials, BAN::StringView path, int flags)
{
return file_from_relative_path(root_file(), credentials, path, flags);
return file_from_relative_path(root_inode, File { root_inode, "/"_sv }, credentials, path, flags);
}
private:

View File

@ -5,6 +5,7 @@
#include <BAN/WeakPtr.h>
#include <kernel/FS/Socket.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLock.h>
namespace Kernel
@ -39,8 +40,8 @@ namespace Kernel
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
bool is_bound() const { return !m_bound_path.empty(); }
bool is_bound_to_unused() const { return m_bound_path == "X"_sv; }
bool is_bound() const { return !m_bound_file.canonical_path.empty(); }
bool is_bound_to_unused() const { return !m_bound_file.inode; }
bool is_streaming() const;
@ -63,7 +64,7 @@ namespace Kernel
private:
const Socket::Type m_socket_type;
BAN::String m_bound_path;
VirtualFileSystem::File m_bound_file;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;

View File

@ -76,6 +76,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_getcwd(char* buffer, size_t size);
BAN::ErrorOr<long> sys_chdir(const char* path);
BAN::ErrorOr<long> sys_fchdir(int fildes);
BAN::ErrorOr<long> sys_chroot(const char* path);
BAN::ErrorOr<long> sys_setuid(uid_t);
BAN::ErrorOr<long> sys_setgid(gid_t);
@ -234,6 +235,7 @@ namespace Kernel
static void update_alarm_queue();
const VirtualFileSystem::File& working_directory() const { return m_working_directory; }
const VirtualFileSystem::File& root_file() const { return m_root_file; }
private:
Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp);
@ -313,6 +315,7 @@ namespace Kernel
mutable Mutex m_process_lock;
VirtualFileSystem::File m_working_directory;
VirtualFileSystem::File m_root_file;
BAN::Vector<Thread*> m_threads;

View File

@ -104,7 +104,7 @@ namespace Kernel::ELF
return BAN::move(program_headers);
}
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> inode, const Credentials& credentials, PageTable& page_table)
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> root, BAN::RefPtr<Inode> inode, const Credentials& credentials, PageTable& page_table)
{
auto file_header = TRY(read_and_validate_file_header(inode));
auto program_headers = TRY(read_program_headers(inode, file_header));
@ -143,7 +143,7 @@ namespace Kernel::ELF
if (!interpreter.empty())
{
auto interpreter_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(credentials, interpreter, O_EXEC)).inode;
auto interpreter_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(root, credentials, interpreter, O_EXEC)).inode;
auto interpreter_file_header = TRY(read_and_validate_file_header(interpreter_inode));
auto interpreter_program_headers = TRY(read_program_headers(interpreter_inode, interpreter_file_header));

View File

@ -186,7 +186,8 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, BAN::StringView block_device_path, BAN::StringView target)
{
auto block_device_file = TRY(file_from_absolute_path(credentials, block_device_path, true));
// TODO: allow custom root
auto block_device_file = TRY(file_from_absolute_path(root_inode(), credentials, block_device_path, true));
if (!block_device_file.inode->is_device())
return BAN::Error::from_errno(ENOTBLK);
@ -200,7 +201,8 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, BAN::RefPtr<FileSystem> file_system, BAN::StringView path)
{
auto file = TRY(file_from_absolute_path(credentials, path, true));
// TODO: allow custom root
auto file = TRY(file_from_absolute_path(root_inode(), credentials, path, true));
if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
@ -227,7 +229,7 @@ namespace Kernel
return nullptr;
}
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_relative_path(const File& parent, const Credentials& credentials, BAN::StringView path, int flags)
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_relative_path(BAN::RefPtr<Inode> root_inode, const File& parent, const Credentials& credentials, BAN::StringView path, int flags)
{
LockGuard _(m_mutex);
@ -269,6 +271,8 @@ namespace Kernel
auto orig = inode;
// resolve file name
{
if (!(inode == root_inode && path_part == ".."_sv))
{
auto parent_inode = inode;
if (path_part == ".."_sv)
@ -277,6 +281,7 @@ namespace Kernel
if (!parent_inode->can_access(credentials, O_SEARCH))
return BAN::Error::from_errno(EACCES);
inode = TRY(parent_inode->find_inode(path_part));
}
if (path_part == ".."_sv)
{
@ -310,7 +315,7 @@ namespace Kernel
if (link_target.front() == '/')
{
inode = root_inode();
inode = root_inode;
canonical_path.clear();
}
else

View File

@ -13,7 +13,15 @@
namespace Kernel
{
static BAN::HashMap<BAN::String, BAN::WeakPtr<UnixDomainSocket>> s_bound_sockets;
struct UnixSocketHash
{
BAN::hash_t operator()(const BAN::RefPtr<Inode>& socket)
{
return BAN::hash<const Inode*>{}(socket.ptr());
}
};
static BAN::HashMap<BAN::RefPtr<Inode>, BAN::WeakPtr<UnixDomainSocket>, UnixSocketHash> s_bound_sockets;
static SpinLock s_bound_socket_lock;
static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE;
@ -57,9 +65,7 @@ namespace Kernel
if (is_bound() && !is_bound_to_unused())
{
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(m_bound_path);
if (it != s_bound_sockets.end())
s_bound_sockets.remove(it);
s_bound_sockets.remove(m_bound_file.inode);
}
if (m_info.has<ConnectionInfo>())
{
@ -117,17 +123,22 @@ namespace Kernel
return_inode = reinterpret_cast<UnixDomainSocket*>(return_inode_tmp.ptr());
}
TRY(return_inode->m_bound_path.push_back('X'));
TRY(return_inode->m_bound_file.canonical_path.push_back('X'));
return_inode->m_info.get<ConnectionInfo>().connection = TRY(pending->get_weak_ptr());
pending->m_info.get<ConnectionInfo>().connection = TRY(return_inode->get_weak_ptr());
pending->m_info.get<ConnectionInfo>().connection_done = true;
if (address && address_len && !is_bound_to_unused())
{
size_t copy_len = BAN::Math::min<size_t>(*address_len, sizeof(sockaddr) + m_bound_path.size() + 1);
auto& sockaddr_un = *reinterpret_cast<struct sockaddr_un*>(address);
sockaddr_un.sun_family = AF_UNIX;
strncpy(sockaddr_un.sun_path, pending->m_bound_path.data(), copy_len);
sockaddr_un sa_un {
.sun_family = AF_UNIX,
.sun_path {},
};
strcpy(sa_un.sun_path, pending->m_bound_file.canonical_path.data());
const size_t to_copy = BAN::Math::min<size_t>(*address_len, sizeof(sockaddr_un));
memcpy(address, &sa_un, to_copy);
*address_len = to_copy;
}
return TRY(Process::current().open_inode(VirtualFileSystem::File(return_inode, "<unix socket>"_sv), O_RDWR | flags));
@ -141,10 +152,11 @@ namespace Kernel
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EAFNOSUPPORT);
if (!is_bound())
TRY(m_bound_path.push_back('X'));
TRY(m_bound_file.canonical_path.push_back('X'));
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_RDWR
@ -154,7 +166,7 @@ namespace Kernel
{
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(file.canonical_path);
auto it = s_bound_sockets.find(file.inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(ECONNREFUSED);
target = it->value.lock();
@ -236,7 +248,7 @@ namespace Kernel
// FIXME: This feels sketchy
auto parent_file = bind_path.front() == '/'
? VirtualFileSystem::get().root_file()
? TRY(Process::current().root_file().clone())
: TRY(Process::current().working_directory().clone());
if (auto ret = Process::current().create_file_or_dir(AT_FDCWD, bind_path.data(), 0755 | S_IFSOCK); ret.is_error())
{
@ -245,6 +257,7 @@ namespace Kernel
return ret.release_error();
}
auto file = TRY(VirtualFileSystem::get().file_from_relative_path(
Process::current().root_file().inode,
parent_file,
Process::current().credentials(),
bind_path,
@ -252,10 +265,10 @@ namespace Kernel
));
SpinLockGuard _(s_bound_socket_lock);
if (s_bound_sockets.contains(file.canonical_path))
if (s_bound_sockets.contains(file.inode))
return BAN::Error::from_errno(EADDRINUSE);
TRY(s_bound_sockets.emplace(file.canonical_path, TRY(get_weak_ptr())));
m_bound_path = BAN::move(file.canonical_path);
TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr())));
m_bound_file = BAN::move(file);
return {};
}
@ -354,14 +367,21 @@ namespace Kernel
}
else
{
BAN::String canonical_path;
BAN::RefPtr<Inode> target_inode;
if (!address)
{
auto& connectionless_info = m_info.get<ConnectionlessInfo>();
if (connectionless_info.peer_address.empty())
return BAN::Error::from_errno(EDESTADDRREQ);
TRY(canonical_path.append(connectionless_info.peer_address));
auto absolute_path = TRY(Process::current().absolute_path_of(connectionless_info.peer_address));
target_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_RDWR
)).inode;
}
else
{
@ -372,17 +392,16 @@ namespace Kernel
return BAN::Error::from_errno(EAFNOSUPPORT);
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
target_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_WRONLY
));
canonical_path = BAN::move(file.canonical_path);
)).inode;
}
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(canonical_path);
auto it = s_bound_sockets.find(target_inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(EDESTADDRREQ);
auto target = it->value.lock();
@ -449,20 +468,11 @@ namespace Kernel
if (!connection)
return BAN::Error::from_errno(ENOTCONN);
sockaddr_un sa_un;
sa_un.sun_family = AF_UNIX;
sa_un.sun_path[0] = 0;
{
SpinLockGuard _(s_bound_socket_lock);
for (auto& [path, socket] : s_bound_sockets)
{
if (socket.lock() != connection)
continue;
strcpy(sa_un.sun_path, path.data());
break;
}
}
sockaddr_un sa_un {
.sun_family = AF_UNIX,
.sun_path = {},
};
strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data());
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
memcpy(address, &sa_un, to_copy);

View File

@ -77,7 +77,7 @@ namespace Kernel
BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
{
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)), flags);
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(Process::current().root_file().inode, m_credentials, absolute_path, flags)), flags);
}
struct SocketInfo

View File

@ -103,6 +103,8 @@ namespace Kernel
auto* process = create_process(credentials, 0);
process->m_working_directory = VirtualFileSystem::get().root_file();
process->m_root_file = VirtualFileSystem::get().root_file();
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
TRY(process->m_cmdline.emplace_back());
@ -118,7 +120,7 @@ namespace Kernel
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
auto executable_inode = executable_file.inode;
auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table()));
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
process->m_mapped_regions = BAN::move(executable.regions);
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
@ -456,7 +458,7 @@ namespace Kernel
auto parent_file = TRY(find_relative_parent(fd, path));
auto file = path
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
? TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent_file, m_credentials, path, flags))
: BAN::move(parent_file);
return file;
@ -480,7 +482,7 @@ namespace Kernel
if (auto index = path_sv.rfind('/'); index.has_value())
{
parent = TRY(VirtualFileSystem::get().file_from_relative_path(relative_parent, m_credentials, path_sv.substring(0, index.value()), flags));
parent = TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, relative_parent, m_credentials, path_sv.substring(0, index.value()), flags));
file_name = path_sv.substring(index.value() + 1);
}
else
@ -510,7 +512,7 @@ namespace Kernel
ASSERT(m_process_lock.is_locked());
if (path && path[0] == '/')
return VirtualFileSystem::get().root_file();
return TRY(m_root_file.clone());
if (fd == AT_FDCWD)
return TRY(m_working_directory.clone());
@ -582,6 +584,7 @@ namespace Kernel
}
auto working_directory = TRY(m_working_directory.clone());
auto root_file = TRY(m_root_file.clone());
BAN::Vector<BAN::String> cmdline;
TRY(cmdline.resize(m_cmdline.size()));
@ -604,6 +607,7 @@ namespace Kernel
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
forked->m_controlling_terminal = m_controlling_terminal;
forked->m_working_directory = BAN::move(working_directory);
forked->m_root_file = BAN::move(root_file);
forked->m_cmdline = BAN::move(cmdline);
forked->m_environ = BAN::move(environ);
forked->m_page_table = BAN::move(page_table);
@ -656,7 +660,7 @@ namespace Kernel
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
auto executable_inode = executable_file.inode;
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
auto executable = TRY(ELF::load_from_inode(m_root_file.inode, executable_inode, m_credentials, *new_page_table));
auto new_mapped_regions = BAN::move(executable.regions);
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
@ -1044,7 +1048,7 @@ namespace Kernel
TRY(validate_string_access(path));
auto [parent, file_name] = TRY(find_parent_file(fd, path, O_RDONLY));
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, file_name, flags);
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent, m_credentials, file_name, flags);
VirtualFileSystem::File file;
if (file_or_error.is_error())
@ -1054,7 +1058,7 @@ namespace Kernel
// FIXME: There is a race condition between next two lines
TRY(parent.inode->create_file(file_name, (mode & 0777) | Inode::Mode::IFREG, m_credentials.euid(), m_credentials.egid()));
file = TRY(VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, file_name, flags & ~O_RDWR));
file = TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent, m_credentials, file_name, flags & ~O_RDWR));
}
else
{
@ -1135,7 +1139,7 @@ namespace Kernel
credentials.set_egid(credentials.rgid());
auto relative_parent = TRY(find_relative_parent(AT_FDCWD, path));
TRY(VirtualFileSystem::get().file_from_relative_path(relative_parent, credentials, path, flags));
TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, relative_parent, credentials, path, flags));
return 0;
}
@ -1258,6 +1262,7 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -1280,6 +1285,7 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -2095,22 +2101,25 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_chdir(const char* path)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto file = TRY(find_file(AT_FDCWD, path, O_SEARCH));
m_working_directory = BAN::move(file);
m_working_directory = TRY(find_file(AT_FDCWD, path, O_SEARCH));
return 0;
}
BAN::ErrorOr<long> Process::sys_fchdir(int fildes)
{
LockGuard _(m_process_lock);
m_working_directory = TRY(m_open_file_descriptors.file_of(fildes));
return 0;
}
auto file = TRY(m_open_file_descriptors.file_of(fildes));
m_working_directory = BAN::move(file);
BAN::ErrorOr<long> Process::sys_chroot(const char* path)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (!m_credentials.is_superuser())
return BAN::Error::from_errno(EACCES);
m_root_file = TRY(find_file(AT_FDCWD, path, O_SEARCH));
return 0;
}

View File

@ -121,8 +121,8 @@ namespace Kernel
void TTY::keyboard_task(void*)
{
BAN::RefPtr<Inode> keyboard_inode;
if (auto ret = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY); !ret.is_error())
keyboard_inode = ret.value().inode;
if (auto ret = DevFileSystem::get().root_inode()->find_inode("keyboard"_sv); !ret.is_error())
keyboard_inode = ret.release_value();
else
{
dprintln("could not open keyboard device: {}", ret.error());

26
ports/SDL2_mixer/build.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash ../install.sh
NAME='SDL2_mixer'
VERSION='2.8.1'
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_mixer/releases/download/release-$VERSION/SDL2_mixer-$VERSION.tar.gz#cb760211b056bfe44f4a1e180cc7cb201137e4d1572f2002cc1be728efd22660"
DEPENDENCIES=('SDL2')
configure() {
$BANAN_CMAKE --fresh -S . -B build -G Ninja \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-DCMAKE_INSTALL_PREFIX='/usr' \
-DCMAKE_BUILD_TYPE=Release \
-DSDL2MIXER_WAVPACK=OFF \
-DSDL2MIXER_MIDI=OFF \
-DSDL2MIXER_OPUS=OFF \
-DSDL2MIXER_MOD=OFF \
|| exit 1
}
build() {
$BANAN_CMAKE --build build || exit 1
}
install() {
$BANAN_CMAKE --install build || exit 1
}

View File

@ -3,7 +3,7 @@
NAME='binutils'
VERSION='2.44'
DOWNLOAD_URL="https://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.gz#0cdd76777a0dfd3dd3a63f215f030208ddb91c2361d2bcc02acec0f1c16b6a2e"
DEPENDENCIES=('zlib')
DEPENDENCIES=('zlib' 'zstd')
MAKE_INSTALL_TARGETS=('install-strip')
CONFIGURE_OPTIONS=(
"--target=$BANAN_TOOLCHAIN_TRIPLE"
@ -16,6 +16,13 @@ CONFIGURE_OPTIONS=(
'--disable-werror'
)
pre_configure() {
unset PKG_CONFIG_DIR
unset PKG_CONFIG_SYSROOT_DIR
unset PKG_CONFIG_LIBDIR
unset PKG_CONFIG_PATH
}
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libbfd.la

View File

@ -2,20 +2,22 @@
NAME='doom'
VERSION='git'
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#613f870b6fa83ede448a247de5a2571092fa729d"
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#5041246e859052e2e258ca6edb4e1e9bbd98fcf5"
DEPENDENCIES=('SDL2' 'SDL2_mixer' 'timidity')
configure() {
make --directory doomgeneric clean
rm -rf doomgeneric/build
}
build() {
if [ ! -f ../doom1.wad ]; then
wget https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad -O ../doom1.wad || exit 1
fi
make --directory doomgeneric --file Makefile.banan_os -j$(nproc) || exit 1
CFLAGS='-std=c11' make --directory doomgeneric --file Makefile.sdl CC="$CC" SDL_PATH="$BANAN_SYSROOT/usr/bin/" || exit 1
}
install() {
cp doomgeneric/build/doom "${BANAN_SYSROOT}/bin/" || exit 1
cp doomgeneric/doomgeneric "${BANAN_SYSROOT}/bin/doom" || exit 1
cp ../doom1.wad "$BANAN_SYSROOT/home/user/" || exit 1
}

View File

@ -1,224 +0,0 @@
From 0f37d9f2df042eb8ba021dd91b898c1f07d86b58 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Fri, 18 Oct 2024 03:44:10 +0300
Subject: [PATCH] Add support for banan-os
---
doomgeneric/Makefile.banan_os | 57 +++++++++++
doomgeneric/doomgeneric_banan_os.cpp | 138 +++++++++++++++++++++++++++
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..0878148
--- /dev/null
+++ b/doomgeneric/Makefile.banan_os
@@ -0,0 +1,57 @@
+################################################################
+#
+# $Id:$
+#
+# $Log:$
+#
+
+ifeq ($(V),1)
+ VB=''
+else
+ VB=@
+endif
+
+CC=$(BANAN_ARCH)-pc-banan_os-gcc
+CXX=$(BANAN_ARCH)-pc-banan_os-g++
+CFLAGS+=-O3 -std=c11 -Wall -DNORMALUNIX -DLINUX -DSNDSERV -D_DEFAULT_SOURCE
+CXXFLAGS+=$(CFLAGS) --std=c++20
+LDFLAGS+=
+LIBS+=-lgui -linput -lstdc++
+
+# subdirectory for objects
+OBJDIR=build
+OUTPUT=$(OBJDIR)/doom
+
+SRC_DOOM = dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o w_checksum.o w_file.o w_main.o w_wad.o z_zone.o w_file_stdc.o i_input.o i_video.o doomgeneric.o doomgeneric_banan_os.o
+OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM))
+
+all: $(OUTPUT)
+
+clean:
+ rm -rf $(OBJDIR)
+ rm -f $(OUTPUT)
+ rm -f $(OUTPUT).gdb
+ rm -f $(OUTPUT).map
+
+$(OUTPUT): $(OBJS)
+ @echo [Linking $@]
+ $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \
+ -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map
+ @echo [Size]
+ -$(CROSS_COMPILE)size $(OUTPUT)
+
+$(OBJS): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: %.c
+ @echo [Compiling $<]
+ $(VB)$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: %.cpp
+ @echo [Compiling $<]
+ $(VB)$(CXX) $(CXXFLAGS) -c $< -o $@
+
+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..9161771
--- /dev/null
+++ b/doomgeneric/doomgeneric_banan_os.cpp
@@ -0,0 +1,139 @@
+extern "C"
+{
+#include "doomgeneric.h"
+#include "doomkeys.h"
+}
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/banan-os.h>
+#include <sys/framebuffer.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include <LibGUI/Window.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+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;
+
+extern "C"
+{
+
+void DG_Init()
+{
+ s_window = MUST(LibGUI::Window::create(DOOMGENERIC_RESX, DOOMGENERIC_RESY, "DOOM"_sv));
+ s_window->set_key_event_callback(
+ [](LibGUI::EventPacket::KeyEvent::event_t 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);
+ }
+ }
+
+ if (doom_key == 0)
+ return;
+
+ 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()
+{
+ auto& texture = s_window->texture();
+ for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
+ for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
+ texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
+ s_window->invalidate();
+ s_window->poll_events();
+}
+
+void DG_SleepMs(uint32_t ms)
+{
+ struct timespec ts;
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+ nanosleep(&ts, NULL);
+}
+
+uint32_t DG_GetTicksMs()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+}
+
+int DG_GetKey(int* pressed, unsigned char* doomKey)
+{
+ if (s_key_read_index == s_key_write_index)
+ return 0;
+
+ unsigned short key_data = s_key_queue[s_key_read_index];
+ s_key_read_index = (s_key_read_index + 1) % s_key_queue_size;
+
+ *pressed = key_data >> 8;
+ *doomKey = key_data & 0xFF;
+
+ return 1;
+}
+
+void DG_SetWindowTitle(const char* title)
+{
+ (void)title;
+}
+
+int main(int argc, char** argv)
+{
+ doomgeneric_Create(argc, argv);
+
+ for (;;)
+ doomgeneric_Tick();
+
+ return 0;
+}
+
+}
--
2.45.2

View File

@ -0,0 +1,27 @@
From a4e6b807885a7cb4a507b4e114743aa0004376ad Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 01:57:38 +0300
Subject: [PATCH] add support for custom SDL path
---
doomgeneric/Makefile.sdl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doomgeneric/Makefile.sdl b/doomgeneric/Makefile.sdl
index 38402da..8c2f84e 100644
--- a/doomgeneric/Makefile.sdl
+++ b/doomgeneric/Makefile.sdl
@@ -12,8 +12,8 @@ else
endif
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PATH)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PATH)sdl2-config --cflags --libs` -lSDL2_mixer
CC=clang # gcc or g++
--
2.50.1

View File

@ -1,34 +0,0 @@
From c28fd460c15a3d4cc5aac35d1ea5744f1722cab4 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Wed, 3 Apr 2024 21:39:22 +0300
Subject: [PATCH] Call exit() on I_Quit() and I_Error()
---
doomgeneric/i_system.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doomgeneric/i_system.c b/doomgeneric/i_system.c
index 5d00091..bfb204f 100644
--- a/doomgeneric/i_system.c
+++ b/doomgeneric/i_system.c
@@ -257,6 +257,8 @@ void I_Quit (void)
entry = entry->next;
}
+ exit(0);
+
#if ORIGCODE
SDL_Quit();
@@ -403,6 +405,8 @@ void I_Error (char *error, ...)
entry = entry->next;
}
+ exit(1);
+
exit_gui_popup = !M_ParmExists("-nogui");
// Pop up a GUI dialog box to show the error message, if the
--
2.47.1

View File

@ -0,0 +1,25 @@
From fd5308b45021ca18e7703d810e2e2ba86c174669 Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 01:56:26 +0300
Subject: [PATCH] set timidity config path
---
doomgeneric/i_sdlmusic.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doomgeneric/i_sdlmusic.c b/doomgeneric/i_sdlmusic.c
index f56392f..80b9021 100644
--- a/doomgeneric/i_sdlmusic.c
+++ b/doomgeneric/i_sdlmusic.c
@@ -110,7 +110,7 @@ static boolean sdl_was_initialized = false;
static boolean musicpaused = false;
static int current_music_volume;
-char *timidity_cfg_path = "";
+char *timidity_cfg_path = "/etc/timidity.cfg";
static char *temp_timidity_cfg = NULL;
--
2.50.1

View File

@ -1,48 +0,0 @@
From 70c235938f0b64c4f08a478d3107e5254ad904c6 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Wed, 27 Nov 2024 13:28:42 +0200
Subject: [PATCH] Remove unnecessary copy from framebuffer
---
doomgeneric/doomgeneric.c | 2 --
doomgeneric/doomgeneric_banan_os.cpp | 6 +++---
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/doomgeneric/doomgeneric.c b/doomgeneric/doomgeneric.c
index 782a7e7..f4eb63e 100644
--- a/doomgeneric/doomgeneric.c
+++ b/doomgeneric/doomgeneric.c
@@ -18,8 +18,6 @@ void doomgeneric_Create(int argc, char **argv)
M_FindResponseFile();
- DG_ScreenBuffer = malloc(DOOMGENERIC_RESX * DOOMGENERIC_RESY * 4);
-
DG_Init();
D_DoomMain ();
diff --git a/doomgeneric/doomgeneric_banan_os.cpp b/doomgeneric/doomgeneric_banan_os.cpp
index d00c30d..9d13b43 100644
--- a/doomgeneric/doomgeneric_banan_os.cpp
+++ b/doomgeneric/doomgeneric_banan_os.cpp
@@ -80,14 +80,13 @@ void DG_Init()
s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
}
);
+
+ ASSERT(DG_ScreenBuffer == nullptr);
+ DG_ScreenBuffer = s_window->texture().pixels().data();
}
void DG_DrawFrame()
{
- auto& texture = s_window->texture();
- for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
- for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
- texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
s_window->invalidate();
s_window->poll_events();
}
--
2.47.1

View File

@ -2,10 +2,11 @@
NAME='quake2'
VERSION='git'
DOWNLOAD_URL="https://github.com/ozkl/quake2generic.git#a967e4f567a98941326fc7fe76eee5e52a04a633"
DOWNLOAD_URL="https://github.com/ozkl/quake2generic.git#50190797664fd42fc1b0266150c54f76f92bfa15"
DEPENDENCIES=('SDL2' 'SDL2_mixer')
configure() {
:
make clean
}
build() {
@ -24,11 +25,13 @@ build() {
echo "File hash does not match" >&2
exit 1
fi
make -j$(nproc) || exit 1
cflags='-Dstricmp=strcasecmp -Wno-incompatible-pointer-types'
make CC="$CC" BASE_CFLAGS="$cflags" SDL_PATH="$BANAN_SYSROOT/usr/bin/" -j$(nproc) || exit 1
}
install() {
cp build/quake2 "${BANAN_SYSROOT}/bin/" || exit 1
cp -v build/quake2-soft "${BANAN_SYSROOT}/bin/quake2" || exit 1
baseq2_tar=$(realpath ../baseq2.tar.gz || exit 1)
cd "$BANAN_SYSROOT/home/user/"

View File

@ -1,482 +0,0 @@
From f900c2967edc684334b663e522aeec79e8fee10d Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Thu, 14 Nov 2024 12:33:39 +0200
Subject: [PATCH] Add support for banan-os
---
Makefile | 106 +++-------------
port_soft_banan_os.cpp | 277 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 295 insertions(+), 88 deletions(-)
create mode 100644 port_soft_banan_os.cpp
diff --git a/Makefile b/Makefile
index 46142df..4437418 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,3 @@
-
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
-
MOUNT_DIR=.
BUILDDIR=build
@@ -18,21 +14,19 @@ GAME_DIR=$(MOUNT_DIR)/game
CTF_DIR=$(MOUNT_DIR)/ctf
XATRIX_DIR=$(MOUNT_DIR)/xatrix
-CC=clang #emcc
+CC=$(BANAN_ARCH)-banan_os-gcc
BASE_CFLAGS=-Dstricmp=strcasecmp
+CXX=$(BANAN_ARCH)-banan_os-g++
+CXXFLAGS=--std=c++20
RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -ffast-math -funroll-loops \
-fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
-malign-jumps=2 -malign-functions=2
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-LDFLAGS=-ldl -lm
-XCFLAGS=-I/opt/X11/include
-
-GLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib \
- $(SDL_LIBS) -lGL
-GLCFLAGS=$(SDL_CFLAGS)
+LDFLAGS=-lgui -linput
+XCFLAGS=
SHLIBEXT=so
@@ -43,6 +37,10 @@ DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
DO_GL_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $<
+DO_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
+DO_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+DO_GL_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $<
+
#############################################################################
# SETUP AND BUILD
#############################################################################
@@ -61,14 +59,12 @@ createdirs:
@-mkdir -p $(BUILDDIR) \
$(BUILDDIR)/client \
$(BUILDDIR)/ref_soft \
- $(BUILDDIR)/ref_softsdl \
- $(BUILDDIR)/ref_gl \
$(BUILDDIR)/net \
$(BUILDDIR)/sound \
$(BUILDDIR)/game
-TARGETS: $(BUILDDIR)/quake2-soft $(BUILDDIR)/quake2-gl
+TARGETS: $(BUILDDIR)/quake2
#############################################################################
# CLIENT/SERVER
@@ -122,7 +118,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/client/pmove.o \
\
- $(BUILDDIR)/net/net_unix.o \
+ $(BUILDDIR)/net/net_loopback.o \
\
$(BUILDDIR)/sound/snddma_null.o \
\
@@ -200,38 +196,11 @@ REF_SOFT_OBJS = \
$(BUILDDIR)/ref_soft/r_rast.o \
$(BUILDDIR)/ref_soft/r_scan.o \
$(BUILDDIR)/ref_soft/r_sprite.o \
- $(BUILDDIR)/ref_soft/r_surf.o
-
-
-REF_SOFT_SDL_OBJS = \
- $(BUILDDIR)/ref_soft/port_soft_sdl.o
-
-
-#############################################################################
-# REF_GL
-#############################################################################
-
-REF_GL_OBJS = \
- $(BUILDDIR)/ref_gl/gl_draw.o \
- $(BUILDDIR)/ref_gl/gl_image.o \
- $(BUILDDIR)/ref_gl/gl_light.o \
- $(BUILDDIR)/ref_gl/gl_mesh.o \
- $(BUILDDIR)/ref_gl/gl_model.o \
- $(BUILDDIR)/ref_gl/gl_rmain.o \
- $(BUILDDIR)/ref_gl/gl_rmisc.o \
- $(BUILDDIR)/ref_gl/gl_rsurf.o \
- $(BUILDDIR)/ref_gl/gl_warp.o \
- \
- $(BUILDDIR)/ref_gl/qgl_system.o \
- $(BUILDDIR)/ref_gl/port_gl_sdl.o
-
-
-$(BUILDDIR)/quake2-soft : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS)
- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
-
-$(BUILDDIR)/quake2-gl : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS)
- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
+ $(BUILDDIR)/ref_soft/r_surf.o \
+ $(BUILDDIR)/ref_soft/port_soft_banan_os.o
+$(BUILDDIR)/quake2 : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(LDFLAGS)
$(BUILDDIR)/client/cl_cin.o : $(CLIENT_DIR)/cl_cin.c
$(DO_CC)
@@ -362,7 +331,7 @@ $(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c
$(BUILDDIR)/client/glob.o : $(OTHER_DIR)/glob.c
$(DO_CC)
-$(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
+$(BUILDDIR)/net/net_loopback.o : $(NET_DIR)/net_loopback.c
$(DO_CC)
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
@@ -689,45 +658,8 @@ $(BUILDDIR)/ref_soft/r_sprite.o : $(REF_SOFT_DIR)/r_sprite.c
$(BUILDDIR)/ref_soft/r_surf.o : $(REF_SOFT_DIR)/r_surf.c
$(DO_GL_SHLIB_CC)
-$(BUILDDIR)/ref_soft/port_soft_sdl.o : $(MOUNT_DIR)/port_soft_sdl.c
- $(DO_GL_SHLIB_CC)
-
-#############################################################################
-# REF_GL
-#############################################################################
-
-$(BUILDDIR)/ref_gl/gl_draw.o : $(REF_GL_DIR)/gl_draw.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_image.o : $(REF_GL_DIR)/gl_image.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_light.o : $(REF_GL_DIR)/gl_light.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_mesh.o : $(REF_GL_DIR)/gl_mesh.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_model.o : $(REF_GL_DIR)/gl_model.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rmain.o : $(REF_GL_DIR)/gl_rmain.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rmisc.o : $(REF_GL_DIR)/gl_rmisc.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rsurf.o : $(REF_GL_DIR)/gl_rsurf.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_warp.o : $(REF_GL_DIR)/gl_warp.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/qgl_system.o : $(REF_GL_DIR)/qgl_system.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/port_gl_sdl.o : $(MOUNT_DIR)/port_gl_sdl.c
- $(DO_GL_SHLIB_CC)
+$(BUILDDIR)/ref_soft/port_soft_banan_os.o : $(MOUNT_DIR)/port_soft_banan_os.cpp
+ $(DO_GL_SHLIB_CXX)
#############################################################################
@@ -738,8 +670,6 @@ clean:
-rm -rf \
$(BUILDDIR)/client \
$(BUILDDIR)/ref_soft \
- $(BUILDDIR)/ref_softsdl \
- $(BUILDDIR)/ref_gl \
$(BUILDDIR)/game \
$(BUILDDIR)/net \
$(BUILDDIR)/sound \
diff --git a/port_soft_banan_os.cpp b/port_soft_banan_os.cpp
new file mode 100644
index 0000000..c7d7e16
--- /dev/null
+++ b/port_soft_banan_os.cpp
@@ -0,0 +1,278 @@
+#include <LibGUI/Window.h>
+#include <LibInput/KeyEvent.h>
+#include <LibInput/MouseEvent.h>
+#include <LibImage/Image.h>
+
+#include <BAN/Debug.h>
+
+extern "C" {
+
+#include "ref_soft/r_local.h"
+#include "client/keys.h"
+
+#include "quake2.h"
+
+static LibImage::Image::Color s_palette[256];
+
+static int s_mouse_dx { 0 };
+static int s_mouse_dy { 0 };
+static bool s_relative_mouse { false };
+
+static BAN::Vector<uint8_t> s_buffer;
+static BAN::UniqPtr<LibGUI::Window> s_window;
+static bool s_is_fullscreen { false };
+
+static int key_to_quake_key(LibInput::Key key)
+{
+ using namespace LibInput;
+
+ switch (key)
+ {
+ case Key::PageUp: return K_PGUP;
+ case Key::PageDown: return K_PGDN;
+ case Key::Home: return K_HOME;
+ case Key::End: return K_END;
+ case Key::ArrowLeft: return K_LEFTARROW;
+ case Key::ArrowRight: return K_RIGHTARROW;
+ case Key::ArrowDown: return K_DOWNARROW;
+ case Key::ArrowUp: return K_UPARROW;
+ case Key::Escape: return K_ESCAPE;
+ case Key::Enter: return K_ENTER;
+ case Key::Tab: return K_TAB;
+ case Key::F1: return K_F1;
+ case Key::F2: return K_F2;
+ case Key::F3: return K_F3;
+ case Key::F4: return K_F4;
+ case Key::F5: return K_F5;
+ case Key::F6: return K_F6;
+ case Key::F7: return K_F7;
+ case Key::F8: return K_F8;
+ case Key::F9: return K_F9;
+ case Key::F10: return K_F10;
+ case Key::F11: return K_F11;
+ case Key::F12: return K_F12;
+ case Key::Backspace: return K_BACKSPACE;
+ case Key::Delete: return K_DEL;
+ case Key::LeftShift:
+ case Key::RightShift: return K_SHIFT;
+ case Key::LeftCtrl:
+ case Key::RightCtrl: return K_CTRL;
+ case Key::LeftAlt:
+ case Key::RightAlt: return K_ALT;
+ case Key::Insert: return K_INS;
+ default:
+ if (const char* ascii = key_to_utf8(key, 0); ascii && strlen(ascii) == 1)
+ return *ascii;
+ break;
+ }
+
+ return 0;
+}
+
+static int button_to_quake_button(LibInput::MouseButton button)
+{
+ using namespace LibInput;
+
+ switch (button)
+ {
+ case LibInput::MouseButton::Left: return K_MOUSE1;
+ case LibInput::MouseButton::Right: return K_MOUSE2;
+ case LibInput::MouseButton::Middle: return K_MOUSE3;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void create_window(uint32_t width, uint32_t height)
+{
+ ASSERT(!s_window);
+ s_window = MUST(LibGUI::Window::create(width, height, "Quake2"_sv));
+
+ s_window->set_mouse_move_event_callback(
+ [](auto event)
+ {
+ if (!s_relative_mouse)
+ return;
+ s_mouse_dx += event.x;
+ s_mouse_dy += event.y;
+ }
+ );
+
+ s_window->set_mouse_button_event_callback(
+ [](auto event)
+ {
+ if (int button = button_to_quake_button(event.button))
+ Quake2_SendKey(button, event.pressed);
+ }
+ );
+
+ s_window->set_key_event_callback(
+ [](auto event)
+ {
+ if (int key = key_to_quake_key(event.key))
+ Quake2_SendKey(key, event.pressed());
+ }
+ );
+
+ s_window->set_close_window_event_callback(
+ []()
+ {
+ char command[] = "quit";
+ ri.Cmd_ExecuteText(EXEC_NOW, command);
+ }
+ );
+}
+
+rserr_t SWimp_SetMode(int* pwidth, int* pheight, int mode, qboolean fullscreen)
+{
+ int width, height;
+
+ if (!ri.Vid_GetModeInfo(&width, &height, mode))
+ return rserr_invalid_mode;
+
+ if (!s_window)
+ create_window(width, height);
+ else if (s_window->width() != width || s_window->height() != height)
+ {
+ s_window->request_resize(width, height);
+
+ bool resized { false };
+ s_window->set_resize_window_event_callback([&]() { resized = true; });
+ while (!resized)
+ s_window->poll_events();
+ s_window->set_resize_window_event_callback({});
+
+ ASSERT(s_window->width() == width && s_window->height() == height);
+ }
+
+ if (s_is_fullscreen != fullscreen)
+ {
+ s_is_fullscreen = fullscreen;
+ s_window->set_fullscreen(fullscreen);
+ }
+
+ MUST(s_buffer.resize(s_window->width() * s_window->height()));
+ vid.rowbytes = s_window->width();
+ vid.buffer = s_buffer.data();
+
+ *pwidth = s_window->width();
+ *pheight = s_window->height();
+
+ ri.Vid_NewWindow(s_window->width(), s_window->height());
+
+ return rserr_ok;
+}
+
+void SWimp_Shutdown(void)
+{
+}
+
+int SWimp_Init(void* hInstance, void* wndProc)
+{
+ return true;
+}
+
+static qboolean SWimp_InitGraphics(qboolean fullscreen)
+{
+ return rserr_ok;
+}
+
+void SWimp_SetPalette(const unsigned char* palette)
+{
+ for (int i = 0; i < 256; i++)
+ {
+ s_palette[i].r = *palette++;
+ s_palette[i].g = *palette++;
+ s_palette[i].b = *palette++;
+ s_palette[i].a = *palette++;
+ }
+}
+
+void SWimp_BeginFrame(float camera_seperation)
+{
+}
+
+void SWimp_EndFrame(void)
+{
+ auto& texture = s_window->texture();
+ const uint32_t width = s_window->width();
+ const uint32_t height = s_window->height();
+ for (int y = 0; y < height; y++)
+ for (int x = 0; x < width; x++)
+ texture.set_pixel(x, y, s_palette[s_buffer[y * width + x]].as_argb());
+ s_window->invalidate();
+}
+
+void SWimp_AppActivate(qboolean active)
+{
+}
+
+int QG_Milliseconds(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (ts.tv_sec * 1'000) + (ts.tv_nsec / 1'000'000);
+}
+
+void QG_GetMouseDiff(int* dx, int* dy)
+{
+ *dx = s_mouse_dx;
+ s_mouse_dx = 0;
+
+ *dy = s_mouse_dy;
+ s_mouse_dy = 0;
+}
+
+void QG_CaptureMouse(void)
+{
+ s_relative_mouse = true;
+ s_window->set_mouse_capture(true);
+}
+
+void QG_ReleaseMouse(void)
+{
+ s_relative_mouse = false;
+ s_window->set_mouse_capture(false);
+}
+
+static uint64_t get_current_ns()
+{
+ timespec last_ts;
+ clock_gettime(CLOCK_MONOTONIC, &last_ts);
+ return (uint64_t)last_ts.tv_sec * 1'000'000'000 + last_ts.tv_nsec;
+}
+
+int main(int argc, char** argv)
+{
+ Quake2_Init(argc, argv);
+
+ uint64_t last_ns = get_current_ns();
+ for (;;)
+ {
+ s_window->poll_events();
+
+ const uint64_t current_ns = get_current_ns();
+ uint64_t duration_ns = current_ns - last_ns;
+
+ if (duration_ns < 1'000'000)
+ {
+ timespec sleep_ts {
+ .tv_sec = 0,
+ .tv_nsec = (long)(1'000'000 - duration_ns)
+ };
+ while (nanosleep(&sleep_ts, &sleep_ts))
+ continue;
+ duration_ns = get_current_ns() - last_ns;
+ }
+
+ Quake2_Frame(duration_ns / 1'000'000);
+
+ last_ns = current_ns;
+ }
+
+ return 0;
+}
+
+}
--
2.47.0

View File

@ -0,0 +1,52 @@
From fd08d90bb7ee8388a9e005bae23edcccbfc73dbb Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 19:52:20 +0300
Subject: [PATCH] add support for custom SDL path and add sound support
---
Makefile | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 8edbffa..de2f605 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PATH)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PATH)sdl2-config --cflags --libs` -lSDL2_mixer
MOUNT_DIR=.
@@ -124,7 +124,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/net/net_unix.o \
\
- $(BUILDDIR)/sound/snddma_null.o \
+ $(BUILDDIR)/sound/snd_sdl.o \
\
$(BUILDDIR)/port_platform_unix.o
@@ -353,7 +353,7 @@ $(BUILDDIR)/client/vid_menu.o : $(OTHER_DIR)/vid_menu.c
$(BUILDDIR)/client/vid_lib.o : $(OTHER_DIR)/vid_lib.c
$(DO_CC)
-$(BUILDDIR)/client/snddma_null.o : $(NULL_DIR)/snddma_null.c
+$(BUILDDIR)/client/snd_sdl.o : $(NULL_DIR)/snd_sdl.c
$(DO_CC)
$(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c
@@ -368,7 +368,7 @@ $(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
$(DO_CC)
-$(BUILDDIR)/sound/snddma_null.o : $(SOUND_DIR)/snddma_null.c
+$(BUILDDIR)/sound/snd_sdl.o : $(SOUND_DIR)/snd_sdl.c
$(DO_GL_SHLIB_CC)
--
2.50.1

View File

@ -0,0 +1,42 @@
From fbdf3e7c40c1de83a2361bb904d8dbd3464ccebd Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 19:54:38 +0300
Subject: [PATCH 2/2] fix socket creation
---
net/net_unix.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/net/net_unix.c b/net/net_unix.c
index a92e57c..f297dff 100644
--- a/net/net_unix.c
+++ b/net/net_unix.c
@@ -451,24 +451,16 @@ int NET_Socket (char *net_interface, int port)
qboolean _true = true;
int i = 1;
- if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ if ((newsocket = socket (PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
return 0;
}
- // make it non-blocking
- if (ioctl (newsocket, FIONBIO, &_true) == -1)
- {
- Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
- return 0;
- }
-
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
- return 0;
}
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
--
2.50.1

31
ports/timidity/build.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash ../install.sh
NAME='timidity'
VERSION='2.15.0'
DOWNLOAD_URL="https://sourceforge.net/projects/timidity/files/TiMidity++/TiMidity++-$VERSION/TiMidity++-$VERSION.tar.gz#0b6109a3c64604c8851cd9bb4cbafc014a4e13b0025f597e586d9742388f6fb7"
TAR_CONTENT="TiMidity++-$VERSION"
CONFIG_SUB=('autoconf/config.sub')
CONFIGURE_OPTIONS=(
'--without-x'
'lib_cv_va_copy=y'
'lib_cv___va_copy=n'
'lib_cv_va_val_copy=n'
'CFLAGS=-std=c11'
)
pre_configure() {
unset CC CXX LD
}
post_install() {
if [ ! -f ../eawpats.zip ]; then
wget https://www.quaddicted.com/files/idgames/sounds/eawpats.zip -O ../eawpats.zip || exit 1
fi
eawpats_dir="/usr/share/eawpats"
mkdir -p "$BANAN_SYSROOT/$eawpats_dir"
unzip -qod "$BANAN_SYSROOT/$eawpats_dir" ../eawpats.zip
cp "$BANAN_SYSROOT/$eawpats_dir/timidity.cfg" "$BANAN_SYSROOT/etc/"
sed -i "s|^dir .*$|dir $eawpats_dir|g" "$BANAN_SYSROOT/etc/timidity.cfg"
}

View File

@ -3,13 +3,15 @@
NAME='tinygb'
VERSION='git'
DOWNLOAD_URL="https://github.com/jewelcodes/tinygb.git#57fdaff675a6b5b963b2b6624868d9698eabe375"
DEPENDENCIES=('SDL2')
configure() {
make -f Makefile.banan_os clean
sed -i "s|shell sdl2-config|shell $BANAN_SYSROOT/usr/bin/sdl2-config|g" Makefile
make clean
}
build() {
make -f Makefile.banan_os -j$(nproc) || exit 1
make CC="$CC" LD="$CC" || exit 1
}
install() {

View File

@ -1,420 +0,0 @@
From 7f7c6402e384591bca63021aa97d60a8107de88d Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Mon, 5 May 2025 00:59:03 +0300
Subject: [PATCH] Add support for banan-os
---
Makefile.banan_os | 28 +++
src/platform/banan-os/main.cpp | 362 +++++++++++++++++++++++++++++++++
2 files changed, 390 insertions(+)
create mode 100644 Makefile.banan_os
create mode 100644 src/platform/banan-os/main.cpp
diff --git a/Makefile.banan_os b/Makefile.banan_os
new file mode 100644
index 0000000..22e191e
--- /dev/null
+++ b/Makefile.banan_os
@@ -0,0 +1,28 @@
+CC = $(BANAN_ARCH)-banan_os-gcc
+CXX = $(BANAN_ARCH)-banan_os-g++
+LD = $(BANAN_ARCH)-banan_os-gcc
+
+CFLAGS = -c -O2 -Isrc/include -Wall
+CXXFLAGS = --std=c++20
+LDFLAGS = -O2 -lgui -linput
+
+SRC := $(shell find src -name "*.c" -not -path 'src/platform/*') $(shell find src/platform/banan-os -name "*.c" -or -name "*.cpp")
+OBJ := $(addsuffix .o,$(SRC))
+
+all: tinygb
+
+clean:
+ @rm -f $(OBJ)
+ @rm -f tinygb
+
+%.c.o: %.c
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
+ $(CC) -o $@ $(CFLAGS) $<
+
+%.cpp.o: %.cpp
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
+ $(CXX) -o $@ $(CFLAGS) $(CXXFLAGS) $<
+
+tinygb: $(OBJ)
+ @echo -e "\x1B[0;1;36m [ LD ]\x1B[0m tinygb"
+ $(LD) $(OBJ) -o tinygb $(LDFLAGS)
diff --git a/src/platform/banan-os/main.cpp b/src/platform/banan-os/main.cpp
new file mode 100644
index 0000000..94f249e
--- /dev/null
+++ b/src/platform/banan-os/main.cpp
@@ -0,0 +1,364 @@
+
+/* tinygb - a tiny gameboy emulator
+ (c) 2022 by jewel */
+
+extern "C" {
+#include <tinygb.h>
+}
+
+#include <LibGUI/Window.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+long rom_size;
+int scaling = 4;
+int frameskip = 0; // no skip
+
+timing_t timing;
+char *rom_filename;
+
+BAN::UniqPtr<LibGUI::Window> s_window;
+
+// Key Config
+LibInput::Key key_a;
+LibInput::Key key_b;
+LibInput::Key key_start;
+LibInput::Key key_select;
+LibInput::Key key_up;
+LibInput::Key key_down;
+LibInput::Key key_left;
+LibInput::Key key_right;
+LibInput::Key key_throttle;
+
+LibInput::Key get_key(const char* keyname)
+{
+ if (keyname == nullptr);
+ else if (!strcmp("a", keyname)) return LibInput::Key::A;
+ else if (!strcmp("b", keyname)) return LibInput::Key::B;
+ else if (!strcmp("c", keyname)) return LibInput::Key::C;
+ else if (!strcmp("d", keyname)) return LibInput::Key::D;
+ else if (!strcmp("e", keyname)) return LibInput::Key::E;
+ else if (!strcmp("f", keyname)) return LibInput::Key::F;
+ else if (!strcmp("g", keyname)) return LibInput::Key::G;
+ else if (!strcmp("h", keyname)) return LibInput::Key::H;
+ else if (!strcmp("i", keyname)) return LibInput::Key::I;
+ else if (!strcmp("j", keyname)) return LibInput::Key::J;
+ else if (!strcmp("k", keyname)) return LibInput::Key::K;
+ else if (!strcmp("l", keyname)) return LibInput::Key::L;
+ else if (!strcmp("m", keyname)) return LibInput::Key::M;
+ else if (!strcmp("n", keyname)) return LibInput::Key::N;
+ else if (!strcmp("o", keyname)) return LibInput::Key::O;
+ else if (!strcmp("p", keyname)) return LibInput::Key::P;
+ else if (!strcmp("q", keyname)) return LibInput::Key::Q;
+ else if (!strcmp("r", keyname)) return LibInput::Key::R;
+ else if (!strcmp("s", keyname)) return LibInput::Key::S;
+ else if (!strcmp("t", keyname)) return LibInput::Key::T;
+ else if (!strcmp("u", keyname)) return LibInput::Key::U;
+ else if (!strcmp("v", keyname)) return LibInput::Key::V;
+ else if (!strcmp("w", keyname)) return LibInput::Key::W;
+ else if (!strcmp("x", keyname)) return LibInput::Key::X;
+ else if (!strcmp("y", keyname)) return LibInput::Key::Y;
+ else if (!strcmp("z", keyname)) return LibInput::Key::Z;
+ else if (!strcmp("0", keyname)) return LibInput::Key::_0;
+ else if (!strcmp("1", keyname)) return LibInput::Key::_1;
+ else if (!strcmp("2", keyname)) return LibInput::Key::_2;
+ else if (!strcmp("3", keyname)) return LibInput::Key::_3;
+ else if (!strcmp("4", keyname)) return LibInput::Key::_4;
+ else if (!strcmp("5", keyname)) return LibInput::Key::_5;
+ else if (!strcmp("6", keyname)) return LibInput::Key::_6;
+ else if (!strcmp("7", keyname)) return LibInput::Key::_7;
+ else if (!strcmp("8", keyname)) return LibInput::Key::_8;
+ else if (!strcmp("9", keyname)) return LibInput::Key::_9;
+ else if (!strcmp("up", keyname)) return LibInput::Key::ArrowUp;
+ else if (!strcmp("down", keyname)) return LibInput::Key::ArrowDown;
+ else if (!strcmp("left", keyname)) return LibInput::Key::ArrowLeft;
+ else if (!strcmp("right", keyname)) return LibInput::Key::ArrowRight;
+ else if (!strcmp("space", keyname)) return LibInput::Key::Space;
+ else if (!strcmp("rshift", keyname)) return LibInput::Key::RightShift;
+ else if (!strcmp("lshift", keyname)) return LibInput::Key::LeftShift;
+ else if (!strcmp("backspace", keyname)) return LibInput::Key::Backspace;
+ else if (!strcmp("delete", keyname)) return LibInput::Key::Delete;
+ else if (!strcmp("tab", keyname)) return LibInput::Key::Tab;
+ else if (!strcmp("escape", keyname)) return LibInput::Key::Escape;
+ else if (!strcmp("exclamation", keyname)) return LibInput::Key::ExclamationMark;
+ else if (!strcmp("at", keyname)) return LibInput::Key::AtSign;
+ else if (!strcmp("hash", keyname)) return LibInput::Key::Hashtag;
+ else if (!strcmp("dollar", keyname)) return LibInput::Key::Dollar;
+ else if (!strcmp("percent", keyname)) return LibInput::Key::Percent;
+ else if (!strcmp("caret", keyname)) return LibInput::Key::Caret;
+ else if (!strcmp("ampersand", keyname)) return LibInput::Key::Ampersand;
+ else if (!strcmp("asterisk", keyname)) return LibInput::Key::Asterix;
+ else if (!strcmp("leftparenthesis", keyname)) return LibInput::Key::OpenParenthesis;
+ else if (!strcmp("rightparenthesis", keyname)) return LibInput::Key::CloseParenthesis;
+
+ return LibInput::Key::None;
+}
+
+static void load_keys()
+{
+ key_a = get_key(config_file.a);
+ if (key_a == LibInput::Key::None)
+ key_a = LibInput::Key::Z;
+
+ key_b = get_key(config_file.b);
+ if (key_b == LibInput::Key::None)
+ key_b = LibInput::Key::X;
+
+ key_start = get_key(config_file.start);
+ if (key_start == LibInput::Key::None)
+ key_start = LibInput::Key::Enter;
+
+ key_select = get_key(config_file.select);
+ if (key_select == LibInput::Key::None)
+ key_select = LibInput::Key::RightShift;
+
+ key_up = get_key(config_file.up);
+ if (key_up == LibInput::Key::None)
+ key_up = LibInput::Key::ArrowUp;
+
+ key_down = get_key(config_file.down);
+ if (key_down == LibInput::Key::None)
+ key_down = LibInput::Key::ArrowDown;
+
+ key_left = get_key(config_file.left);
+ if (key_left == LibInput::Key::None)
+ key_left = LibInput::Key::ArrowLeft;
+
+ key_right = get_key(config_file.right);
+ if (key_right == LibInput::Key::None)
+ key_right = LibInput::Key::ArrowRight;
+
+ key_throttle = get_key(config_file.throttle);
+ if (key_throttle == LibInput::Key::None)
+ key_throttle = LibInput::Key::Space;
+}
+
+void delay(int ms)
+{
+ const timespec ts {
+ .tv_sec = static_cast<time_t>(ms / 1000),
+ .tv_nsec = (ms % 1000) * 1000000
+ };
+ nanosleep(&ts, nullptr);
+}
+
+void destroy_window()
+{
+ s_window.clear();
+}
+
+void update_window(uint32_t *framebuffer)
+{
+ auto pixels = s_window->texture().pixels();
+ for (int i = 0; i < scaled_h; i++)
+ {
+ uint32_t* src = &framebuffer[i * scaled_w];
+ uint32_t* dst = using_sgb_border
+ ? &pixels[(i + gb_y) * s_window->width() + gb_x]
+ : &pixels[i * s_window->width()];
+ memcpy(dst, src, scaled_w * 4);
+ }
+
+ if (framecount > frameskip)
+ {
+ s_window->invalidate();
+ framecount = 0;
+ drawn_frames++;
+ }
+}
+
+void update_border(uint32_t *framebuffer)
+{
+ auto pixels = s_window->texture().pixels();
+ for (int i = 0; i < sgb_scaled_h; i++)
+ {
+ uint32_t* src = &framebuffer[i * sgb_scaled_w];
+ uint32_t* dst = &pixels[i * s_window->width()];
+ memcpy(dst, src, sgb_scaled_w*4);
+ }
+}
+
+void resize_sgb_window()
+{
+ s_window->request_resize(SGB_WIDTH * scaling, SGB_HEIGHT * scaling);
+
+ bool resized { false };
+ s_window->set_resize_window_event_callback([&]() { resized = true; });
+ while (!resized)
+ s_window->poll_events();
+ s_window->set_resize_window_event_callback({});
+
+ ASSERT(s_window->width() == static_cast<uint32_t>(SGB_WIDTH * scaling));
+ ASSERT(s_window->height() == static_cast<uint32_t>(SGB_HEIGHT * scaling));
+}
+
+int main(int argc, char **argv) {
+ if(argc != 2) {
+ fprintf(stdout, "usage: %s rom_name\n", argv[0]);
+ return 1;
+ }
+
+ rom_filename = argv[1];
+
+ open_log();
+ open_config();
+ load_keys();
+
+ // open the rom
+ FILE *rom_file = fopen(rom_filename, "r");
+ if(!rom_file) {
+ write_log("unable to open %s for reading: %s\n", rom_filename, strerror(errno));
+ return 1;
+ }
+
+ fseek(rom_file, 0L, SEEK_END);
+ rom_size = ftell(rom_file);
+ fseek(rom_file, 0L, SEEK_SET);
+
+ write_log("loading rom from file %s, %d KiB\n", rom_filename, rom_size / 1024);
+
+ rom = malloc(rom_size);
+ if(!rom) {
+ write_log("unable to allocate memory\n");
+ fclose(rom_file);
+ return 1;
+ }
+
+ if (fread(rom, 1, rom_size, rom_file) <= 0)
+ {
+ write_log("an error occured while reading from rom file: %s\n", strerror(errno));
+ fclose(rom_file);
+ free(rom);
+ return 1;
+ }
+
+ fclose(rom_file);
+
+ if (auto ret = LibGUI::Window::create(GB_WIDTH * scaling, GB_HEIGHT * scaling, "tinygb"_sv); !ret.is_error())
+ s_window = ret.release_value();
+ else
+ {
+ write_log("couldn't create SDL window: %s\n", ret.error().get_message());
+ free(rom);
+ return 1;
+ }
+
+ s_window->set_key_event_callback([](LibGUI::EventPacket::KeyEvent::event_t event) {
+ int key = 0;
+ if (event.key == key_left)
+ key = JOYPAD_LEFT;
+ else if (event.key == key_right)
+ key = JOYPAD_RIGHT;
+ else if (event.key == key_up)
+ key = JOYPAD_UP;
+ else if (event.key == key_down)
+ key = JOYPAD_DOWN;
+ else if (event.key == key_a)
+ key = JOYPAD_A;
+ else if (event.key == key_b)
+ key = JOYPAD_B;
+ else if (event.key == key_start)
+ key = JOYPAD_START;
+ else if (event.key == key_select)
+ key = JOYPAD_SELECT;
+ else if (event.key == key_throttle)
+ throttle_enabled = event.released();
+ else if (event.pressed() && (event.key == LibInput::Key::Plus || event.key == LibInput::Key::Equals))
+ next_palette();
+ else if (event.pressed() && (event.key == LibInput::Key::Hyphen))
+ prev_palette();
+
+ if (key)
+ joypad_handle(event.pressed(), key);
+ });
+
+ // start emulation
+ memory_start();
+ cpu_start();
+ display_start();
+ timer_start();
+ sound_start();
+
+ time_t rawtime;
+ struct tm *timeinfo;
+ int sec = 500; // any invalid number
+ char new_title[256];
+ int percentage;
+ int throttle_underflow = 0;
+ int throttle_target = throttle_lo + SPEED_ALLOWANCE;
+
+ while(1) {
+ s_window->poll_events();
+
+ for(timing.current_cycles = 0; timing.current_cycles < timing.main_cycles; ) {
+ cpu_cycle();
+ display_cycle();
+ timer_cycle();
+ }
+
+
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+
+ if(sec != timeinfo->tm_sec) {
+ sec = timeinfo->tm_sec;
+ percentage = (drawn_frames * 1000) / 597;
+ sprintf(new_title, "tinygb (%d fps - %d%%)", drawn_frames, percentage);
+ s_window->set_title(new_title);
+
+ // adjust cpu throttle according to acceptable fps (98%-102%)
+ if(throttle_enabled) {
+ if(percentage < throttle_lo) {
+ // emulation is too slow
+ if(!throttle_time) {
+ // throttle_time--;
+
+ if(!throttle_underflow) {
+ throttle_underflow = 1;
+ write_log("WARNING: CPU throttle interval has underflown, emulation may be too slow\n");
+ }
+ } else {
+ //write_log("too slow; decreasing throttle time: %d\n", throttle_time);
+
+ // this will speed up the speed adjustments for a more natural feel
+ if(percentage < (throttle_target/3)) throttle_time /= 3;
+ else if(percentage < (throttle_target/2)) throttle_time /= 2;
+ else throttle_time--;
+ }
+
+ // prevent this from going too low
+ if(throttle_time <= (THROTTLE_THRESHOLD/3)) {
+ cycles_per_throttle += (cycles_per_throttle/5); // delay 20% less often
+ throttle_time = (THROTTLE_THRESHOLD/3);
+ }
+ } else if(percentage > throttle_hi) {
+ // emulation is too fast
+ //write_log("too fast; increasing throttle time: %d\n", throttle_time);
+
+ if(throttle_time) {
+ // to make sure we're not multiplying zero
+ if(percentage > (throttle_target*3)) throttle_time *= 3;
+ else if(percentage > (throttle_target*2)) throttle_time *= 2;
+ else throttle_time++;
+ }
+ else {
+ throttle_time++;
+ }
+
+ // prevent unnecessary lag
+ if(throttle_time > THROTTLE_THRESHOLD) {
+ cycles_per_throttle -= (cycles_per_throttle/5); // delay 20% more often
+ throttle_time = THROTTLE_THRESHOLD;
+ }
+ }
+ }
+
+ drawn_frames = 0;
+ }
+ }
+
+ die(0, "");
+ return 0;
+}
\ No newline at end of file
--
2.49.0

View File

@ -113,6 +113,7 @@ __BEGIN_DECLS
O(SYS_FUTEX, futex) \
O(SYS_GETGROUPS, getgroups) \
O(SYS_SETGROUPS, setgroups) \
O(SYS_CHROOT, chroot) \
enum Syscall
{

View File

@ -596,6 +596,7 @@ int unlinkat(int fd, const char* path, int flag);
int usleep(useconds_t usec);
ssize_t write(int fildes, const void* buf, size_t nbyte);
int chroot(const char* path);
int getpagesize(void);
char* getpass(const char* prompt);

View File

@ -626,6 +626,10 @@ int getopt(int argc, char* const argv[], const char* optstring)
return '?';
}
int chroot(const char* path)
return syscall(SYS_CHROOT, path);
}
int getpagesize(void)
{
return PAGE_SIZE;

View File

@ -31,7 +31,8 @@ namespace LibFont
#if __is_kernel
{
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
// FIXME: This does not account for chroot
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path(Kernel::VirtualFileSystem::get().root_inode(), { 0, 0, 0, 0 }, path, O_RDONLY)).inode;
TRY(file_data.resize(inode->size()));
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
}

View File

@ -128,7 +128,8 @@ namespace LibInput
#if __is_kernel
{
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0));
// FIXME: This does not account for chroot
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path(Kernel::VirtualFileSystem::get().root_inode(), { 0, 0, 0, 0 }, path, 0));
TRY(file_data.resize(file.inode->size()));
TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast<uint8_t*>(file_data.data()), file_data.size() }));
canonical_path = file.canonical_path;

View File

@ -42,6 +42,12 @@ int main(int argc, char** argv)
exit(1);
}
if (fork() == 0)
{
execl("/bin/AudioServer", "AudioServer", NULL);
exit(1);
}
bool first = true;
termios termios;