PSPx форум

PSPx форум (https://www.pspx.ru/forum/index.php)
-   Программирование для PSP (https://www.pspx.ru/forum/forumdisplay.php?f=101)
-   -   Технологии программирования на PSP (https://www.pspx.ru/forum/showthread.php?t=31184)

wSlava 23.01.2007 14:22

Технологии программирования на PSP
 
Решил создать тему, в которой бы складировалась информация, связанная с девелоперским софтом под PSP, а именно, 2D/3D движки, SDK, библиотеки, средства разработки и т.д.
Первый пост выкладываю о Java виртуальной машине Kilobyte Virtual Machine (KVM) - BLUEKVM - порт J2ME для PSP, вот ссылка на источник :
http://groups-beta.google.com/group/java4psp
То что Java пришла на PSP, очень замечательно, и пусть это не сильно поможет в программировании графики, но есть масса полезных программ , которые можно гораздо проще портировать с PC. Например, у меня есть хороший OpenSource словарь на Java, который поддерживает универсальный многоязыковой формат словарей, которых превеликое множество, а словарь на PSP очень многие и давно просят. И таких полезных программ достаточно много. В общем, кто заинтересуется, исследуйте и отписывайтесь !

wSlava 28.01.2007 15:05

Вложений: 1
Итак, следующая полезная вещь - XML парсер под PSP под названием TinyXML. Сама библиотечка кросплатформенная, вот общее описание http://www.grinninglizard.com/tinyxmldocs/index.html. Исходники TinyXML под PSP взял из проекта PSPoste (почтовик), можете взять из аттачмента.

wSlava 04.03.2007 14:49

На http://ps2dev.org выложили очень полезную документацию про структуру HomeBrew приложений и модулей с точки зрения программирования:
http://ps2dev.org/psp/Tutorials/PSP_...tches.download
MUST HAVE для тех, кто хочет программировать на PSP !

добавлено через 4 минуты
Так же выкладываю ссылку на сводный документ по семинару на Assembly 2006, где очень подробно изложена аппаратная часть PSP и методы ее программирования: http://ps2dev.org/psp/Tutorials/PSP_...embly.download

wSlava 09.03.2007 22:31

Продолжаю тему. На PSP нет, к сожалению, встроенной системы шрифтов, поэтому одна из проблем при программировании - это поддержка этих самых шрифтов. Парсинг стандартных шрифтов - это очень сложно и окажется задачей более сложной и объемной (даже если использовать наработки) чем сама задуманная программа. Второй способ - это использование спрайтов с изображениями букв, очень легко в использовании, но нарисовать этот набор тоже трудоемко. Но есть выход, программа, которая по заданному шрифту, размеру и стилю создаст этот
набор ! Держите исходник на Delphi (автор с ником Spose) :

На форме должны присутствовать:
Button1: TButton; //Кнопка генерации
Image1: TImage; //Тут будем рисовать
Edit1: TEdit;//От суда будем брать название шрифта
Edit3: TEdit;//От суда будем брать цвет шрифта
На нажатие кнопки(OnClick) пишем: var
x,y,z:integer;
c:char;
begin
Image1.Picture.LoadFromFile(′shablon.bmp′); //Ну берем 24 разрядный фон из БИТМАПА
x:=2; //Устанавливаем место отрисовки первой буквы на 2 (первое место будет пробелом)
for c:=′!′ to ′я′ do //Из таблицы символов от "!" до буквы "я" делаем:
with image1.Canvas do
begin
font.Name:=(edit1.Text); //Узнаем название шрифта
font.Size:=12; //Его размер ставим на 12
font.Style:=[fsBold]; //Делаем шрифт ЖИРНЫМ
font.Color:=stringtocolor(edit3.Text); //Ставим цвет шрифта
textout(x*20-trunc(textwidth(c)*1.5),10-(textheight(c) div 2),c); //Рисуем данный(по номеру) символ из таблицы символов (см. выше) на этом месте
x:=x+1; //Следующее место отрисовки
end; //Отрисовали все символы!!!
//Далее идет фильтр обводящий каждую букву черным цветом
for y:=0 to x*20 do //20 - ширина кадра(в одном кадре - одна буква)
for z:=0 to 20 do
if
image1.Canvas.Pixels[y,z]=stringtocolor(edit3.Text) then //Если цвет пикселя=Цвету шрифта то
begin
if
image1.Canvas.Pixels[y-1,z]=clWhite then //Если надо то обводим
image1.Canvas.Pixels[y-1,z]:=clBlack;
if image1.Canvas.Pixels[y-1,z-1]=clWhite then
image1.Canvas.Pixels[y-1,z-1]:=clBlack;
if image1.Canvas.Pixels[y+1,z-1]=clWhite then
image1.Canvas.Pixels[y+1,z-1]:=clBlack;
if image1.Canvas.Pixels[y,z+1]=clWhite then
image1.Canvas.Pixels[y,z+1]:=clBlack;
if image1.Canvas.Pixels[y,z-1]=clWhite then
image1.Canvas.Pixels[y,z-1]:=clBlack;
if image1.Canvas.Pixels[y+1,z+1]=clWhite then
image1.Canvas.Pixels[y+1,z+1]:=clBlack;
if image1.Canvas.Pixels[y+1,z]=clWhite then
image1.Canvas.Pixels[y+1,z]:=clBlack;
if image1.Canvas.Pixels[y-1,z+1]=clWhite then
image1.Canvas.Pixels[y-1,z+1]:=clBlack;
end;
image1.picture.SaveToFile(edit1.text+′.bmp′); //Сохраняем полученый БИТМАП в "Название Шрифта".bmp
end;
Как видите, все очень просто !

BonifacE 16.03.2007 11:47

Начинаю выкладывать занятные статьи с ps2dev
--------------------------------------------------------------------------------------
Попробую немножко просветить по поводу GE процессора , и минимальной обвязки для работы без sceGu библиотеки.

Текста писать много не буду, лучше на примере.

1. Инициализация GE

Перехват VBlankHandler
Установка callbacks от GE процессора

SceVoid GE_Initialize()
{
sceDisplaySetVblankCallback(1,GE_DisplayVBlank,SCE_NULL);

SceGeCbParam cb_param;
cb_param.pSignalFunc = GE_Signal;
cb_param.pSignalCookie = SCE_NULL;
cb_param.pFinishFunc = GE_Finish;
cb_param.pFinishCookie = SCE_NULL;
dsEngine::GE.SetInterruptID(sceGeSetCallback(&cb_param));

}

Теперь рассмотрим сам VBlankHandler

BEGIN_CRITICAL,END_CRITICAL - это семафорная обвязка. (sceKernelWaitSema,sceKernelSignalSema)
здесь происходит установка нового front буффера , также подсчитываеться FPS

/// VBlank Interrupt
SceVoid dsEngine::dsGeCore::VBlankInterrupt(SceUInt32 )
{
BEGIN_CRITICAL();
{
m_VBlankCount++;

if (m_DrawLock == SCE_TRUE)
{
END_CRITICAL();
return;
}

}
END_CRITICAL();

UpdateCommandBufferState();

BEGIN_CRITICAL();
{
if (m_Locked == SCE_FALSE && m_RequestFlip == SCE_TRUE)
{
m_FlipFrameBufferCount++;

sceDisplaySetFrameBuf(m_FlipFrameBufferAddress,512,
SCE_DISPLAY_PIXEL_RGBA8888,SCE_DISPLAY_UPDATETIMING_NEXTHSYNC);

m_CurrFrontBufferAddress = m_FlipFrameBufferAddress;

m_RequestFlip = SCE_FALSE;
}
else
{
profile.missedVBlankCount++;
}

if (m_VBlankCount > 60)
{
m_fCurrentFPS = (static_cast<SceFloat32>(m_FlipFrameBufferCount) * 60.0f) /
static_cast<SceFloat32>(m_VBlankCount);

m_VBlankCount = 0;
m_FlipFrameBufferCount = 0;
}
}
END_CRITICAL();

UpdateCommandBufferState();
}


Теперь самое интересное (UpdateCommandBufferState)
Это как раз display double buffer list.
Непосредственная работа с GE

/// Обновление статусов command push buffer.
/// проверка на окончание отрисовки, и проверка на
/// отсылку нового command push buffer
SceVoid dsEngine::dsGeCore::UpdateCommandBufferState()
{
BEGIN_CRITICAL();
{
// если этот командный буффер уже отослан на исполнение,
// тогда проверяем статус его отрисовки.
if (m_CommandBufferStatus[m_DrawCommandBufferIdx] == CMDBUFFSTATUS_QUEUED)
{
// если список уже отрисовался
if (sceGeDrawSync(1) == SCE_GE_LIST_COMPLETED)
{
// если нет запроса на флип front/back буффер,
// завершаем данный список и просим сделать флип на
// следующем vblank interrupt
if (m_RequestFlip == SCE_FALSE)
{
// запоминаем новый адрес frame buffer для флипа и делаем запрос на флип.
m_FlipFrameBufferAddress = static_cast<SceUInt32*>
(m_CommandBufferFrameAddress[m_DrawCommandBufferIdx]);
m_RequestFlip = SCE_TRUE;

// освобождаем command push buffer
m_CommandBufferStatus[m_DrawCommandBufferIdx] = CMDBUFFSTATUS_FREE;

m_DrawCommandBufferIdx = 1 - m_DrawCommandBufferIdx;
}
}
}

// если коммандный буффер подготовлен к отcылке, отправляем его на GE
if (m_Locked == SCE_FALSE &&
m_CommandBufferStatus[m_DrawCommandBufferIdx] == CMDBUFFSTATUS_READY)
{
if (m_RequestFlip == SCE_FALSE)
{
profile.startGPUTime = sceKernelGetSystemTimeLow();

m_CommandBufferStatus[m_DrawCommandBufferIdx] = CMDBUFFSTATUS_QUEUED;

m_QueueDispListId[m_DrawCommandBufferIdx] = sceGeListEnQueue
(
m_CommandBuffer[m_DrawCommandBufferIdx],
SCE_NULL,
m_InterruptID,
SCE_NULL
);
}
}
}
END_CRITICAL();
}


Все что осталось подсмотреть, это реализация callbacks GE

CMD_FINISH

SceVoid dsEngine::dsGeCore::FinishCallback(SceUInt32 )
{
profile.currentGPUTime = sceKernelGetSystemTimeLow() - profile.startGPUTime;

UpdateCommandBufferState();
}

CMD_SIGNAL

static SceVoid GE_Signal(SceInt32 interruptCode,SceVoid* cookie,const SceVoid* memoryAddress)
{
register SceUShort16 intrCode = static_cast<SceUShort16>(interruptCode);
// внутренние GE library сообщения
if ((intrCode & 0xf000) == 0xf000)
{

// сохранения контекста
if (intrCode == GECORE_SIGNAL_STORECONTEXT)
{
sceGeSaveContext(&geContext);
}
// восстановление контекста
else if (intrCode == GECORE_SIGNAL_RESTORECONTEXT)
{
sceGeRestoreContext(&geContext);
}
// изменение ширины трансляции адресов GE процессора
else if (intrCode == GECORE_SIGNAL_SETADDRESSTRANSLATION)
{
sceGeEdramSetAddrTranslation(sceGeGetCmd(SCE_GE_CMD_END)&0xFFFF);
}
// системные SIGNAL идут через паузу в GE
// поэтому продолжаем работу GE процессора.
sceGeContinue();
}
else
{
if (geSignalCallback != SCE_NULL)
{
geSignalCallback(intrCode);
}
}
}


Работа с COMMAND PUSH BUFFER

Делаем такую функцию в .h

inline SceVoid GE_PUTCOMMAND(SceUInt32 command)
{
*dsEngine::geCmdBuffer++ = command;
}

теперь пример заполнения PUSH BUFFER

static SceVoid GECORE_SetViewport()
{
SceFloat32 sx = static_cast<SceFloat32>( geDisplayWidth / 2);
SceFloat32 sy = static_cast<SceFloat32>(-geDisplayHeight / 2);
SceFloat32 tx = 2048.0f;
SceFloat32 ty = 2048.0f;

GE_PUTCOMMAND(SCE_GE_SET_SX_FLOAT24(sx));
GE_PUTCOMMAND(SCE_GE_SET_SY_FLOAT24(sy));
GE_PUTCOMMAND(SCE_GE_SET_TX_FLOAT24(tx));
GE_PUTCOMMAND(SCE_GE_SET_TY_FLOAT24(ty));
}

.....

SceVoid GECORE_SetDepthRange(SceInt32 depthMin,SceInt32 depthMax)
{
GE_PUTCOMMAND(SCE_GE_SET_MINZ(depthMin));
GE_PUTCOMMAND(SCE_GE_SET_MAXZ(depthMax));

SceFloat32 fDepthMin = static_cast<SceFloat32>(depthMin);
SceFloat32 fDepthMax = static_cast<SceFloat32>(depthMax);

SceFloat32 sz = (fDepthMax - fDepthMin) * 0.5f;
SceFloat32 tz = (fDepthMax + fDepthMin) * 0.5f;

GE_PUTCOMMAND(SCE_GE_SET_SZ_FLOAT24(sz));
GE_PUTCOMMAND(SCE_GE_SET_TZ_FLOAT24(tz));
}

....

BeginFrame/EndFrame

В BeginFrame, показанными выше коммандами делаем DefaultRenderState
Более интересен EndFrame

EndFrame
1. Подводим статистику для профилирования (эмуляция perfhud :) )
и запоминаем значения статистики (например последних 128 значений), что бы выводить графики CPU,GPU выполнения отдельных GE list , etc....

2. Отрисовка интерфейса профилирования

И в конце

geCmdBuffer = SCE_NULL;
m_geCmdBufferStart = SCE_NULL;

BEGIN_CRITICAL();
{
m_CommandBufferStatus[m_FillCommandBufferIdx] = CMDBUFFSTATUS_READY;

if (m_CommandBufferStatus[1 - m_FillCommandBufferIdx] == CMDBUFFSTATUS_FREE)
{
m_DrawCommandBufferIdx = m_FillCommandBufferIdx;
}
}
END_CRITICAL();

m_bFrontBufferValid = SCE_FALSE;

UpdateCommandBufferState();

m_FillCommandBufferIdx = 1 - m_FillCommandBufferIdx;


В BeginFrame соотв. будет

geCmdBuffer = reinterpret_cast<SceUInt32*>
(0x40000000 | reinterpret_cast<SceUInt32>(m_CommandBuffer[m_FillCommandBufferIdx]));
m_geCmdBufferStart = geCmdBuffer;

BonifacE 16.03.2007 11:56

Обнаружилось, что максимальный push buffer fetch rate - ~90mb\s из eDRAM и примерно в 1.6-1.7 раза медленнее из DRAM, из scratchpad совсем медленно и печально, да и странное это пока для меня устройство на PSP. Вывод: храните PB в eDRAM.

Тестировалось очень просто. Забивалось NOP-ами и мерялось между SIGNALs. Данный тест никакой более интересной информации для меня пока не выдал, что печально. Тестировал разные количества NOP-ов (разные размеры PB). Единственное, смущает это небольшая нестабильность и пиковая до 25% (!). Eсли в очереди держать всегда хотябы два lists, то нестабильности нет. Просто прибавляются те 25% если из DRAM, из eDRAM нестабильность сильно меньше.

BonifacE 16.03.2007 12:00

основные функции sceGu*:

// Инициализация графики
sceGuInit();
// Завершение работы с графикой
sceGuTerm();
// Начало работы с новый дисплей-листом
sceGuStart(GU_DIRECT, list); // лист должен быть выровненным на границу 16 байт
// Установка формата пикселей и размера фреймбуфера
// (обычно SCR_WIDTH=480, SCR_HEIGHT=272, BUF_WIDTH=512, PIXEL_SIZE=2 или 4)
sceGuDrawBuffer(GU_PSM_5650, (void*)0, BUF_WIDTH);
// Установка размеров экрана
// Пусть FRAME_SIZE = BUF_WIDTH * SCR_HEIGHT * PIXEL_SIZE
sceGuDispBuffer(SCR_WIDTH, SCR_HEIGHT, (void*) FRAME_SIZE, BUF_WIDTH);
// Установка размеров экрана
sceGuDepthBuffer((void*)(FRAME_SIZE*2), BUF_WIDTH);
// Установка смещения. Пространство рендеринга на PSP – 4096х4096, мы рисуем в центре
sceGuOffset(2048 - (SCR_WIDTH/2), 2048 - (SCR_HEIGHT/2));
// Установка окна - координаты центра и размеры
sceGuViewport(2048, 2048, SCR_WIDTH, SCR_HEIGHT);
// Пространство значений глубины
sceGuDepthRange(65535, 0);
// Закончить текущий дисплей-лист
sceGuFinish();
// Ждать конца отрисовки дисплей-листа
sceGuSync(0, 0);
// Ждать вертикальной синхронизации
sceDisplayWaitVblankStart();
// Поменять местами видимый и рабочий буферы
sceGuSwapBuffers();
// Включить(GU_TRUE) или выключить(GU_FALSE) дисплей
sceGuDisplay(GU_TRUE);
// Выбор формата палитры
sceGuClutMode(GU_PSM_4444, 0, 0xff, 0);
// Загрузка палитры
sceGuClutLoad((PALETTE_ENTRIES/8), pPalette);
// Установка форматы текстуры
sceGuTexMode(GU_PSM_T8, 0, 0, 0);
// Установка текущей текстуры
sceGuTexImage(TEX_LOD, TEX_WIDTH, TEX_HEIGHT, TEXBUF_WIDTH, pTexture);
// Выбор типа фильтрации текстуры (анизотропки нету:)
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
// Отрисовать набор примитивов (индексированных или нет)
sceGuDrawArray(PRIMITIVE_TYPE, VERTEX_FORMAT, VERTEX_COUNT, pIndices, pVertices);

BonifacE 16.03.2007 12:42

еще одна интересная ссылка http://www.psp-programming.com/tutorials/, там можно найти весьма пользительный урок по загрузке и проигрыванию mp3 и основы GU

wSlava 16.03.2007 22:10

Пасиб за сайт, я подробней покопал, вот это уже то что нужно !!!!!!
http://www.psp-programming.com/code/...id=c:tutorials

добавлено через 6 минут
Почитал, отлично, все что нужно по GU, по крайней мере для начала. В общем буду переваривать.

wSlava 17.03.2007 18:36

Вот еще библиотеку Oldschool Library for PSP приглядел
http://dl.qj.net/Oldschool-Library-f...5422/catid/202
вот экзамплы:
http://oslib.palib.info/samples/

wSlava 23.03.2007 23:20

Нашел хороший мануал по Makefile:
http://www.eng.hawaii.edu/Tutor/Make/index.html

wSlava 09.04.2007 22:50

Вот SVN всех библиотек под PSPSDK :
http://svn.ps2dev.org/listing.php?re...%2F&rev=0&sc=0
(я забираю TortoiseSVN клиентом)

Mortem 09.04.2007 23:33

блин, у меня ps2dev не грузиццо... ):

wSlava 13.04.2007 01:35

Вложений: 1
В общем, вот предварительно собранный SDK
http://ifolder.ru/1665343
В нем включены библиотеки (все уже откомпайлено и готово к использованию):
- zlib : библиотека сжатия
- libpng: PNG
- jpeg : JPG
- libmad: mp3
- LTE: Game /Window interface engine
- PSPGL : OpenGL

Установка: скопировать в любое место и это будет каталогом SDK, так же можно залить поверх
уже установленного.

так же прилагаю исходники тетриса 1.4 (добавил фон в виде jpeg), где применяются zlib, libpng, jpeg, libmad. Так же в исходниках есть надстройки над этими библиотеками mp3player.c, graphics.cpp (мною доправленный), серьезно облегчающие кодинг.

Mortem 13.04.2007 11:11

Респектище!!!

l3VGV 02.07.2007 21:45

python on PSP. побаловался, прикольно. хотя и бесполезно.
http://fraca7.homeunix.net/trac/wiki

freecod 02.08.2007 21:59

Вот хороший 2D движок действительно бы не помешал...

Mortem 09.08.2007 03:21

freecod
Чем не устраивает MGF?

l3VGV 09.08.2007 08:51

old style(или school?) library есть ещё. буржуи по ней немеряно прутся.
http://oslib.palib.info/samples/

Mortem 15.08.2007 22:40

school


Текущее время: 20:52. Часовой пояс GMT +3.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2025, vBulletin Solutions, Inc. Перевод: zCarot
PSPx Forum - Сообщество фанатов игровых консолей.