iniciando o projeto

This commit is contained in:
2026-02-01 16:41:07 -03:00
commit 431ccb69db
12 changed files with 1840 additions and 0 deletions

126
CROSS_COMPILE.md Normal file
View File

@@ -0,0 +1,126 @@
# Cross-Compilation Guide for ARM64
This guide explains how to cross-compile the framebuffer demo for ARM64 (aarch64) architecture, which is used by the R36 Ultra device.
## Prerequisites
### Install ARM64 Cross-Compiler
On Ubuntu/Debian:
```bash
sudo apt-get update
sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install valac
```
### Verify Installation
```bash
aarch64-linux-gnu-gcc --version
```
## Compilation Methods
### Method 1: Using the Compile Script (Recommended)
```bash
./compile.sh arm64
```
This will:
1. Compile Vala code to C
2. Cross-compile C code to ARM64 using `aarch64-linux-gnu-gcc`
3. Create a statically-linked binary for ARM64
### Method 2: Manual Cross-Compilation
#### Step 1: Compile Vala to C
```bash
valac --pkg posix -C framebuffer_demo.vala
```
#### Step 2: Cross-compile C to ARM64
```bash
aarch64-linux-gnu-gcc framebuffer_demo.c -o framebuffer_demo \
$(pkg-config --cflags --libs glib-2.0 gobject-2.0) \
-static
```
### Method 3: Native Compilation (on R36 Ultra)
If you prefer to compile directly on the R36 Ultra device:
```bash
./compile.sh
```
## Verifying the Binary
Check the compiled binary architecture:
```bash
file framebuffer_demo
```
Expected output:
```
framebuffer_demo: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, ...
```
## Transferring to R36 Ultra
### Using SCP
```bash
scp framebuffer_demo user@r36ultra:/home/user/
```
### Using USB/SD Card
1. Copy `framebuffer_demo` to USB drive or SD card
2. Insert into R36 Ultra
3. Copy to device storage
## Running on R36 Ultra
```bash
chmod +x framebuffer_demo
sudo ./framebuffer_demo
```
## Troubleshooting
### Cross-compiler not found
```bash
sudo apt-get install gcc-aarch64-linux-gnu
```
### Missing GLib dependencies
```bash
sudo apt-get install libglib2.0-dev
```
### Binary won't run on device
- Ensure you compiled for the correct architecture (ARM64/aarch64)
- Try static linking: add `-static` flag to gcc command
- Check device architecture: `uname -m` (should show `aarch64`)
### Permission denied on /dev/fb0
```bash
sudo ./framebuffer_demo
```
## Static vs Dynamic Linking
### Static Linking (Recommended for R36 Ultra)
- Binary includes all dependencies
- Larger file size
- No dependency issues on target device
- Use `-static` flag
### Dynamic Linking
- Smaller binary
- Requires compatible libraries on target device
- May have compatibility issues
- Remove `-static` flag
## Architecture Information
- **R36 Ultra**: ARM64 (aarch64)
- **Cross-compiler**: `aarch64-linux-gnu-gcc`
- **Target**: Linux ARM 64-bit

150
MENU_README.md Normal file
View File

@@ -0,0 +1,150 @@
# Menu Interativo com Navegação por Joystick - R36 Ultra
## ✅ Compilado com Sucesso para ARM64!
Sistema de menu interativo com suporte a navegação por joystick/gamepad para R36 Ultra.
## 📦 Arquivos
- **`menu_demo.c`** - Código fonte do menu interativo
- **`menu_demo`** - Binário ARM64 (755KB, estaticamente linkado)
- **`compile_menu.sh`** - Script de compilação
## 🎮 Características
### Interface
- ✅ 5 botões navegáveis
- ✅ Destaque visual do botão selecionado
- ✅ Bordas coloridas (amarelo quando selecionado)
- ✅ Fundo escuro com texto claro
- ✅ Título "MENU PRINCIPAL"
- ✅ Instruções na parte inferior
### Controles Suportados
- **D-Pad Cima/Baixo** - Navegar entre botões
- **Botão A / Enter** - Selecionar opção
- **ESC** - Sair
- **Ctrl+C** - Forçar saída
### Opções do Menu
1. **INICIAR JOGO**
2. **CONFIGURACOES**
3. **CARREGAR SAVE**
4. **CREDITOS**
5. **SAIR** (encerra o programa)
## 🚀 Como Usar
### Transferir para R36 Ultra
**Via SCP:**
```bash
scp menu_demo user@r36ultra:/home/user/
```
**Via USB/SD Card:**
1. Copie `menu_demo` para USB/SD
2. Insira no R36 Ultra
3. Copie para o dispositivo
### Executar no R36 Ultra
```bash
chmod +x menu_demo
sudo ./menu_demo
```
## 🎨 Cores e Visual
- **Botão Normal**: Fundo cinza escuro (80,80,80) com borda clara
- **Botão Selecionado**: Fundo azul (50,100,200) com borda amarela (255,200,0)
- **Texto**: Branco (255,255,255)
- **Fundo**: Cinza escuro (30,30,30)
## 🔧 Recompilar
### Para ARM64 (cross-compile):
```bash
./compile_menu.sh arm64
```
### Para nativo (x86_64):
```bash
./compile_menu.sh
```
## 📝 Personalização
### Adicionar Novos Botões
Edite a função `main()` em `menu_demo.c`:
```c
menu_add_button(&menu, "NOVO BOTAO");
```
### Alterar Cores
Edite a função `draw_button()`:
```c
// Botão selecionado (B, G, R, A)
draw_rectangle(fb, btn->x, btn->y, btn->width, btn->height, 200, 100, 50, 255);
```
### Alterar Tamanho dos Botões
No topo do arquivo:
```c
#define BUTTON_HEIGHT 60
#define BUTTON_WIDTH 500
#define BUTTON_MARGIN 10
```
## 🎯 Detecção de Entrada
O programa tenta abrir automaticamente os seguintes dispositivos:
- `/dev/input/event0`
- `/dev/input/event1`
- `/dev/input/event2`
- `/dev/input/event3`
- `/dev/input/js0`
Se nenhum dispositivo for encontrado, o programa ainda funciona mas você precisará usar SSH ou terminal para enviar comandos.
## 🔍 Debugging
Para ver qual dispositivo de entrada foi aberto:
```bash
sudo ./menu_demo
# Saída: "Opened input device: /dev/input/eventX"
```
Para listar dispositivos de entrada disponíveis:
```bash
ls -la /dev/input/
```
## 💡 Próximos Passos
Para adicionar funcionalidade aos botões, edite o switch case em `main()`:
```c
case BTN_SOUTH: // A button
case KEY_ENTER:
printf("Activated: %s\n", menu.buttons[menu.selected].text);
if (menu.selected == 0) { // INICIAR JOGO
// Adicione sua lógica aqui
}
break;
```
## 📊 Informações Técnicas
- **Resolução**: 720x720 pixels
- **Formato**: BGRA (4 bytes por pixel)
- **Framebuffer**: `/dev/fb0`
- **Arquitetura**: ARM64 (aarch64)
- **Linkagem**: Estática (sem dependências)
- **Tamanho**: 755KB

