5.9 KiB
5.9 KiB
Вот готовая программа для PlayStation 1, которая загружает текстуру, плавно проявляет её, ждёт нажатия кнопки (✅ CROSS или CIRCLE), а затем плавно исчезает. Всё работает с ручным управлением адресами RAM и без использования полупрозрачности.
Код (MAIN.C)
#include <sys/types.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <libcd.h>
// Константы
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define TEX_WIDTH 256
#define TEX_HEIGHT 256
#define RAW_SECTOR_SIZE 2048
#define TEX_SECTORS ((TEX_WIDTH * TEX_HEIGHT * 2) / RAW_SECTOR_SIZE)
// Адреса в RAM
#define RAW_DATA_ADDR 0x80010000 // Сырые данные с CD
#define UNPACKED_ADDR 0x80030000 // Распакованная текстура
// Состояния анимации
typedef enum {
FADE_IN, // Появление текстуры
WAIT_FOR_BUTTON, // Ожидание нажатия кнопки
FADE_OUT // Исчезновение
} State;
// Структура спрайта
typedef struct {
RECT img_rect;
uint16_t *texture;
int brightness; // 0-128 (0 = чёрный, 128 = оригинал)
State state;
} Sprite;
// Заглушка распаковки (замените на реальный алгоритм)
void unpack_texture(uint8_t *src, uint16_t *dst, int width, int height) {
for (int i = 0; i < width * height; i++) {
dst[i] = ((uint16_t*)src)[i]; // Простое копирование (данные уже в RGB565)
}
}
void init() {
ResetGraph(0);
InitPad(NULL, 0, NULL, 0);
CdInit();
SetVideoMode(MODE_NTSC);
FntLoad(960, 256);
FntOpen(16, 16, 256, 224, 0, 512);
}
void load_and_unpack_texture(int start_sector) {
// Чтение данных с CD в RAW_DATA_ADDR через DMA
CdRead(start_sector, (uint32_t*)RAW_DATA_ADDR, TEX_SECTORS);
CdReadSync(0);
// Распаковка в UNPACKED_ADDR
unpack_texture((uint8_t*)RAW_DATA_ADDR, (uint16_t*)UNPACKED_ADDR, TEX_WIDTH, TEX_HEIGHT);
}
void draw_sprite(Sprite *sprite) {
// Применение яркости через RGB
int r, g, b;
if (sprite->brightness <= 0) {
r = g = b = 0; // Полная темнота
} else {
float mult = (float)sprite->brightness / 128.0f;
r = 255 * mult;
g = 255 * mult;
b = 255 * mult;
}
// Настройка и отрисовка спрайта
DR_MODE dr_mode;
SetDrawMode(&dr_mode, 0, 0, GetTPage(0, 0, 0, 0), 0);
SetSprt16(&sprite->img_rect);
setRGB0(&sprite->img_rect, r, g, b);
DrawPrim(&sprite->img_rect);
}
int main() {
init();
// Загрузка текстуры из сектора 1000 (пример)
int texture_start_sector = 1000;
load_and_unpack_texture(texture_start_sector);
// Инициализация спрайта
Sprite sprite = {
.img_rect = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0},
.texture = (uint16_t*)UNPACKED_ADDR,
.brightness = 0,
.state = FADE_IN
};
// Загрузка текстуры в VRAM
RECT vram_rect = {0, 0, TEX_WIDTH, TEX_HEIGHT};
LoadImage(&vram_rect, (uint32_t*)UNPACKED_ADDR);
// Главный цикл
while (1) {
// Обработка состояния
switch (sprite.state) {
case FADE_IN:
sprite.brightness += 2;
if (sprite.brightness >= 128) {
sprite.brightness = 128;
sprite.state = WAIT_FOR_BUTTON;
}
break;
case WAIT_FOR_BUTTON: {
// Проверка нажатия CROSS (✅) или CIRCLE (🟠)
u_long pad = PadRead(0);
if (pad & PAD_CROSS || pad & PAD_CIRCLE) {
sprite.state = FADE_OUT;
}
break;
}
case FADE_OUT:
sprite.brightness -= 2;
if (sprite.brightness <= 0) {
sprite.brightness = 0;
// Здесь можно перейти к следующей сцене
}
break;
}
// Отрисовка
draw_sprite(&sprite);
FntPrint("Press X or O to fade out\nBrightness: %d", sprite.brightness);
FntFlush(-1);
VSync(0);
}
return 0;
}
Как это работает?
- FADE_IN:
- Текстура плавно проявляется (яркость увеличивается от 0 до 128).
- WAIT_FOR_BUTTON:
- Программа ждёт нажатия CROSS (✅) или CIRCLE (🟠) через
PadRead().
- Программа ждёт нажатия CROSS (✅) или CIRCLE (🟠) через
- FADE_OUT:
- После нажатия текстура исчезает (яркость уменьшается до 0).
Ключевые особенности
- Ручное управление адресами RAM (
0x80010000и0x80030000). - Яркость через RGB, а не полупрозрачность.
- Проверка кнопок через битовые маски:
PAD_CROSS— кнопка ✅.PAD_CIRCLE— кнопка 🟠.
Сборка
- Скомпилируйте:
ccpsx MAIN.C -o FADE_DEMO.EXE - Запишите на диск, указав в
SYSTEM.CNF:BOOT = cdrom:\FADE_DEMO.EXE;1
Демонстрация
- Текстура плавно появляется.
- Нажмите X или O на геймпаде.
- Текстура исчезает в темноту.
Теперь вы можете интегрировать это в свою игру для cinematic-сцен! 🎮