commit 431ccb69dbb363c0abcb241c9785d8b4f7564847 Author: Benedito Lobo Date: Sun Feb 1 16:41:07 2026 -0300 iniciando o projeto diff --git a/CROSS_COMPILE.md b/CROSS_COMPILE.md new file mode 100644 index 0000000..152eccc --- /dev/null +++ b/CROSS_COMPILE.md @@ -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 diff --git a/MENU_README.md b/MENU_README.md new file mode 100644 index 0000000..a87ef73 --- /dev/null +++ b/MENU_README.md @@ -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4f2490 --- /dev/null +++ b/README.md @@ -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 diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..e68e5a3 --- /dev/null +++ b/compile.sh @@ -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 diff --git a/compile_menu.sh b/compile_menu.sh new file mode 100755 index 0000000..2605b98 --- /dev/null +++ b/compile_menu.sh @@ -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 diff --git a/compile_simple.sh b/compile_simple.sh new file mode 100755 index 0000000..0cd56c2 --- /dev/null +++ b/compile_simple.sh @@ -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 diff --git a/framebuffer_demo b/framebuffer_demo new file mode 100755 index 0000000..df193e8 Binary files /dev/null and b/framebuffer_demo differ diff --git a/framebuffer_demo.c b/framebuffer_demo.c new file mode 100644 index 0000000..23052bb --- /dev/null +++ b/framebuffer_demo.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} + diff --git a/framebuffer_demo.vala b/framebuffer_demo.vala new file mode 100644 index 0000000..1d6ba9c --- /dev/null +++ b/framebuffer_demo.vala @@ -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; + } +} diff --git a/framebuffer_simple.c b/framebuffer_simple.c new file mode 100644 index 0000000..e88b57d --- /dev/null +++ b/framebuffer_simple.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/menu_demo b/menu_demo new file mode 100755 index 0000000..fec8a8e Binary files /dev/null and b/menu_demo differ diff --git a/menu_demo.c b/menu_demo.c new file mode 100644 index 0000000..5ad0732 --- /dev/null +++ b/menu_demo.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}