86
README.md Normal file
View File

@@ -0,0 +1,86 @@
# R36 Ultra Framebuffer Demo - ARM64 Build
## ✅ Successfully Compiled for ARM64!
The program has been cross-compiled for ARM64 (aarch64) architecture.
## Files
- **`framebuffer_simple.c`** - Pure C implementation (no dependencies)
- **`framebuffer_demo.vala`** - Vala implementation (requires GLib)
- **`framebuffer_demo`** - ARM64 binary (statically linked, ready to run)
- **`compile_simple.sh`** - Compilation script for C version
## Binary Information
```
framebuffer_demo: ELF 64-bit LSB executable, ARM aarch64, statically linked
```
This binary is:
- ✅ Compiled for ARM64 (R36 Ultra architecture)
- ✅ Statically linked (no dependencies needed)
- ✅ Ready to transfer and run on R36 Ultra
## Transfer to R36 Ultra
### Option 1: SCP (Network Transfer)
```bash
scp framebuffer_demo user@r36ultra-ip:/home/user/
```
### Option 2: USB/SD Card
1. Copy `framebuffer_demo` to USB drive or SD card
2. Insert into R36 Ultra
3. Copy to device
## Running on R36 Ultra
```bash
chmod +x framebuffer_demo
sudo ./framebuffer_demo
```
## What It Does
The program:
1. Opens `/dev/fb0` framebuffer (720x720, BGRA format)
2. Draws colorful shapes:
- Red rectangle
- Green circle
- Blue rectangle
- Yellow circle
3. Waits for Enter key
4. Clears screen and exits
## Recompiling
### For ARM64 (cross-compile):
```bash
./compile_simple.sh arm64
```
### For native (x86_64):
```bash
./compile_simple.sh
```
## Customization
Edit `framebuffer_simple.c` and use these functions:
- `fill_screen(fb, b, g, r, a)` - Fill screen with color
- `set_pixel(fb, x, y, b, g, r, a)` - Set individual pixel
- `draw_rectangle(fb, x, y, w, h, b, g, r, a)` - Draw rectangle
- `draw_circle(fb, cx, cy, radius, b, g, r, a)` - Draw circle
- `fb_update(fb)` - Write to framebuffer
**Note**: Colors are in BGRA format (Blue, Green, Red, Alpha)
## Advantages of C Version
- ✅ No dependencies (pure C, statically linked)
- ✅ Easy cross-compilation
- ✅ Small binary size
- ✅ Fast execution
- ✅ Works on any ARM64 Linux system

49
compile.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
# Check if cross-compilation is requested
if [ "$1" == "arm64" ] || [ "$1" == "aarch64" ]; then
echo "Cross-compiling Vala framebuffer demo for ARM64..."
# Check if cross-compiler is available
if ! command -v aarch64-linux-gnu-gcc &> /dev/null; then
echo "Error: ARM64 cross-compiler not found!"
echo "Install with: sudo apt-get install gcc-aarch64-linux-gnu"
exit 1
fi
# Compile Vala to C
echo "Step 1: Compiling Vala to C..."
valac --pkg posix -C framebuffer_demo.vala
if [ $? -ne 0 ]; then
echo "Vala to C compilation failed!"
exit 1
fi
# Cross-compile C to ARM64
echo "Step 2: Cross-compiling C to ARM64..."
aarch64-linux-gnu-gcc framebuffer_demo.c -o framebuffer_demo \
$(pkg-config --cflags --libs glib-2.0 gobject-2.0)
if [ $? -eq 0 ]; then
echo "Cross-compilation successful!"
echo "Binary compiled for ARM64 (aarch64)"
echo "Transfer to R36 Ultra and run with: sudo ./framebuffer_demo"
file framebuffer_demo
else
echo "Cross-compilation failed!"
exit 1
fi
else
echo "Compiling Vala framebuffer demo (native)..."
valac --pkg posix framebuffer_demo.vala -o framebuffer_demo
if [ $? -eq 0 ]; then
echo "Compilation successful!"
echo "Run with: sudo ./framebuffer_demo"
file framebuffer_demo
else
echo "Compilation failed!"
exit 1
fi
fi

39
compile_menu.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
# Compilation script for menu demo
if [ "$1" == "arm64" ] || [ "$1" == "aarch64" ]; then
echo "Cross-compiling menu demo for ARM64..."
if ! command -v aarch64-linux-gnu-gcc &> /dev/null; then
echo "Error: ARM64 cross-compiler not found!"
echo "Install with: sudo apt-get install gcc-aarch64-linux-gnu"
exit 1
fi
aarch64-linux-gnu-gcc -o menu_demo menu_demo.c -static
if [ $? -eq 0 ]; then
echo "✅ Cross-compilation successful!"
echo "Binary compiled for ARM64 (aarch64)"
echo "Transfer to R36 Ultra and run with: sudo ./menu_demo"
file menu_demo
ls -lh menu_demo
else
echo "❌ Cross-compilation failed!"
exit 1
fi
else
echo "Compiling menu demo (native)..."
gcc -o menu_demo menu_demo.c
if [ $? -eq 0 ]; then
echo "✅ Compilation successful!"
echo "Run with: sudo ./menu_demo"
file menu_demo
ls -lh menu_demo
else
echo "❌ Compilation failed!"
exit 1
fi
fi

39
compile_simple.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
# Simple ARM64 cross-compilation script for pure C version
if [ "$1" == "arm64" ] || [ "$1" == "aarch64" ]; then
echo "Cross-compiling C framebuffer demo for ARM64..."
# Check if cross-compiler is available
if ! command -v aarch64-linux-gnu-gcc &> /dev/null; then
echo "Error: ARM64 cross-compiler not found!"
echo "Install with: sudo apt-get install gcc-aarch64-linux-gnu"
exit 1
fi
# Cross-compile pure C version (no dependencies)
aarch64-linux-gnu-gcc -o framebuffer_demo framebuffer_simple.c -static
if [ $? -eq 0 ]; then
echo "Cross-compilation successful!"
echo "Binary compiled for ARM64 (aarch64)"
echo "Transfer to R36 Ultra and run with: sudo ./framebuffer_demo"
file framebuffer_demo
else
echo "Cross-compilation failed!"
exit 1
fi
else
echo "Compiling C framebuffer demo (native)..."
gcc -o framebuffer_demo framebuffer_simple.c
if [ $? -eq 0 ]; then
echo "Compilation successful!"
echo "Run with: sudo ./framebuffer_demo"
file framebuffer_demo
else
echo "Compilation failed!"
exit 1
fi
fi

BIN
framebuffer_demo Executable file

Binary file not shown.

