Технологии программирования на 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 очень многие и давно просят. И таких полезных программ достаточно много. В общем, кто заинтересуется, исследуйте и отписывайтесь ! |
Вложений: 1
Итак, следующая полезная вещь - XML парсер под PSP под названием TinyXML. Сама библиотечка кросплатформенная, вот общее описание http://www.grinninglizard.com/tinyxmldocs/index.html. Исходники TinyXML под PSP взял из проекта PSPoste (почтовик), можете взять из аттачмента.
|
На 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 |
Продолжаю тему. На 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; Как видите, все очень просто ! |
Начинаю выкладывать занятные статьи с 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; |
Обнаружилось, что максимальный 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 нестабильность сильно меньше. |
основные функции 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); |
еще одна интересная ссылка http://www.psp-programming.com/tutorials/, там можно найти весьма пользительный урок по загрузке и проигрыванию mp3 и основы GU
|
Пасиб за сайт, я подробней покопал, вот это уже то что нужно !!!!!!
http://www.psp-programming.com/code/...id=c:tutorials добавлено через 6 минут Почитал, отлично, все что нужно по GU, по крайней мере для начала. В общем буду переваривать. |
Вот еще библиотеку Oldschool Library for PSP приглядел
http://dl.qj.net/Oldschool-Library-f...5422/catid/202 вот экзамплы: http://oslib.palib.info/samples/ |
Нашел хороший мануал по Makefile:
http://www.eng.hawaii.edu/Tutor/Make/index.html |
Вот SVN всех библиотек под PSPSDK :
http://svn.ps2dev.org/listing.php?re...%2F&rev=0&sc=0 (я забираю TortoiseSVN клиентом) |
блин, у меня ps2dev не грузиццо... ):
|
Вложений: 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 (мною доправленный), серьезно облегчающие кодинг. |
Респектище!!!
|
python on PSP. побаловался, прикольно. хотя и бесполезно.
http://fraca7.homeunix.net/trac/wiki |
Вот хороший 2D движок действительно бы не помешал...
|
freecod
Чем не устраивает MGF? |
old style(или school?) library есть ещё. буржуи по ней немеряно прутся.
http://oslib.palib.info/samples/ |
school
|
Текущее время: 20:52. Часовой пояс GMT +3. |
Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2025, vBulletin Solutions, Inc. Перевод: zCarot
PSPx Forum - Сообщество фанатов игровых консолей.