#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdlib.h>
#include <pspgu.h>
#include <pspgum.h>
#include <math.h>
#ifndef bool
#define bool char
#define true 1
#define false 0
#endif
PSP_MODULE_INFO("SIMPLY GU MODE",0,1,1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
static unsigned int __attribute__((aligned(16))) list[262144];
bool done=false;
int exit_callback(int arg1,int arg2,void *common)
{
done=true;
return(0);
}
int CallbackThread(SceSize args, void *argp)
{
int cbid;
cbid=sceKernelCreateCallback("Exit Callback",exit_callback,NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return(0);
}
int SetupCallbacks(void)
{
int thid = 0;
thid=sceKernelCreateThread("update_thread",CallbackThread,0x11,0xFA0,0,0);
if(thid>=0) sceKernelStartThread(thid, 0, 0);
return(thid);
}
//начинаем программу
int main(void)
{
SceCtrlData pad;
pspDebugScreenInit();
SetupCallbacks();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
sceKernelDcacheWritebackAll();
//---------------------------------------------
//по сути - это немного модифицированный OpenGL
//---------------------------------------------
//инициализируем графику GU
sceGuInit();
//запускаем на выполнение новый контекст дисплея - он должен выполниться сразу, т.к. GU_DIRECT
sceGuStart(GU_DIRECT,list);
//устанавливаем параметры буфера рисования- формат пикселя, указатель на область видеопамяти, длину строки (выровненную, а не физическую)
sceGuDrawBuffer(GU_PSM_8888,(void*)0,512);
//устанавливаем параметры буфера экрана - размер экрана, указатель на видеопамять, длину строки
sceGuDispBuffer(480,272,(void*)0x88000,512);
//устанавливаем параметры буфера глубины- указатель на начало буфера глубины в видеопамяти и длину строки
sceGuDepthBuffer((void*)0x110000,512);
//устанавливаем смещение экрана в общем пространстве 4096x4096 (в PSP такой размер виртуального экрана, судя по всему)
sceGuOffset(2048-(480/2),2048-(272/2));//ставим по центру
//настраиваем видовой порт - порт просмотра- координаты центра и размеры сторон
sceGuViewport(2048,2048,480,272);
//устанавливаем диапазон значений для буфера глубины - передняя и задняя плоскости отсечения (буфер инвертирован и значения от 0 до 65535 !)
sceGuDepthRange(65535,0);
//включаем обрезание области показа по размерам видового порта
sceGuScissor(0,0,480,272);
sceGuEnable(GU_SCISSOR_TEST);
//настроим матрицу проецирования
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(90.0f,16.0/9.0f,0.1f,100.0f);
//включим тест глубины
sceGuDepthFunc(GU_GEQUAL);
sceGuEnable(GU_DEPTH_TEST);
//включим режим гладкой интерполяции цвета граней
sceGuShadeModel(GU_SMOOTH);
//включим режим отсечения граней, повёрнутых обратной стороной к наблюдателю
sceGuFrontFace(GU_CW);
sceGuDisable(GU_CULL_FACE);
//очистим экран и буфер глубины
sceGuClearColor(0x00000000);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
//инициализируем матрицы
sceGumMatrixMode(GU_VIEW);
sceGumLoadIdentity();
sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();
//теперь можно рисовать
ScePspFVector3 ScePspFVector3_Working;
ScePspFVector3_Working.x=0;
ScePspFVector3_Working.y=0;
ScePspFVector3_Working.z=-10;
sceGumTranslate(&ScePspFVector3_Working);
//выбираем цвет
sceGuColor(0xffffffff);
//распределяем память в текущем дисплейном списке
//как только список выполнится, память освободится
//нельзя создавать массив вершин в обычной памяти, только в памяти списка или как глобальный массив!
//Иначе ничего изображено не будет.
float __attribute__((aligned(16))) *vertex=(float*)sceGuGetMemory(9*sizeof(float));
//треугольник задан в пространстве
vertex[0]=5;//x
vertex[1]=0;//y
vertex[2]=0;//z
vertex[3]=0;//x
vertex[4]=0;//y
vertex[5]=0;//z
vertex[6]=0;//x
vertex[7]=5;//y
vertex[8]=0;//z
//рисуем
sceGumDrawArray(GU_TRIANGLES,GU_VERTEX_32BITF|GU_TRANSFORM_3D,3,0,vertex);
//а вот так вот можно рисовать с координатами уже спроецированными на плоскость экрана
//выбираем цвет
sceGuColor(0xff00ffff);
vertex[0]=0;//x
vertex[1]=0;//y
vertex[2]=0;//z
vertex[3]=160;//x
vertex[4]=0;//y
vertex[5]=0;//z
vertex[6]=0;//x
vertex[7]=120;//y
vertex[8]=0;//z
//рисуем
sceGumDrawArray(GU_TRIANGLES,GU_VERTEX_32BITF|GU_TRANSFORM_2D,3,0,vertex);
//и выводим изображение
sceGuFinish();
//ждём, пока дисплейный список (у нас - контекст дисплея) не выполнится
sceGuSync(0,GU_SYNC_DONE);
//включаем дисплей
sceGuDisplay(GU_TRUE);
//делаем видимым буфер, в котором мы рисовали
sceGuSwapBuffers();
//ждём нажатия любой клавиши
while(!done)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons!=0) break;
}
sceGuTerm();
sceKernelExitGame();
return(0);
}
Вопросы такие:
1) Как я понял, работает GU всегда на основе дисплейных списков (как в OpenGL). И для списка нужно явно указывать доступный объём памяти да ещё и с выравниванием по параграфу. Почему-то все задают размер 262144 - это почему так? И вообще, сколько на борту видеопамяти?
2) Почему буфер глубины 16-ти битный? Точность же пострадает...
3) Какой смысл в виртуальном экране 4096x4096, если отображать можно 480x272 максимум и при этом переключать страницы sceGuSwapBuffers(). Зачем же тогда такой экран? Хм... Какой в нём смысл? Единственно, реализовывать полноэкранное сглаживание можно используя полный 4096x4096, но примимо ли это на PSP?
4) Нулевой байт цвета - это альфа-канал?
5) Почему примитивы можно создавать либо глобально в программе, либо распределяя память дисплейного списка командой float __attribute__((aligned(16))) *vertex=(float*)sceGuGetMemory(9*sizeof(float)), но нельзя выделить память типа float vertex[9]. У меня последний вариант не работает никак.
6) Зачем придумано обрезание порта просмотра командами
sceGuScissor(0,0,480,272);
sceGuEnable(GU_SCISSOR_TEST);
7) Для чего нужна команда sceGuDisplay(GU_TRUE); Не понимаю логики. Зачем включать то, что уже включено? Хм...
Вот такие вот пироги... я хорошо знаком с OpenGL, но вот GU меня местами удивляет неимоверно.
с огл щас тока разбираюсь. но по идее сони от него не могло уйти далеко... может модель это матрица типа установки вида проектирования в огл?
Нет, для проецирования есть специальная матрица. Я могу вам показать мою старую (года 4 ей уже) реализацию софтверного OpenGL (точнее, части - тестуры я так и не сделал - пропал интерес). Не для PSP. Там конвейер матриц можно посмотреть.
Жалко... придётся выяснять опытным путём... Увы, в русском сегменте инета никакой вразумительной информации я не нашёл. А с английским у меня некоторые трудности - я немецкий учил, а английский исключительно "опытным путём". Ну ничего, эксперименты покажут, что вся эта тарабарщина из себя представляет.
добавлено через 4 часа 17 минут
1) Однако, оказывается, что альфа-канал в цвете идёт первым, а вот дальше идут уже b g и r.
2) Инициализацию локальных и глобальных массивов вершин примитивов можно делать только до sceGuInit. После sceGuInit инициализацию можно делать только через выделенный дисплею блок памяти, через sceGuGetMemory.
3) Чтобы каждую точку примитива раскрасить в свой цвет или чтобы назначить ей точку текстуры,нормали и т.д. нужно объединять флаги команды sceGumDrawArray, например, sceGumDrawArray(GU_TRIANGLES,GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,3,0, sVertex);
Ну а с остальным пока экспериментирую...
Последний раз редактировалось Ilsor; 24.06.2008 в 12:27.
Причина: добавил, подумав
Вот что ещё выяснил:
1) При задании текстур данные идут как RGBA (т.е. порядок не такой, как при задании цвета! в sceGuColor)
2) Если синхронизацию по sceDisplayWaitVblankStart() ставить после sceGuSwapBuffers(), то вверху экрана будет полоса, где вывод производиться не будет - отстаём от развёртки?
3) Ширина и высота текстуры должны быть степенью 2 и ширина должна быть выровнена по параграфу (16 байт).
Вот код моей библиотеки для работы со спрайтами с использованием GU:
#ifndef CSPRITE_H_INCLUDED
#define CSPRITE_H_INCLUDED
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <psprtc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pspgu.h>
#include <pspgum.h>
#ifndef bool
#define bool char
#define true 1
#define false 0
#endif
//спрайт
struct SGuSprite
{
int Width;//ширина
int Height;//высота
int WidthImage;//ширина картинки
int HeightImage;//высота картинки
unsigned char *Data;//указатель на данные спрайта
};
//загрузить спрайт
bool GuSprite_LoadSprite(char *FileName,struct SGuSprite *sGuSprite,unsigned char alpha);
//отобразить спрайт
void GuSprite_PutSprite(int x,int y,struct SGuSprite *sGuSprite);
//удалить спрайт
void GuSprite_DeleteSprite(struct SGuSprite *sGuSprite);
//выставить спрайту для цвета (r,g,b) значение alpha
void GuSprite_ReplaceAlpha(unsigned char alpha,unsigned char r,unsigned char g,unsigned char b,struct SGuSprite *sGuSprite);
#endif // CSPRITE_H_INCLUDED
//-------------------------------------------------------------------------
#include "gusprite.h"
struct SGuVertex
{
float U;
float V;
unsigned int Color;
float X;
float Y;
float Z;
};
//заголовок TGA-файла
#pragma pack(1)
struct TGAHEADER
{
char identsize;//размер поля ID заголовка (0)
char colorMapType;//если ли палитра:0-нет,1-есть
char imageType;//тип картинки:0-нет,1-индексные цвета,2-RGB,3-оттенки серого, (3-й бит - RLE-кодирование)
unsigned short colorMapStart;//начало карты цветов
unsigned short colorMapLength;//количество цветов в карте
unsigned char colorMapBits;//размерность палитры
unsigned short xstart;//начальные координаты изображения
unsigned short ystart;
unsigned short width;//размер изображения по X
unsigned short height;//размер изображения по Y
char bits;//количесто бит на пиксель (8,16,24,32)
char de******or;//дескриптор изрображения
};
#pragma pack(8)
//загрузить спрайт (формат - TGA)
bool GuSprite_LoadSprite(char *FileName,struct SGuSprite *sGuSprite,unsigned char alpha)
{
//задаём размеры по-умолчанию
sGuSprite->Data=NULL;
sGuSprite->Width=0;
sGuSprite->Height=0;
//пробуем считать изображение
struct TGAHEADER tgaHeader;
SceUID SceUID_File;
SceUID_File=sceIoOpen(FileName,PSP_O_RDONLY,0777);//открываем файл
if (SceUID_File<0) return(false);//ошибка
//читаем заголовок
if (sceIoRead(SceUID_File,&tgaHeader,sizeof(struct TGAHEADER))<sizeof(struct TGAHEADER))//ошибка - мало данных
{
sceIoClose(SceUID_File);
return(false);
}
//проверяем на возможность чтения
if (tgaHeader.imageType&8)
{
sceIoClose(SceUID_File);
return(false);//RLE не поддерживаем
}
if ((tgaHeader.imageType&7)==0 || (tgaHeader.imageType&7)==3)
{
sceIoClose(SceUID_File);
return(false);//градации серого и отсутствие изображения не поддерживаем
}
//задаём параметры изображения
sGuSprite->Width=tgaHeader.width;
sGuSprite->Height=tgaHeader.height;
//определяем размер изображения, являющегося степенью двойки с широной, кратной 4-м байтам
sGuSprite->WidthImage=1;
sGuSprite->HeightImage=1;
while(sGuSprite->WidthImage<sGuSprite->Width || sGuSprite->WidthImage%4!=0) sGuSprite->WidthImage*=2;
while(sGuSprite->HeightImage<sGuSprite->Height) sGuSprite->HeightImage*=2;
//выделяем память для изображения
int image_length=tgaHeader.width*tgaHeader.height*tgaHeader.bits/8;
unsigned char *i_buffer=(unsigned char*)malloc(image_length);
//считываем изображение
sceIoLseek(SceUID_File,sizeof(struct TGAHEADER)+tgaHeader.colorMapStart+tgaHeader.colorMapLength*tgaHeader.colorMapBits/8,SEEK_SET);
if(sceIoRead(SceUID_File,i_buffer,image_length)<image_length)
{
sceIoClose(SceUID_File);
free(i_buffer);
return(false);
}
//а теперь анализируем формат
if (tgaHeader.bits==24)//BGR - модицифируем для четвёрок байт
{
sceIoClose(SceUID_File);
unsigned char *out_image=(unsigned char*)malloc(sGuSprite->WidthImage*sGuSprite->HeightImage*4);
int y,x;
if (tgaHeader.de******or==32)//прямой формат
{
unsigned char *oi_ptr=out_image;
unsigned char *i_ptr=i_buffer;
for(y=0;y<tgaHeader.height;y++,i_ptr+=tgaHeader.width*3,oi_ptr+=sGuSprite->WidthImage*4)
{
unsigned char *i_ptrc=i_ptr;
unsigned char *oi_ptrc=oi_ptr;
for(x=0;x<tgaHeader.width;x++)
{
unsigned char b=*(i_ptrc);i_ptrc++;
unsigned char g=*(i_ptrc);i_ptrc++;
unsigned char r=*(i_ptrc);i_ptrc++;
unsigned char a=alpha;
*oi_ptrc=r;oi_ptrc++;
*oi_ptrc=g;oi_ptrc++;
*oi_ptrc=b;oi_ptrc++;
*oi_ptrc=a;oi_ptrc++;
}
}
}
if (tgaHeader.de******or==8)//обратный формат
{
unsigned char *oi_ptr=out_image;
unsigned char *i_ptr=i_buffer+tgaHeader.width*tgaHeader.height*3-1;
for(y=tgaHeader.height-1;y>=0;y--,i_ptr-=tgaHeader.width*3,oi_ptr+=sGuSprite->WidthImage*4)
{
unsigned char *i_ptrc=i_ptr;
unsigned char *oi_ptrc=oi_ptr;
for(x=0;x<tgaHeader.width;x++)
{
unsigned char b=*(i_ptrc);i_ptrc++;
unsigned char g=*(i_ptrc);i_ptrc++;
unsigned char r=*(i_ptrc);i_ptrc++;
unsigned char a=alpha;
*oi_ptrc=r;oi_ptrc++;
*oi_ptrc=g;oi_ptrc++;
*oi_ptrc=b;oi_ptrc++;
*oi_ptrc=a;oi_ptrc++;
}
}
}
free(i_buffer);
sGuSprite->Data=out_image;
return(true);
}
if (tgaHeader.colorMapType==1 && tgaHeader.colorMapBits/8==3)//есть палитра по 24 бита
{
sceIoLseek(SceUID_File,tgaHeader.colorMapStart+sizeof(struct TGAHEADER),SEEK_SET);
//читаем палитру
unsigned char *color_map=(unsigned char*)malloc(tgaHeader.colorMapLength*3);
if (sceIoRead(SceUID_File,color_map,tgaHeader.colorMapLength*3)<tgaHeader.colorMapLength*3)
{
sceIoClose(SceUID_File);
free(color_map);
free(i_buffer);
return(false);
}
//нам потребуется изменить формат
unsigned char *out_image=(unsigned char*)malloc(sGuSprite->WidthImage*sGuSprite->HeightImage*4);
int y,x;
if (tgaHeader.de******or==32)//прямой формат
{
unsigned char *oi_ptr=out_image;
unsigned char *i_ptr=i_buffer;
for(y=0;y<tgaHeader.height;y++,i_ptr+=tgaHeader.width,oi_ptr+=sGuSprite->WidthImage*4)
{
unsigned char *i_ptrc=i_ptr;
unsigned char *oi_ptrc=oi_ptr;
for(x=0;x<tgaHeader.width;x++,i_ptrc++)
{
int index=(*i_ptrc)*3;
unsigned char b=color_map[index];
unsigned char g=color_map[index+1];
unsigned char r=color_map[index+2];
unsigned char a=alpha;
*oi_ptrc=r;oi_ptrc++;
*oi_ptrc=g;oi_ptrc++;
*oi_ptrc=b;oi_ptrc++;
*oi_ptrc=a;oi_ptrc++;
}
}
}
if (tgaHeader.de******or==8)//формат перевёрнутый
{
unsigned char *oi_ptr=out_image;
unsigned char *i_ptr=i_buffer+tgaHeader.width*(tgaHeader.height-1);
for(y=tgaHeader.height-1;y>=0;y--,i_ptr-=tgaHeader.width,oi_ptr+=sGuSprite->WidthImage*4)
{
unsigned char *i_ptrc=i_ptr;
unsigned char *oi_ptrc=oi_ptr;
for(x=0;x<tgaHeader.width;x++,i_ptrc++)
{
int index=(*i_ptrc)*3;
unsigned char b=color_map[index];
unsigned char g=color_map[index+1];
unsigned char r=color_map[index+2];
unsigned char a=alpha;
*oi_ptrc=r;oi_ptrc++;
*oi_ptrc=g;oi_ptrc++;
*oi_ptrc=b;oi_ptrc++;
*oi_ptrc=a;oi_ptrc++;
}
}
}
free(i_buffer);
free(color_map);
sGuSprite->Data=out_image;
sceIoClose(SceUID_File);
return(true);
}
//иные режимы не поддерживаем
sceIoClose(SceUID_File);
free(i_buffer);
return(false);
}
//отобразить спрайт
void GuSprite_PutSprite(int x,int y,struct SGuSprite *sGuSprite)
{
if (sGuSprite->Data==NULL || sGuSprite->Width==0 || sGuSprite->Height==0) return;//спрайт отсутствует
sceGuTexMode(GU_PSM_8888,0,0,0);
sceGuTexImage(0,sGuSprite->WidthImage,sGuSprite->HeightImage,sGuSprite->WidthImage,sGuSprite->Data);
sceGuTexFunc(GU_TFX_MODULATE,GU_TCC_RGBA);
sceGuTexFilter(GU_NEAREST,GU_NEAREST);
sceGuTexWrap(GU_CLAMP,GU_CLAMP);
sceGuTexScale(1,1);
sceGuTexOffset(0,0);
struct SGuVertex *sGuVertex;
sGuVertex=sceGuGetMemory(2*sizeof(struct SGuVertex));
sGuVertex[0].X=x;
sGuVertex[0].Y=y;
sGuVertex[0].Z=0;
sGuVertex[0].Color=0xffffffff;
sGuVertex[0].U=0;
sGuVertex[0].V=0;
sGuVertex[1].X=x+sGuSprite->Width;
sGuVertex[1].Y=y+sGuSprite->Height;
sGuVertex[1].Z=0;
sGuVertex[1].Color=0xffffffff;
sGuVertex[1].U=sGuSprite->Width;
sGuVertex[1].V=sGuSprite->Height;
sceGumDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,sGuVertex);
}
//удалить спрайт
void GuSprite_DeleteSprite(struct SGuSprite *sGuSprite)
{
if (sGuSprite->Data==NULL || sGuSprite->Width==0 || sGuSprite->Height==0) return;//спрайт отсутствует
free(sGuSprite->Data);
sGuSprite->Data=NULL;
sGuSprite->Width=0;
sGuSprite->Height=0;
}
//выставить спрайту для цвета (r,g,b) значение alpha
void GuSprite_ReplaceAlpha(unsigned char alpha,unsigned char r,unsigned char g,unsigned char b,struct SGuSprite *sGuSprite)
{
if (sGuSprite->Data==NULL || sGuSprite->Width==0 || sGuSprite->Height==0) return;//спрайт отсутствует
unsigned char *ptr=sGuSprite->Data;
int n;
int length=sGuSprite->WidthImage*sGuSprite->HeightImage;
for(n=0;n<length;n++)
{
unsigned char ri=*ptr;ptr++;
unsigned char gi=*ptr;ptr++;
unsigned char bi=*ptr;ptr++;
if (ri==r && gi==g && bi==b) *ptr=alpha;
ptr++;
}
}
А вот пример приложения-заготовки для пасьянса с двумя спрайтами, причём, второй спрайт (указатель) имеет область прозрачности.
Последний раз редактировалось Ilsor; 24.06.2008 в 19:07.
Хороший вопрос... Наверное, из целей совместимости с OpenGL. А вообще, картинки всякие (TGA и BMP и другие) тоже порядок цветов меняют. Я уже и не помню, зачем им это надо было... Но вообще, это не очень удобно лично мне.
добавлено через 1 минуту
Ах да, я сказал несколько неоднозначно:
"Однако, оказывается, что альфа-канал в цвете идёт первым, а вот дальше идут уже b g и r. "
Т.е. раскладка битовая такая: abgr.
А для текстуры или спрайта раскладка: rgba
Последний раз редактировалось Ilsor; 24.06.2008 в 22:09.
Причина: добавил, подумав
Другие консоли: PS3(CECHC 60Gb), DS lite, x360(20Gb/120Gb)
Регистрация: 11.05.2007
Возраст: 43
Сообщений: 2,509
Вы сказали Спасибо: 337
Поблагодарили 988 раз(а) в 579 сообщениях
Сила репутации: 1
Репутация: 948 
(это имя известно всем)
может во время какихто прередач(внутре конвеера или из памяти в гу...) удобно чтобы байты задом наперёд шли...хых. мистика
однако ценное наблюдение. спасибо.
Да нет, вроде конвейеру-то как раз всё равно... Может, там для прямого вывода загруженных картинок сделано? То есть, читаем, скажем, bmp и тут же выводим простым копированием в видеопамять. Хотя вряд ли. Надо поискать смысл инверсии порядка цветов.
Отправил GU текстурку 480x272 по-моему, а по его представлениям 512x512. Ну что можно сказать... либо я что-то сделал не так, либо он с такими размерами не работает. Экран мерцает, по нему идут полосы, хотя на заднем фоне текстуру видно. Увеличивал размер памяти дисплейного списка - не помогло. А с маленькими 64x64 без проблем всё идёт. Наверное, 512 для него слишком жирно...
А вот GU-приложение "пасьянс косынка". Пока - прототип. То есть, играть можно (аналоговый джойстик и кнопка "крестик"). Это на нём текстуру зелёного сукна вместо 480x272 мне пришлось заменить маленький кусочек.
Занятно. Попытался вывести несколько раз относительно крупный спрайт (256x64). Опять глюки. Экран мерцает, картинка разваливается. Причём, один спрайт выводится. Два - уже нет. Такое впечатление, что Gu массив данных спрайта зачем-то перекидывает в память списка и заданных 256 кБ не хватает. Но если выделить в 10 раз больше, тоже работать не начинает. Если выводить один спрайт в одном дисплейном списке, а второй во втором, то тоже ничего не выходит, либо я чего-то не так делаю.
Вот сейчас сделал спрайты 128x64 и выделил под список 512 кБ. Пока работает. Интересно, если я ещё спрайтов добавлю, оно продолжит работать... хм..
А всё-таки непонятно, как же выглядит адресное пространство PSP. Я попытался снять скриншот в моём пасьянсе копированием области, заданной GU как видеобуфер (т.е. начинающейся с 0 (!) - обычно-то для графических приложений не для GU задавался адрес 64 мБ)
<...>
static unsigned int staticOffset=0;
static unsigned int getMemorySize(unsigned int width,unsigned int height,unsigned int psm)
{
switch (psm)
{
case GU_PSM_T4: return((width*height)>>1);
case GU_PSM_T8: return(width*height);
case GU_PSM_5650:
case GU_PSM_5551:
case GU_PSM_4444:
case GU_PSM_T16: return(2*width*height);
case GU_PSM_8888:
case GU_PSM_T32: return(4*width*height);
default: return(0);
}
}
void* getStaticVramBuffer(unsigned int width,unsigned int height,unsigned int psm)
{
unsigned int memSize=getMemorySize(width,height,psm);
void* result=(void*)staticOffset;
staticOffset+=memSize;
return(result);
}
void* getStaticVramTexture(unsigned int width,unsigned int height,unsigned int psm)
{
void* result=getStaticVramBuffer(width,height,psm);
return((void*)(((unsigned int)result) + ((unsigned int)sceGeEdramGetAddr())));
}
<...>
void* fbp0=getStaticVramBuffer(512,272,GU_PSM_8888);
void* fbp1=getStaticVramBuffer(512,272,GU_PSM_8888);
void* zbp=getStaticVramBuffer(512,272,GU_PSM_4444);
//инициализируем графику GU
sceGuInit();
//запускаем на выполнение новый контекст дисплея - он должен выполниться сразу, т.к. GU_DIRECT
sceGuStart(GU_DIRECT,list);
//устанавливаем параметры буфера рисования- формат пикселя, указатель на область видеопамяти, длину строки (выровненную, а не физическую)
sceGuDrawBuffer(GU_PSM_8888,fbp0,512);
//устанавливаем параметры буфера экрана - размер экрана, указатель на видеопамять, длину строки
sceGuDispBuffer(480,272,fbp1,512);
//устанавливаем параметры буфера глубины- указатель на начало буфера глубины в видеопамяти и длину строки
sceGuDepthBuffer(zbp,512);
и ничего не вышло. Точнее, я выделил память через malloc и туда сделал memcpy с адреса fbp0 (и с fbp1 тоже пробовал). Приставка вырубается и перезагружается. Но ведь когда я работал с видео через прямое обращение к видеопамяти, то самое в 64 мБ, то всё работало отлично. Не понимаю я, где же реально расположена видеопамять и как так получается, что я могу указать видеопамять на каких-то адресах, где по какой-то случайности не попадает кусок моей программы? Я пытался GU дать адрес равный 64 мБ - на экране хаос точек. Эх, знать бы архитектуру и принципы управления памятью этого чуда...
думаю начинать копировать с 0 бесполезно, для неё это ркивой указатель и она сразу его в топку. АФАЙК начинать надо с 64Кб.
Однако, для GU этот указатель вполне рабочий. И Совершенно не понятно, почему он в нуле, а следующий за ним тоже затирает совсем не свободную область памяти.