736
framebuffer_demo.c Normal file
View File

@@ -0,0 +1,736 @@
/* framebuffer_demo.c generated by valac 0.56.18, the Vala compiler
* generated from framebuffer_demo.vala, do not modify */
#include <glib-object.h>
#include <glib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
#define FRAMEBUFFER_DEMO_WIDTH 720
#define FRAMEBUFFER_DEMO_HEIGHT 720
#define FRAMEBUFFER_DEMO_BPP 4
#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif
#if !defined(VALA_EXTERN)
#if defined(_MSC_VER)
#define VALA_EXTERN __declspec(dllexport) extern
#elif __GNUC__ >= 4
#define VALA_EXTERN __attribute__((visibility("default"))) extern
#else
#define VALA_EXTERN extern
#endif
#endif
#define TYPE_FRAMEBUFFER_DEMO (framebuffer_demo_get_type ())
#define FRAMEBUFFER_DEMO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FRAMEBUFFER_DEMO, FramebufferDemo))
#define FRAMEBUFFER_DEMO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FRAMEBUFFER_DEMO, FramebufferDemoClass))
#define IS_FRAMEBUFFER_DEMO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FRAMEBUFFER_DEMO))
#define IS_FRAMEBUFFER_DEMO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FRAMEBUFFER_DEMO))
#define FRAMEBUFFER_DEMO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FRAMEBUFFER_DEMO, FramebufferDemoClass))
typedef struct _FramebufferDemo FramebufferDemo;
typedef struct _FramebufferDemoClass FramebufferDemoClass;
typedef struct _FramebufferDemoPrivate FramebufferDemoPrivate;
#define _framebuffer_demo_unref0(var) ((var == NULL) ? NULL : (var = (framebuffer_demo_unref (var), NULL)))
#define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
typedef struct _ParamSpecFramebufferDemo ParamSpecFramebufferDemo;
struct _FramebufferDemo {
GTypeInstance parent_instance;
volatile int ref_count;
FramebufferDemoPrivate * priv;
};
struct _FramebufferDemoClass {
GTypeClass parent_class;
void (*finalize) (FramebufferDemo *self);
};
struct _FramebufferDemoPrivate {
gint fb_fd;
guint8* framebuffer;
gint framebuffer_length1;
gint _framebuffer_size_;
};
struct _ParamSpecFramebufferDemo {
GParamSpec parent_instance;
};
static gint FramebufferDemo_private_offset;
static gpointer framebuffer_demo_parent_class = NULL;
VALA_EXTERN gpointer framebuffer_demo_ref (gpointer instance);
VALA_EXTERN void framebuffer_demo_unref (gpointer instance);
VALA_EXTERN GParamSpec* param_spec_framebuffer_demo (const gchar* name,
const gchar* nick,
const gchar* blurb,
GType object_type,
GParamFlags flags);
VALA_EXTERN void value_set_framebuffer_demo (GValue* value,
gpointer v_object);
VALA_EXTERN void value_take_framebuffer_demo (GValue* value,
gpointer v_object);
VALA_EXTERN gpointer value_get_framebuffer_demo (const GValue* value);
VALA_EXTERN GType framebuffer_demo_get_type (void) G_GNUC_CONST ;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FramebufferDemo, framebuffer_demo_unref)
VALA_EXTERN FramebufferDemo* framebuffer_demo_new (void);
VALA_EXTERN FramebufferDemo* framebuffer_demo_construct (GType object_type);
VALA_EXTERN void framebuffer_demo_set_pixel (FramebufferDemo* self,
gint x,
gint y,
guint8 b,
guint8 g,
guint8 r,
guint8 a);
VALA_EXTERN void framebuffer_demo_fill_screen (FramebufferDemo* self,
guint8 b,
guint8 g,
guint8 r,
guint8 a);
VALA_EXTERN void framebuffer_demo_draw_rectangle (FramebufferDemo* self,
gint x,
gint y,
gint w,
gint h,
guint8 b,
guint8 g,
guint8 r,
guint8 a);
VALA_EXTERN void framebuffer_demo_draw_circle (FramebufferDemo* self,
gint cx,
gint cy,
gint radius,
guint8 b,
guint8 g,
guint8 r,
guint8 a);
VALA_EXTERN void framebuffer_demo_update (FramebufferDemo* self);
VALA_EXTERN gboolean framebuffer_demo_is_open (FramebufferDemo* self);
static gint framebuffer_demo_main (gchar** args,
gint args_length1);
static void framebuffer_demo_finalize (FramebufferDemo * obj);
static GType framebuffer_demo_get_type_once (void);
static inline gpointer
framebuffer_demo_get_instance_private (FramebufferDemo* self)
{
return G_STRUCT_MEMBER_P (self, FramebufferDemo_private_offset);
}
FramebufferDemo*
framebuffer_demo_construct (GType object_type)
{
FramebufferDemo* self = NULL;
guint8* _tmp2_;
FILE* _tmp3_;
FILE* _tmp4_;
self = (FramebufferDemo*) g_type_create_instance (object_type);
self->priv->fb_fd = open ("/dev/fb0", O_RDWR, (mode_t) 0);
if (self->priv->fb_fd < 0) {
FILE* _tmp0_;
FILE* _tmp1_;
_tmp0_ = stderr;
fprintf (_tmp0_, "Error: Cannot open framebuffer device /dev/fb0\n");
_tmp1_ = stderr;
fprintf (_tmp1_, "Make sure you have permissions (try running with sudo)\n");
return self;
}
_tmp2_ = g_new0 (guint8, (FRAMEBUFFER_DEMO_WIDTH * FRAMEBUFFER_DEMO_HEIGHT) * FRAMEBUFFER_DEMO_BPP);
self->priv->framebuffer = (g_free (self->priv->framebuffer), NULL);
self->priv->framebuffer = _tmp2_;
self->priv->framebuffer_length1 = (FRAMEBUFFER_DEMO_WIDTH * FRAMEBUFFER_DEMO_HEIGHT) * FRAMEBUFFER_DEMO_BPP;
self->priv->_framebuffer_size_ = self->priv->framebuffer_length1;
_tmp3_ = stdout;
fprintf (_tmp3_, "Framebuffer opened successfully\n");
_tmp4_ = stdout;
fprintf (_tmp4_, "Resolution: %dx%d, Format: BGRA\n", FRAMEBUFFER_DEMO_WIDTH, FRAMEBUFFER_DEMO_HEIGHT);
return self;
}
FramebufferDemo*
framebuffer_demo_new (void)
{
return framebuffer_demo_construct (TYPE_FRAMEBUFFER_DEMO);
}
void
framebuffer_demo_set_pixel (FramebufferDemo* self,
gint x,
gint y,
guint8 b,
guint8 g,
guint8 r,
guint8 a)
{
gboolean _tmp0_ = FALSE;
gboolean _tmp1_ = FALSE;
gboolean _tmp2_ = FALSE;
gint offset = 0;
guint8* _tmp3_;
gint _tmp3__length1;
guint8* _tmp4_;
gint _tmp4__length1;
guint8* _tmp5_;
gint _tmp5__length1;
guint8* _tmp6_;
gint _tmp6__length1;
g_return_if_fail (self != NULL);
if (x < 0) {
_tmp2_ = TRUE;
} else {
_tmp2_ = x >= FRAMEBUFFER_DEMO_WIDTH;
}
if (_tmp2_) {
_tmp1_ = TRUE;
} else {
_tmp1_ = y < 0;
}
if (_tmp1_) {
_tmp0_ = TRUE;
} else {
_tmp0_ = y >= FRAMEBUFFER_DEMO_HEIGHT;
}
if (_tmp0_) {
return;
}
offset = ((y * FRAMEBUFFER_DEMO_WIDTH) + x) * FRAMEBUFFER_DEMO_BPP;
_tmp3_ = self->priv->framebuffer;
_tmp3__length1 = self->priv->framebuffer_length1;
_tmp3_[offset + 0] = b;
_tmp4_ = self->priv->framebuffer;
_tmp4__length1 = self->priv->framebuffer_length1;
_tmp4_[offset + 1] = g;
_tmp5_ = self->priv->framebuffer;
_tmp5__length1 = self->priv->framebuffer_length1;
_tmp5_[offset + 2] = r;
_tmp6_ = self->priv->framebuffer;
_tmp6__length1 = self->priv->framebuffer_length1;
_tmp6_[offset + 3] = a;
}
void
framebuffer_demo_fill_screen (FramebufferDemo* self,
guint8 b,
guint8 g,
guint8 r,
guint8 a)
{
g_return_if_fail (self != NULL);
{
gint y = 0;
y = 0;
{
gboolean _tmp0_ = FALSE;
_tmp0_ = TRUE;
while (TRUE) {
if (!_tmp0_) {
gint _tmp1_;
_tmp1_ = y;
y = _tmp1_ + 1;
}
_tmp0_ = FALSE;
if (!(y < FRAMEBUFFER_DEMO_HEIGHT)) {
break;
}
{
gint x = 0;
x = 0;
{
gboolean _tmp2_ = FALSE;
_tmp2_ = TRUE;
while (TRUE) {
if (!_tmp2_) {
gint _tmp3_;
_tmp3_ = x;
x = _tmp3_ + 1;
}
_tmp2_ = FALSE;
if (!(x < FRAMEBUFFER_DEMO_WIDTH)) {
break;
}
framebuffer_demo_set_pixel (self, x, y, b, g, r, a);
}
}
}
}
}
}
}
void
framebuffer_demo_draw_rectangle (FramebufferDemo* self,
gint x,
gint y,
gint w,
gint h,
guint8 b,
guint8 g,
guint8 r,
guint8 a)
{
g_return_if_fail (self != NULL);
{
gint dy = 0;
dy = 0;
{
gboolean _tmp0_ = FALSE;
_tmp0_ = TRUE;
while (TRUE) {
if (!_tmp0_) {
gint _tmp1_;
_tmp1_ = dy;
dy = _tmp1_ + 1;
}
_tmp0_ = FALSE;
if (!(dy < h)) {
break;
}
{
gint dx = 0;
dx = 0;
{
gboolean _tmp2_ = FALSE;
_tmp2_ = TRUE;
while (TRUE) {
if (!_tmp2_) {
gint _tmp3_;
_tmp3_ = dx;
dx = _tmp3_ + 1;
}
_tmp2_ = FALSE;
if (!(dx < w)) {
break;
}
framebuffer_demo_set_pixel (self, x + dx, y + dy, b, g, r, a);
}
}
}
}
}
}
}
void
framebuffer_demo_draw_circle (FramebufferDemo* self,
gint cx,
gint cy,
gint radius,
guint8 b,
guint8 g,
guint8 r,
guint8 a)
{
g_return_if_fail (self != NULL);
{
gint y = 0;
y = -radius;
{
gboolean _tmp0_ = FALSE;
_tmp0_ = TRUE;
while (TRUE) {
if (!_tmp0_) {
gint _tmp1_;
_tmp1_ = y;
y = _tmp1_ + 1;
}
_tmp0_ = FALSE;
if (!(y <= radius)) {
break;
}
{
gint x = 0;
x = -radius;
{
gboolean _tmp2_ = FALSE;
_tmp2_ = TRUE;
while (TRUE) {
if (!_tmp2_) {
gint _tmp3_;
_tmp3_ = x;
x = _tmp3_ + 1;
}
_tmp2_ = FALSE;
if (!(x <= radius)) {
break;
}
if (((x * x) + (y * y)) <= (radius * radius)) {
framebuffer_demo_set_pixel (self, cx + x, cy + y, b, g, r, a);
}
}
}
}
}
}
}
}
void
framebuffer_demo_update (FramebufferDemo* self)
{
gssize written = 0L;
guint8* _tmp1_;
gint _tmp1__length1;
guint8* _tmp2_;
gint _tmp2__length1;
g_return_if_fail (self != NULL);
if (self->priv->fb_fd < 0) {
FILE* _tmp0_;
_tmp0_ = stderr;
fprintf (_tmp0_, "Error: Framebuffer not opened\n");
return;
}
lseek (self->priv->fb_fd, (off_t) 0, SEEK_SET);
_tmp1_ = self->priv->framebuffer;
_tmp1__length1 = self->priv->framebuffer_length1;
_tmp2_ = self->priv->framebuffer;
_tmp2__length1 = self->priv->framebuffer_length1;
written = write (self->priv->fb_fd, _tmp1_, (gsize) _tmp2__length1);
if (written < ((gssize) 0)) {
FILE* _tmp3_;
_tmp3_ = stderr;
fprintf (_tmp3_, "Error writing to framebuffer\n");
}
}
gboolean
framebuffer_demo_is_open (FramebufferDemo* self)
{
gboolean result;
g_return_val_if_fail (self != NULL, FALSE);
result = self->priv->fb_fd >= 0;
return result;
}
static gchar*
g_file_stream_read_line (FILE* self)
{
gint c = 0;
GString* ret = NULL;
GString* _tmp3_;
gchar* result;
g_return_val_if_fail (self != NULL, NULL);
ret = NULL;
while (TRUE) {
GString* _tmp0_;
GString* _tmp2_;
c = fgetc (self);
if (!(c != EOF)) {
break;
}
_tmp0_ = ret;
if (_tmp0_ == NULL) {
GString* _tmp1_;
_tmp1_ = g_string_new ("");
_g_string_free0 (ret);
ret = _tmp1_;
}
if (c == ((gint) '\n')) {
break;
}
_tmp2_ = ret;
g_string_append_c ((GString*) _tmp2_, (gchar) c);
}
_tmp3_ = ret;
if (_tmp3_ == NULL) {
result = NULL;
_g_string_free0 (ret);
return result;
} else {
GString* _tmp4_;
gchar* _tmp5_;
_tmp4_ = ret;
_tmp5_ = ((GString*) _tmp4_)->str;
((GString*) _tmp4_)->str = NULL;
result = _tmp5_;
_g_string_free0 (ret);
return result;
}
}
static gint
framebuffer_demo_main (gchar** args,
gint args_length1)
{
FramebufferDemo* fb = NULL;
FramebufferDemo* _tmp0_;
FramebufferDemo* _tmp1_;
FILE* _tmp2_;
FramebufferDemo* _tmp3_;
FramebufferDemo* _tmp4_;
FramebufferDemo* _tmp5_;
FramebufferDemo* _tmp6_;
FramebufferDemo* _tmp7_;
FramebufferDemo* _tmp8_;
FILE* _tmp9_;
FILE* _tmp10_;
gchar* _tmp11_;
gchar* _tmp12_;
FramebufferDemo* _tmp13_;
FramebufferDemo* _tmp14_;
FILE* _tmp15_;
gint result;
_tmp0_ = framebuffer_demo_new ();
fb = _tmp0_;
_tmp1_ = fb;
if (!framebuffer_demo_is_open (_tmp1_)) {
result = 1;
_framebuffer_demo_unref0 (fb);
return result;
}
_tmp2_ = stdout;
fprintf (_tmp2_, "Drawing demo graphics...\n");
_tmp3_ = fb;
framebuffer_demo_fill_screen (_tmp3_, (guint8) 0, (guint8) 0, (guint8) 0, (guint8) 255);
_tmp4_ = fb;
framebuffer_demo_draw_rectangle (_tmp4_, 100, 100, 200, 150, (guint8) 0, (guint8) 0, (guint8) 255, (guint8) 255);
_tmp5_ = fb;
framebuffer_demo_draw_circle (_tmp5_, 500, 200, 80, (guint8) 0, (guint8) 255, (guint8) 0, (guint8) 255);
_tmp6_ = fb;
framebuffer_demo_draw_rectangle (_tmp6_, 200, 400, 300, 100, (guint8) 255, (guint8) 0, (guint8) 0, (guint8) 255);
_tmp7_ = fb;
framebuffer_demo_draw_circle (_tmp7_, 360, 360, 100, (guint8) 0, (guint8) 255, (guint8) 255, (guint8) 255);
_tmp8_ = fb;
framebuffer_demo_update (_tmp8_);
_tmp9_ = stdout;
fprintf (_tmp9_, "Graphics drawn! Press Enter to clear and exit...\n");
_tmp10_ = stdin;
_tmp11_ = g_file_stream_read_line (_tmp10_);
_tmp12_ = _tmp11_;
_g_free0 (_tmp12_);
_tmp13_ = fb;
framebuffer_demo_fill_screen (_tmp13_, (guint8) 0, (guint8) 0, (guint8) 0, (guint8) 255);
_tmp14_ = fb;
framebuffer_demo_update (_tmp14_);
_tmp15_ = stdout;
fprintf (_tmp15_, "Done!\n");
result = 0;
_framebuffer_demo_unref0 (fb);
return result;
}
int
main (int argc,
char ** argv)
{
return framebuffer_demo_main (argv, argc);
}
static void
value_framebuffer_demo_init (GValue* value)
{
value->data[0].v_pointer = NULL;
}
static void
value_framebuffer_demo_free_value (GValue* value)
{
if (value->data[0].v_pointer) {
framebuffer_demo_unref (value->data[0].v_pointer);
}
}
static void
value_framebuffer_demo_copy_value (const GValue* src_value,
GValue* dest_value)
{
if (src_value->data[0].v_pointer) {
dest_value->data[0].v_pointer = framebuffer_demo_ref (src_value->data[0].v_pointer);
} else {
dest_value->data[0].v_pointer = NULL;
}
}
static gpointer
value_framebuffer_demo_peek_pointer (const GValue* value)
{
return value->data[0].v_pointer;
}
static gchar*
value_framebuffer_demo_collect_value (GValue* value,
guint n_collect_values,
GTypeCValue* collect_values,
guint collect_flags)
{
if (collect_values[0].v_pointer) {
FramebufferDemo * object;
object = collect_values[0].v_pointer;
if (object->parent_instance.g_class == NULL) {
return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
}
value->data[0].v_pointer = framebuffer_demo_ref (object);
} else {
value->data[0].v_pointer = NULL;
}
return NULL;
}
static gchar*
value_framebuffer_demo_lcopy_value (const GValue* value,
guint n_collect_values,
GTypeCValue* collect_values,
guint collect_flags)
{
FramebufferDemo ** object_p;
object_p = collect_values[0].v_pointer;
if (!object_p) {
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
}
if (!value->data[0].v_pointer) {
*object_p = NULL;
} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
*object_p = value->data[0].v_pointer;
} else {
*object_p = framebuffer_demo_ref (value->data[0].v_pointer);
}
return NULL;
}
GParamSpec*
param_spec_framebuffer_demo (const gchar* name,
const gchar* nick,
const gchar* blurb,
GType object_type,
GParamFlags flags)
{
ParamSpecFramebufferDemo* spec;
g_return_val_if_fail (g_type_is_a (object_type, TYPE_FRAMEBUFFER_DEMO), NULL);
spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
G_PARAM_SPEC (spec)->value_type = object_type;
return G_PARAM_SPEC (spec);
}
gpointer
value_get_framebuffer_demo (const GValue* value)
{
g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FRAMEBUFFER_DEMO), NULL);
return value->data[0].v_pointer;
}
void
value_set_framebuffer_demo (GValue* value,
gpointer v_object)
{
FramebufferDemo * old;
g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FRAMEBUFFER_DEMO));
old = value->data[0].v_pointer;
if (v_object) {
g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FRAMEBUFFER_DEMO));
g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
value->data[0].v_pointer = v_object;
framebuffer_demo_ref (value->data[0].v_pointer);
} else {
value->data[0].v_pointer = NULL;
}
if (old) {
framebuffer_demo_unref (old);
}
}
void
value_take_framebuffer_demo (GValue* value,
gpointer v_object)
{
FramebufferDemo * old;
g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_FRAMEBUFFER_DEMO));
old = value->data[0].v_pointer;
if (v_object) {
g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_FRAMEBUFFER_DEMO));
g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
value->data[0].v_pointer = v_object;
} else {
value->data[0].v_pointer = NULL;
}
if (old) {
framebuffer_demo_unref (old);
}
}
static void
framebuffer_demo_class_init (FramebufferDemoClass * klass,
gpointer klass_data)
{
framebuffer_demo_parent_class = g_type_class_peek_parent (klass);
((FramebufferDemoClass *) klass)->finalize = framebuffer_demo_finalize;
g_type_class_adjust_private_offset (klass, &FramebufferDemo_private_offset);
}
static void
framebuffer_demo_instance_init (FramebufferDemo * self,
gpointer klass)
{
self->priv = framebuffer_demo_get_instance_private (self);
self->ref_count = 1;
}
static void
framebuffer_demo_finalize (FramebufferDemo * obj)
{
FramebufferDemo * self;
self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_FRAMEBUFFER_DEMO, FramebufferDemo);
g_signal_handlers_destroy (self);
if (self->priv->fb_fd >= 0) {
close (self->priv->fb_fd);
}
self->priv->framebuffer = (g_free (self->priv->framebuffer), NULL);
}
static GType
framebuffer_demo_get_type_once (void)
{
static const GTypeValueTable g_define_type_value_table = { value_framebuffer_demo_init, value_framebuffer_demo_free_value, value_framebuffer_demo_copy_value, value_framebuffer_demo_peek_pointer, "p", value_framebuffer_demo_collect_value, "p", value_framebuffer_demo_lcopy_value };
static const GTypeInfo g_define_type_info = { sizeof (FramebufferDemoClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) framebuffer_demo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (FramebufferDemo), 0, (GInstanceInitFunc) framebuffer_demo_instance_init, &g_define_type_value_table };
static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
GType framebuffer_demo_type_id;
framebuffer_demo_type_id = g_type_register_fundamental (g_type_fundamental_next (), "FramebufferDemo", &g_define_type_info, &g_define_type_fundamental_info, 0);
FramebufferDemo_private_offset = g_type_add_instance_private (framebuffer_demo_type_id, sizeof (FramebufferDemoPrivate));
return framebuffer_demo_type_id;
}
GType
framebuffer_demo_get_type (void)
{
static volatile gsize framebuffer_demo_type_id__once = 0;
if (g_once_init_enter (&framebuffer_demo_type_id__once)) {
GType framebuffer_demo_type_id;
framebuffer_demo_type_id = framebuffer_demo_get_type_once ();
g_once_init_leave (&framebuffer_demo_type_id__once, framebuffer_demo_type_id);
}
return framebuffer_demo_type_id__once;
}
gpointer
framebuffer_demo_ref (gpointer instance)
{
FramebufferDemo * self;
self = instance;
g_atomic_int_inc (&self->ref_count);
return instance;
}
void
framebuffer_demo_unref (gpointer instance)
{
FramebufferDemo * self;
self = instance;
if (g_atomic_int_dec_and_test (&self->ref_count)) {
FRAMEBUFFER_DEMO_GET_CLASS (self)->finalize (self);
g_type_free_instance ((GTypeInstance *) self);
}
}

