iniciando o projeto
This commit is contained in:
126
CROSS_COMPILE.md
Normal file
126
CROSS_COMPILE.md
Normal 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
150
MENU_README.md
Normal 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
86
README.md
Normal 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
49
compile.sh
Executable 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
39
compile_menu.sh
Executable 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
39
compile_simple.sh
Executable 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
BIN
framebuffer_demo
Executable file
Binary file not shown.
736
framebuffer_demo.c
Normal file
736
framebuffer_demo.c
Normal 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
133
framebuffer_demo.vala
Normal 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
152
framebuffer_simple.c
Normal 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;
|
||||
}
|
||||
330
menu_demo.c
Normal file
330
menu_demo.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user