Files
SergObsidian/PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md
2025-04-20 00:15:46 +05:00

4.6 KiB
Raw Blame History

#include <libgte.h>
#include <libgpu.h>
#include <libgs.h>

/* Структуры данных */
typedef struct {
    uint* next_block;      // Следующий блок DMA (младшие 24 бита)
    uint control;          // Контрольные биты DMA
    uint data_addr;        // Адрес данных
    uint tpage_params;     // Параметры текстуры (TPage)
} DMAControlBlock;

typedef struct {
    short x, y;           // Позиция символа
    short char_width;      // Ширина символа
    ushort flags;         // Флаги рендеринга
    uint* dma_head;       // Голова DMA-цепочки
    uint* dma_tail;       // Хвост DMA-цепочки
} TextRenderState;

/* Константы */
#define SCRAM_BASE   0x1F800000  // Быстрая память PS1
#define DMA_MAGIC    0x80000000  // Флаг DMA-блока
#define CHAR_OFFSET  0x20        // Смещение ASCII-кодов

/* Глобальные переменные (аналоги оригинальных) */
static uint* gDmaNextFree = (uint*)0x8007CE68;
static uint* gDmaCounter = (uint*)0x8007CE6C;
static uint gActiveTpage = 0x8007CA0C;

/* Основная функция рендеринга текста */
DMAControlBlock* RenderTextSystem(
    const char* text, 
    short base_x, 
    short base_y, 
    uint color_flags,
    uint tpage_config
) {
    /* Инициализация состояния */
    TextRenderState state;
    state.x = base_x;
    state.y = base_y;
    state.flags = color_flags;
    
    /* Получаем начальный DMA-блок из SCRAM */
    DMAControlBlock* dma_blocks = (DMAControlBlock*)(*gDmaNextFree | DMA_MAGIC);
    state.dma_head = state.dma_tail = (uint*)dma_blocks;
    
    /* Настройка параметров рендеринга */
    StoreColorToAddr(color_flags, tpage_config);
    InitDMAtextChain(dma_blocks, base_x, base_y);

    /* Основной цикл обработки текста */
    while (*text) {
        char current_char = *text++;
        ushort char_code = current_char - CHAR_OFFSET;
        
        /* Особые обработки для специфичных символов */
        switch (current_char) {
            case 'g': case 'j': case 'p': case 'q': case 'y':
                base_y += 2;  // Смещение для символов с хвостами
                break;
        }

        /* Позиционирование символа */
        short render_x, render_y;
        if (state.flags & 0x10) {
            /* Альтернативный режим позиционирования */
            render_x = base_x - GetCharLeftOffset(char_code);
            render_y = base_y + GetCharBaseline(char_code);
        } else {
            /* Стандартный режим */
            render_x = base_x + dma_blocks->char_width * 8;
            render_y = base_y;
        }

        /* Генерация DMA-команд для символа */
        DMAControlBlock* new_block = AllocDMABlock();
        SetupCharRender(new_block, char_code, render_x, render_y);
        
        /* Добавление в цепочку */
        state.dma_tail->next_block = (uint)new_block & 0xFFFFFF;
        state.dma_tail = new_block;

        /* Обновление позиции */
        if (dma_blocks->char_width == 0) {
            state.dma_head = new_block;
            dma_blocks->char_width = 1;
        }
    }

    /* Финализация текстурных страниц */
    for (int i = 0; i < 2; i++) {
        DMAControlBlock* tpage_block = AllocDMABlock();
        SetDrawTPage(tpage_block, 0, 1, gActiveTpage);
        state.dma_tail->next_block = (uint)tpage_block & 0xFFFFFF;
        state.dma_tail = tpage_block;
    }

    return dma_blocks;
}

/* Вспомогательные функции */
static DMAControlBlock* AllocDMABlock() {
    DMAControlBlock* block = (DMAControlBlock*)(*gDmaNextFree | DMA_MAGIC);
    (*gDmaCounter)--;
    *gDmaNextFree = (*gDmaNextFree & 0xFF000000) | (*block & 0xFFFFFF);
    return block;
}

static void SetupCharRender(DMAControlBlock* block, ushort char_code, short x, short y) {
    /* Настройка параметров символа */
    block->control = 0x1000000;  // Базовые флаги DMA
    block->data_addr = GetCharDataAddr(char_code);
    block->tpage_params = (y << 16) | x;  // Позиция
    
    /* Дополнительные настройки из оригинального кода */
    block->control |= 0x64808080;  // Специфичные флаги PS1
}