133
framebuffer_demo.vala Normal file
View File

@@ -0,0 +1,133 @@
using Posix;
public class FramebufferDemo {
private const int WIDTH = 720;
private const int HEIGHT = 720;
private const int BPP = 4; // BGRA = 4 bytes per pixel
private int fb_fd;
private uint8[] framebuffer;
public FramebufferDemo() {
// Open framebuffer device
fb_fd = Posix.open("/dev/fb0", Posix.O_RDWR);
if (fb_fd < 0) {
GLib.stderr.printf("Error: Cannot open framebuffer device /dev/fb0\n");
GLib.stderr.printf("Make sure you have permissions (try running with sudo)\n");
return;
}
// Allocate framebuffer memory
framebuffer = new uint8[WIDTH * HEIGHT * BPP];
GLib.stdout.printf("Framebuffer opened successfully\n");
GLib.stdout.printf("Resolution: %dx%d, Format: BGRA\n", WIDTH, HEIGHT);
}
~FramebufferDemo() {
if (fb_fd >= 0) {
Posix.close(fb_fd);
}
}
// Set a pixel at (x, y) with BGRA color
public void set_pixel(int x, int y, uint8 b, uint8 g, uint8 r, uint8 a) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
return;
}
int offset = (y * WIDTH + x) * BPP;
framebuffer[offset + 0] = b; // Blue
framebuffer[offset + 1] = g; // Green
framebuffer[offset + 2] = r; // Red
framebuffer[offset + 3] = a; // Alpha
}
// Fill entire screen with a color
public void fill_screen(uint8 b, uint8 g, uint8 r, uint8 a) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
set_pixel(x, y, b, g, r, a);
}
}
}
// Draw a rectangle
public void draw_rectangle(int x, int y, int w, int h, uint8 b, uint8 g, uint8 r, uint8 a) {
for (int dy = 0; dy < h; dy++) {
for (int dx = 0; dx < w; dx++) {
set_pixel(x + dx, y + dy, b, g, r, a);
}
}
}
// Draw a circle
public void draw_circle(int cx, int cy, int radius, uint8 b, uint8 g, uint8 r, uint8 a) {
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius) {
set_pixel(cx + x, cy + y, b, g, r, a);
}
}
}
}
// Update the framebuffer (write to /dev/fb0)
public void update() {
if (fb_fd < 0) {
GLib.stderr.printf("Error: Framebuffer not opened\n");
return;
}
// Seek to beginning of framebuffer
Posix.lseek(fb_fd, 0, Posix.SEEK_SET);
// Write framebuffer data
ssize_t written = Posix.write(fb_fd, framebuffer, framebuffer.length);
if (written < 0) {
GLib.stderr.printf("Error writing to framebuffer\n");
}
}
public bool is_open() {
return fb_fd >= 0;
}
public static int main(string[] args) {
var fb = new FramebufferDemo();
if (!fb.is_open()) {
return 1;
}
GLib.stdout.printf("Drawing demo graphics...\n");
// Fill screen with black
fb.fill_screen(0, 0, 0, 255);
// Draw a red rectangle
fb.draw_rectangle(100, 100, 200, 150, 0, 0, 255, 255);
// Draw a green circle
fb.draw_circle(500, 200, 80, 0, 255, 0, 255);
// Draw a blue rectangle
fb.draw_rectangle(200, 400, 300, 100, 255, 0, 0, 255);
// Draw a yellow circle
fb.draw_circle(360, 360, 100, 0, 255, 255, 255);
// Update the framebuffer
fb.update();
GLib.stdout.printf("Graphics drawn! Press Enter to clear and exit...\n");
GLib.stdin.read_line();
// Clear screen before exit
fb.fill_screen(0, 0, 0, 255);
fb.update();
GLib.stdout.printf("Done!\n");
return 0;
}
}

152
framebuffer_simple.c Normal file
View File

@@ -0,0 +1,152 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#define WIDTH 720
#define HEIGHT 720
#define BPP 4 // BGRA = 4 bytes per pixel
typedef struct {
int fb_fd;
uint8_t *framebuffer;
} FramebufferDemo;
// Initialize framebuffer
int fb_init(FramebufferDemo *fb) {
// Open framebuffer device
fb->fb_fd = open("/dev/fb0", O_RDWR);
if (fb->fb_fd < 0) {
fprintf(stderr, "Error: Cannot open framebuffer device /dev/fb0\n");
fprintf(stderr, "Make sure you have permissions (try running with sudo)\n");
return -1;
}
// Allocate framebuffer memory
fb->framebuffer = (uint8_t*)malloc(WIDTH * HEIGHT * BPP);
if (!fb->framebuffer) {
fprintf(stderr, "Error: Cannot allocate framebuffer memory\n");
close(fb->fb_fd);
return -1;
}
printf("Framebuffer opened successfully\n");
printf("Resolution: %dx%d, Format: BGRA\n", WIDTH, HEIGHT);
return 0;
}
// Close framebuffer
void fb_close(FramebufferDemo *fb) {
if (fb->framebuffer) {
free(fb->framebuffer);
fb->framebuffer = NULL;
}
if (fb->fb_fd >= 0) {
close(fb->fb_fd);
fb->fb_fd = -1;
}
}
// Set a pixel at (x, y) with BGRA color
void set_pixel(FramebufferDemo *fb, int x, int y, uint8_t b, uint8_t g, uint8_t r, uint8_t a) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
return;
}
int offset = (y * WIDTH + x) * BPP;
fb->framebuffer[offset + 0] = b; // Blue
fb->framebuffer[offset + 1] = g; // Green
fb->framebuffer[offset + 2] = r; // Red
fb->framebuffer[offset + 3] = a; // Alpha
}
// Fill entire screen with a color
void fill_screen(FramebufferDemo *fb, uint8_t b, uint8_t g, uint8_t r, uint8_t a) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
set_pixel(fb, x, y, b, g, r, a);
}
}
}
// Draw a rectangle
void draw_rectangle(FramebufferDemo *fb, int x, int y, int w, int h,
uint8_t b, uint8_t g, uint8_t r, uint8_t a) {
for (int dy = 0; dy < h; dy++) {
for (int dx = 0; dx < w; dx++) {
set_pixel(fb, x + dx, y + dy, b, g, r, a);
}
}
}
// Draw a circle
void draw_circle(FramebufferDemo *fb, int cx, int cy, int radius,
uint8_t b, uint8_t g, uint8_t r, uint8_t a) {
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius) {
set_pixel(fb, cx + x, cy + y, b, g, r, a);
}
}
}
}
// Update the framebuffer (write to /dev/fb0)
void fb_update(FramebufferDemo *fb) {
if (fb->fb_fd < 0) {
fprintf(stderr, "Error: Framebuffer not opened\n");
return;
}
// Seek to beginning of framebuffer
lseek(fb->fb_fd, 0, SEEK_SET);
// Write framebuffer data
ssize_t written = write(fb->fb_fd, fb->framebuffer, WIDTH * HEIGHT * BPP);
if (written < 0) {
fprintf(stderr, "Error writing to framebuffer\n");
}
}
int main(int argc, char *argv[]) {
FramebufferDemo fb = {0};
if (fb_init(&fb) < 0) {
return 1;
}
printf("Drawing demo graphics...\n");
// Fill screen with black
fill_screen(&fb, 0, 0, 0, 255);
// Draw a red rectangle
draw_rectangle(&fb, 100, 100, 200, 150, 0, 0, 255, 255);
// Draw a green circle
draw_circle(&fb, 500, 200, 80, 0, 255, 0, 255);
// Draw a blue rectangle
draw_rectangle(&fb, 200, 400, 300, 100, 255, 0, 0, 255);
// Draw a yellow circle
draw_circle(&fb, 360, 360, 100, 0, 255, 255, 255);
// Update the framebuffer
fb_update(&fb);
printf("Graphics drawn! Press Enter to clear and exit...\n");
getchar();
// Clear screen before exit
fill_screen(&fb, 0, 0, 0, 255);
fb_update(&fb);
printf("Done!\n");
fb_close(&fb);
return 0;
}

BIN
menu_demo Executable file

Binary file not shown.

330
menu_demo.c Normal file
View File

@@ -0,0 +1,330 @@
#include <fcntl.h>
#include <linux/input.h>
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define WIDTH 720
#define HEIGHT 720
#define BPP 4 // BGRA = 4 bytes per pixel
#define MAX_BUTTONS 10
#define BUTTON_HEIGHT 60
#define BUTTON_WIDTH 500
#define BUTTON_MARGIN 10
typedef struct {
int fb_fd;
uint8_t *framebuffer;
} FramebufferDemo;
typedef struct {
char text[64];
int x, y, width, height;
int id;
} Button;
typedef struct {
Button buttons[MAX_BUTTONS];
int count;
int selected;
} Menu;
// Initialize framebuffer
int fb_init(FramebufferDemo *fb) {
fb->fb_fd = open("/dev/fb0", O_RDWR);
if (fb->fb_fd < 0) {
fprintf(stderr, "Error: Cannot open framebuffer device /dev/fb0\n");
return -1;
}
fb->framebuffer = (uint8_t *)malloc(WIDTH * HEIGHT * BPP);
if (!fb->framebuffer) {
fprintf(stderr, "Error: Cannot allocate framebuffer memory\n");
close(fb->fb_fd);
return -1;
}
printf("Framebuffer initialized: %dx%d BGRA\n", WIDTH, HEIGHT);
return 0;
}
void fb_close(FramebufferDemo *fb) {
if (fb->framebuffer) {
free(fb->framebuffer);
fb->framebuffer = NULL;
}
if (fb->fb_fd >= 0) {
close(fb->fb_fd);
fb->fb_fd = -1;
}
}
void set_pixel(FramebufferDemo *fb, int x, int y, uint8_t b, uint8_t g,
uint8_t r, uint8_t a) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
return;
}
int offset = (y * WIDTH + x) * BPP;
fb->framebuffer[offset + 0] = b;
fb->framebuffer[offset + 1] = g;
fb->framebuffer[offset + 2] = r;
fb->framebuffer[offset + 3] = a;
}
void fill_screen(FramebufferDemo *fb, uint8_t b, uint8_t g, uint8_t r,
uint8_t a) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
set_pixel(fb, x, y, b, g, r, a);
}
}
}
void draw_rectangle(FramebufferDemo *fb, int x, int y, int w, int h, uint8_t b,
uint8_t g, uint8_t r, uint8_t a) {
for (int dy = 0; dy < h; dy++) {
for (int dx = 0; dx < w; dx++) {
set_pixel(fb, x + dx, y + dy, b, g, r, a);
}
}
}
void draw_border(FramebufferDemo *fb, int x, int y, int w, int h, int thickness,
uint8_t b, uint8_t g, uint8_t r, uint8_t a) {
// Top
draw_rectangle(fb, x, y, w, thickness, b, g, r, a);
// Bottom
draw_rectangle(fb, x, y + h - thickness, w, thickness, b, g, r, a);
// Left
draw_rectangle(fb, x, y, thickness, h, b, g, r, a);
// Right
draw_rectangle(fb, x + w - thickness, y, thickness, h, b, g, r, a);
}
// Simple 8x8 font for characters
void draw_char(FramebufferDemo *fb, int x, int y, char c, uint8_t b, uint8_t g,
uint8_t r, uint8_t a) {
// Simple pixel patterns for some characters
static const uint8_t font[][8] = {
{0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00}, // A
{0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00}, // B
{0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00}, // C
{0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00}, // D
{0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00}, // E
{0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00}, // F
{0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00}, // G
{0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, // H
{0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, // I
{0x1E, 0x0C, 0x0C, 0x0C, 0x6C, 0x6C, 0x38, 0x00}, // J
};
if (c >= 'A' && c <= 'J') {
const uint8_t *pattern = font[c - 'A'];
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if (pattern[row] & (1 << (7 - col))) {
set_pixel(fb, x + col * 2, y + row * 2, b, g, r, a);
set_pixel(fb, x + col * 2 + 1, y + row * 2, b, g, r, a);
set_pixel(fb, x + col * 2, y + row * 2 + 1, b, g, r, a);
set_pixel(fb, x + col * 2 + 1, y + row * 2 + 1, b, g, r, a);
}
}
}
}
}
void draw_text(FramebufferDemo *fb, int x, int y, const char *text, uint8_t b,
uint8_t g, uint8_t r, uint8_t a) {
int offset = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (text[i] >= 'A' && text[i] <= 'Z') {
draw_char(fb, x + offset, y, text[i], b, g, r, a);
offset += 18;
} else if (text[i] >= 'a' && text[i] <= 'z') {
draw_char(fb, x + offset, y, text[i] - 32, b, g, r, a);
offset += 18;
} else {
offset += 10; // Space
}
}
}
void draw_button(FramebufferDemo *fb, Button *btn, int selected) {
if (selected) {
// Selected: bright blue background with yellow border
draw_rectangle(fb, btn->x, btn->y, btn->width, btn->height, 200, 100, 50,
255);
draw_border(fb, btn->x, btn->y, btn->width, btn->height, 4, 0, 200, 255,
255);
} else {
// Normal: dark gray background with light border
draw_rectangle(fb, btn->x, btn->y, btn->width, btn->height, 80, 80, 80,
255);
draw_border(fb, btn->x, btn->y, btn->width, btn->height, 2, 150, 150, 150,
255);
}
// Draw text
int text_x = btn->x + 20;
int text_y = btn->y + (btn->height - 16) / 2;
draw_text(fb, text_x, text_y, btn->text, 255, 255, 255, 255);
}
void fb_update(FramebufferDemo *fb) {
if (fb->fb_fd < 0)
return;
lseek(fb->fb_fd, 0, SEEK_SET);
write(fb->fb_fd, fb->framebuffer, WIDTH * HEIGHT * BPP);
}
// Initialize menu
void menu_init(Menu *menu) {
menu->count = 0;
menu->selected = 0;
}
// Add button to menu
void menu_add_button(Menu *menu, const char *text) {
if (menu->count >= MAX_BUTTONS)
return;
Button *btn = &menu->buttons[menu->count];
strncpy(btn->text, text, sizeof(btn->text) - 1);
btn->text[sizeof(btn->text) - 1] = '\0';
btn->width = BUTTON_WIDTH;
btn->height = BUTTON_HEIGHT;
btn->x = (WIDTH - BUTTON_WIDTH) / 2;
btn->y = 100 + menu->count * (BUTTON_HEIGHT + BUTTON_MARGIN);
btn->id = menu->count;
menu->count++;
}
// Draw entire menu
void menu_draw(FramebufferDemo *fb, Menu *menu) {
// Clear screen with dark background
fill_screen(fb, 30, 30, 30, 255);
// Draw title
draw_text(fb, 250, 30, "MENU PRINCIPAL", 0, 255, 255, 255);
// Draw all buttons
for (int i = 0; i < menu->count; i++) {
draw_button(fb, &menu->buttons[i], i == menu->selected);
}
// Draw instructions at bottom
draw_text(fb, 200, HEIGHT - 40, "USE DIRECIONAL E BOTAO A", 200, 200, 200,
255);
}
// Open joystick/gamepad device
int joystick_open() {
// Try common input device paths
const char *devices[] = {"/dev/input/event0", "/dev/input/event1",
"/dev/input/event2", "/dev/input/event3",
"/dev/input/js0", NULL};
for (int i = 0; devices[i] != NULL; i++) {
int fd = open(devices[i], O_RDONLY | O_NONBLOCK);
if (fd >= 0) {
printf("Opened input device: %s\n", devices[i]);
return fd;
}
}
fprintf(stderr, "Warning: Could not open joystick device\n");
fprintf(stderr, "Falling back to keyboard input (arrow keys + Enter)\n");
return -1;
}
int main(int argc, char *argv[]) {
FramebufferDemo fb = {0};
Menu menu = {0};
if (fb_init(&fb) < 0) {
return 1;
}
// Initialize menu
menu_init(&menu);
menu_add_button(&menu, "INICIAR JOGO");
menu_add_button(&menu, "CONFIGURACOES");
menu_add_button(&menu, "CARREGAR SAVE");
menu_add_button(&menu, "CREDITOS");
menu_add_button(&menu, "SAIR");
// Open joystick
int joy_fd = joystick_open();
// Main loop
int running = 1;
printf("Menu running. Use D-pad to navigate, A button to select.\n");
printf("Press Ctrl+C to exit.\n");
while (running) {
// Draw menu
menu_draw(&fb, &menu);
fb_update(&fb);
// Handle input
if (joy_fd >= 0) {
struct input_event ev;
struct pollfd pfd = {.fd = joy_fd, .events = POLLIN};
if (poll(&pfd, 1, 100) > 0) {
if (read(joy_fd, &ev, sizeof(ev)) == sizeof(ev)) {
if (ev.type == EV_KEY && ev.value == 1) {
// Key pressed
switch (ev.code) {
case BTN_DPAD_UP:
case KEY_UP:
if (menu.selected > 0) {
menu.selected--;
printf("Selected: %s\n", menu.buttons[menu.selected].text);
}
break;
case BTN_DPAD_DOWN:
case KEY_DOWN:
if (menu.selected < menu.count - 1) {
menu.selected++;
printf("Selected: %s\n", menu.buttons[menu.selected].text);
}
break;
case BTN_SOUTH: // A button
case KEY_ENTER:
printf("Activated: %s\n", menu.buttons[menu.selected].text);
if (menu.selected == 4) { // SAIR
running = 0;
}
break;
case KEY_ESC:
running = 0;
break;
}
}
}
}
} else {
// Fallback: wait a bit
usleep(100000);
}
}
// Cleanup
if (joy_fd >= 0) {
close(joy_fd);
}
fill_screen(&fb, 0, 0, 0, 255);
fb_update(&fb);
fb_close(&fb);
printf("Menu closed.\n");
return 0;
}