PSPx форум

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

pspowner 24.11.2006 14:36

GU на PSP
 
Вложений: 1
Вот, посмотрел доку.

Код:

GU_TRIANGLE_STRIP - Filled triangles-strip (3 vertices for the first primitive, 1 for every following)
Т.е. на 1 полигон - 3 точки, на последующие 1. Попробую переделать.


Да, вот ещё что интересное увидел:

Код:

void sceGuFrontFace  (  int  order  ) 
 
  Set the current face-order (for culling).

This only has effect when culling is enabled (GU_CULL_FACE)

Culling order can be:

GU_CW - Clockwise primitives are not culled
GU_CCW - Counter-clockwise are not culled

Parameters:
 order  - Which order to use

Что это? кто - нить может сказать. Что, как заворачивать примитивы?
Ладно, это сейчас не так важно.
Чайник со СТРИПОМ(cube.zip - для 1.50, кидать в psp/game):

BonifacE 27.11.2006 12:42

Все эти команды аналогичны командам из обычного opengl, любая отрисовка подразумевает что у тебя есть видимые полигоны и невидимые (т.е. те что отрисовываются за видимыми глубже по z буферу) соотвественно enabled (GU_CULL_FACE) включает возможность проверки на отрисовку полигонов, а sceGuFrontFace собственно включает саму проверку на отображение полигонов переднего плана. GU_TRIANGLE_STRIP - соотвественно тоже полностью аналогичен командам opengl. В том примере что ты мне показывал, попробуй заменить GU_TRIANGLE_STRIP (каждый следующий полигон строится по двум предыдущем точкам и одной новой) на GU_TRIANGLES (каждый следующий полигон строится по трем новым точкам)

pspowner 27.11.2006 13:13

Ну немного опоздал ты. Хотя всё равно спс. Вроде въехал.
Двусторонние полигоны я уже просёк как строить, сейчас думаю с чем дальше разбираться...

добавлено через 16 минут
Ага, вот ещё.

Код:

struct Vertex __attribute__((aligned(16))) vertices[4] =
{
    {1, 1, 0xff7f0000,-1,-1,0.0000},
    {1, 1, 0xff7f0000,1,1,0.0000},
    {1, 1, 0xff7f0000,0,0,1},
   
    {1,1, 0xff7f0000, -1,-1,0}
};

Вот вроде нарисовался двусторонний полигон. Крутится так здорово.
Вопрос другой, как я буду, не отрываясь от предыдущего полигона, отрисовывать примитив, например Куб? Или это как в той детской загадке получается: нарисуйти домик, неотрывая ручку от бумаги и не повторяя нарисованных линий?

mushue 27.11.2006 13:45

Простой полигон состоит всего-лишь из трёх вершин.
В твоём примере это треугольник:
{1, 1, 0xff7f0000,-1,-1,0},
{1, 1, 0xff7f0000,1,1,0},
{1, 1, 0xff7f0000,0,0,1},
Чтобы завершить этот полигон и представить его ввиде квадратной плоскости нам нужно добавить обратный треугольник. Тоесть сомкнуть вершины так, что бы из двух полигонов получилась плоскость в виде квадрата.
Последовательность замыкания треугольников значения не имеет.

BonifacE 27.11.2006 13:52

TRIANGLE_STRIP нужен для быстрой отрисовки больших обьемов полигонов, например любой ландшафт можно представить в виде одного стрипа, это сильно экономит видео память так как за место 3 вершин грузиш всего одну. Для мало полигональных моделей это не особо эффективно посему, используется чаще всего просто TRIANGLES. Хотя практически любую модельку можно представить в виде стрипа или набора стрипов (в моделерах есть такая галка).

pspowner 27.11.2006 13:54

Муш, прото что квадрат состоит из двух треугольников - это понятно.
Спрашивал я немонго другое.
Четвёртая точка, в моём случае, делает обратную сторону полигона, если я правильно понял.

Если я добавлю ещё одну точку, то следующий полигон от каких вершин будет строиться?

От последних двух? А если мне надо нарисовать полигон не от этих вершин?
Вот тут и получается что я привязан к последнему нарисованному треугольнику. И если я это не буду учитывать, то на экране будет каша.

И что значит последовательность замыкания? Она всего одна, от последних 2х точек.

Поправьте, если где не прав.

добавлено через 1 минуту
Бони, понятно. Я посмотрю в максе, может есть такая возможность...

mushue 27.11.2006 14:08

Цитата:

Сообщение от pspowner (Сообщение 260707)
Муш, прото что квадрат состоит из двух треугольников - это понятно.
Спрашивал я немонго другое.
Четвёртая точка, в моём случае, делает обратную сторону полигона, если я правильно понял.

Если я добавлю ещё одну точку, то следующий полигон от каких вершин будет строиться?

От последних двух? А если мне надо нарисовать полигон не от этих вершин?
Вот тут и получается что я привязан к последнему нарисованному треугольнику. И если я это не буду учитывать, то на экране будет каша.

И что значит последовательность замыкания? Она всего одна, от последних 2х точек.

Поправьте, если где не прав.

добавлено через 1 минуту
Бони, понятно. Я посмотрю в максе, может есть такая возможность...

Самый простой полигон состоит из 3 вершин. Если ты добавляешь вершину, то ожидать результата можно лишь завершив полигон. Пойми три точки в координатах x,y,z строят тебе твой треугольник. Следующий треугольник соответственно в других координатах. Замыкание - это значит сомкнуть два треугольника хотя бы для того, что бы получить квадратную плоскость.

добавлено через 2 минуты
Возможно в GU можно использовать триангуляцию монотонных полигонов. Это как раз то очем ты говорил "домик не отрывая ручки". Но об этом в GU я не знаю.

pspowner 27.11.2006 16:10

Вложений: 1
Гы, значит кубик нарисовался, всё Ок. НО!
Почемуто некоторые треугольники помаргивают... т.е. Такое ощущение что сквозь них что-то пытается пробиться... Хм...

Посмотрите, если кому не в лом...

BonifacE 27.11.2006 16:25

капитан сорсы с мэйк файлом положи и я гляну...

vAST 27.11.2006 16:27

какое то мерцание

pspowner 27.11.2006 16:33

Вложений: 1
Да собственно это сделано на основе примера из ПСПСДК, только вот в примере всё Ок, а как только я меняю геометрию - всё чёрти как.

pspowner 27.11.2006 18:17

Уффффф.

Фсё... разобрался, кубик рисуется всё без стрипа и без внутренностей - выглядит отлично и не мерцает.

Дело-то было в одной строчке:

sceGuFrontFace(GU_CCW);

С этим уже можно жить...

mushue 27.11.2006 18:52

Цитата:

Сообщение от pspowner (Сообщение 260970)
Уффффф.

Фсё... разобрался, кубик рисуется всё без стрипа и без внутренностей - выглядит отлично и не мерцает.

Дело-то было в одной строчке:

sceGuFrontFace(GU_CCW);

С этим уже можно жить...

Ну слава всевышнему! =)

Очень рад за тебя! Поздравляю. Существенный прорыв!

pspowner 29.11.2006 11:54

Муш не смейся, я ведь только учусь :)

Мысли вслух:
Мне захотелось сделат что-то типа 3д движка. Ну чтобы, например, можнон было ходить вокруг этого кубика, смотреть на него с разных сторон.
Но возникли вопросы, над которыми мне стоит основательно задуматься.

Вот так кубик вращается вокруг своей оси:
Код:

ScePspFVector3 pos = { 0, 0, -2.5f + movez*0.1};
ScePspFVector3 rot = { valx * 0.79f * (GU_PI/180.0f), valy * 0.98f * (GU_PI/180.0f), valz * 1.32f * (GU_PI/180.0f) };
sceGumRotateXYZ(&rot);
sceGumTranslate(&pos);

Как заставить его вращаться вокруг наблюдателя? Вокруг Viewport?
Поскольку я этого никогда не делал, то возникла у меня идея начать смещение кубика по оси х в зависимости от расстояния от него.
Вот как-то так:

Код:

ScePspFVector3 pos = { sin(valy* 0.79f * (GU_PI/180.0f))*(-0.25f+movez*0.1), 0, -2.5f + movez*0.1};
Не знаю, правильно это или нет, но результат есть. Хотя и не совсем такой как ожидалось.

Вобщем, пока в раздумьях я.

К тому же, я наконец-то воткнул в свой компьютер второй гигабайт оперативки и ,О ЧУДО!. Готика 3 стала просто летать - поэтому сейчас часть свободного времени трачу на эту игру. Когда она меня утомит, займусь 3д более плотно.

BonifacE 29.11.2006 12:12

http://www.gamedev.ru/articles/?id=30038 http://www.gamedev.ru/articles/?id=30039
http://pmg.org.ru/nehe/index.html

mushue 29.11.2006 12:36

...

ScePspFMatrix4 projection;
ScePspFMatrix4 view;

Проекция по желанию
gumLoadIdentity(&projection);
gumPerspective(&projection,75.0f,16.0f/9.0f,0.5f,1000.0f);


Вот тут самое интересное:
{
ScePspFVector3 pos = {0,0,-5.0f};

gumLoadIdentity(&view);
gumTranslate(&view,&pos);
}

Вот тут еще интереснее =)
sceGuSetMatrix(GU_PROJECTION,&projection);
sceGuSetMatrix(GU_VIEW,&view);

Надеюсь ты понял о чем я?

Ilsor 21.06.2008 07:53

Вложений: 1
Повторю тут вопрос, который уже задавал, но на который никто не ответил.

Есть PSP Slim с 3.90 M33.

Есть вот эта вот программа:
Код:

#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdlib.h>

#include <pspgu.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);

void dump_threadstatus(void);

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);

 sceGuInit();

 while(!done)
 {
  sceCtrlReadBufferPositive(&pad, 1);
  //pad.Lx
  //pad.Ly
  if (pad.Buttons!=0) break;
 }
 sceGuTerm();
 sceKernelExitGame();
 return(0);
}

Отлично компилируется, но при запуске на PSP вылетает с ошибкой 8002012С - библиотека не найдена. Это как это так может быть-то?

Настройки IDE вот такие (см. рисунок):

Ilsor 21.06.2008 19:16

Ёшкин кот! Оказывается, вся проблема была исключительно в линкере. Поменял порядок задания библиотек в ключах- сделал так:
Код:

-lpspgum
-lpspgu
-lpspdebug
-lpspdisplay
-lpspctrl
-lpspsdk
-lpsplibc
-lpspnet_inet
-lpspnet_apctl
-lpspnet_resolver
-lpsputility
-lpspuser
-lpspge
-lpspkernel

и всё заработало.
Раньше у меня -lpspgum и -lpspgu шли последними. Интересный прикол...

l3VGV 23.06.2008 11:09

прикол знатный однако. не встречал подобного... по идее то без раницы должнобыть...

Ilsor 23.06.2008 20:31

А никто не знает, что в GU представляют собой матрицы GU_VIEW и GU_MODEL? В OpenGL это одна матрица преобразований локальной системы координат и зовётся она GL_MODELVIEW. А как это тут её умудрились разбить на две? Хм...

T.I.P. 23.06.2008 20:47

Цитата:

А как это тут её умудрились разбить на две?
ХЗ

P.S. Раздел начал активно двигаЦЦо!

l3VGV 23.06.2008 21:21

с огл щас тока разбираюсь. но по идее сони от него не могло уйти далеко... может модель это матрица типа установки вида проектирования в огл?

Ilsor 23.06.2008 21:24

И ещё вопрос тогда. Вот простейшее GU-приложение:

Код:

#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 меня местами удивляет неимоверно. :)

Ilsor 23.06.2008 21:27

Вложений: 1
Цитата:

с огл щас тока разбираюсь. но по идее сони от него не могло уйти далеко... может модель это матрица типа установки вида проектирования в огл?
Нет, для проецирования есть специальная матрица. Я могу вам показать мою старую (года 4 ей уже) реализацию софтверного OpenGL (точнее, части - тестуры я так и не сделал - пропал интерес). Не для PSP. Там конвейер матриц можно посмотреть.

l3VGV 23.06.2008 22:03

Ээээ. мастер ты это. мыж тут нубы :)а ты к нам будто мы соневские доки читали и знаем...
видеопамяти на борту 2 метра афайк.

Ilsor 24.06.2008 12:27

Жалко... придётся выяснять опытным путём... Увы, в русском сегменте инета никакой вразумительной информации я не нашёл. А с английским у меня некоторые трудности - я немецкий учил, а английский исключительно "опытным путём". :) Ну ничего, эксперименты покажут, что вся эта тарабарщина из себя представляет. :)

добавлено через 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 19:03

Вложений: 1
Вот что ещё выяснил:
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++;
 }
}

А вот пример приложения-заготовки для пасьянса с двумя спрайтами, причём, второй спрайт (указатель) имеет область прозрачности.

l3VGV 24.06.2008 21:58

А какой смысл в пикселе интресно порядок менять?

Ilsor 24.06.2008 22:09

Хороший вопрос... Наверное, из целей совместимости с OpenGL. А вообще, картинки всякие (TGA и BMP и другие) тоже порядок цветов меняют. Я уже и не помню, зачем им это надо было... Но вообще, это не очень удобно лично мне. :)

добавлено через 1 минуту
Ах да, я сказал несколько неоднозначно:
"Однако, оказывается, что альфа-канал в цвете идёт первым, а вот дальше идут уже b g и r. "

Т.е. раскладка битовая такая: abgr.

А для текстуры или спрайта раскладка: rgba

l3VGV 24.06.2008 22:35

может во время какихто прередач(внутре конвеера или из памяти в гу...) удобно чтобы байты задом наперёд шли...хых. мистика :)
однако ценное наблюдение. спасибо.

Ilsor 25.06.2008 06:15

Да нет, вроде конвейеру-то как раз всё равно... Может, там для прямого вывода загруженных картинок сделано? То есть, читаем, скажем, bmp и тут же выводим простым копированием в видеопамять. Хотя вряд ли. Надо поискать смысл инверсии порядка цветов.

Ilsor 29.06.2008 12:23

Отправил GU текстурку 480x272 по-моему, а по его представлениям 512x512. Ну что можно сказать... либо я что-то сделал не так, либо он с такими размерами не работает. Экран мерцает, по нему идут полосы, хотя на заднем фоне текстуру видно. Увеличивал размер памяти дисплейного списка - не помогло. А с маленькими 64x64 без проблем всё идёт. Наверное, 512 для него слишком жирно...

Ilsor 29.06.2008 13:57

Вложений: 1
А вот GU-приложение "пасьянс косынка". Пока - прототип. То есть, играть можно (аналоговый джойстик и кнопка "крестик"). Это на нём текстуру зелёного сукна вместо 480x272 мне пришлось заменить маленький кусочек. :)

Ilsor 05.07.2008 17:28

Занятно. Попытался вывести несколько раз относительно крупный спрайт (256x64). Опять глюки. Экран мерцает, картинка разваливается. Причём, один спрайт выводится. Два - уже нет. Такое впечатление, что Gu массив данных спрайта зачем-то перекидывает в память списка и заданных 256 кБ не хватает. Но если выделить в 10 раз больше, тоже работать не начинает. Если выводить один спрайт в одном дисплейном списке, а второй во втором, то тоже ничего не выходит, либо я чего-то не так делаю.
Вот сейчас сделал спрайты 128x64 и выделил под список 512 кБ. Пока работает. Интересно, если я ещё спрайтов добавлю, оно продолжит работать... хм..

Ilsor 07.07.2008 20:45

А всё-таки непонятно, как же выглядит адресное пространство 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 мБ - на экране хаос точек. Эх, знать бы архитектуру и принципы управления памятью этого чуда...

l3VGV 07.07.2008 21:26

Даю справку. по адресам:
http://wiki.ps2dev.org/psp:memory_map

Надеюсь это то. на слимке чутка отличается но не критично. чуть пошире куски основной памяти и безкешевой области.

думаю начинать копировать с 0 бесполезно, для неё это ркивой указатель и она сразу его в топку. АФАЙК начинать надо с 64Кб.

Также советую заглянуть в папку с семплами, там был пример как гулять по памяти, делать карту и как дампить всякое разное.

Ilsor 08.07.2008 06:23

Цитата:

думаю начинать копировать с 0 бесполезно, для неё это ркивой указатель и она сразу его в топку. АФАЙК начинать надо с 64Кб.
Однако, для GU этот указатель вполне рабочий. И Совершенно не понятно, почему он в нуле, а следующий за ним тоже затирает совсем не свободную область памяти.

l3VGV 08.07.2008 09:42

Вопрос без официальных доков имхо не отвечаем :) те как факт мы это знаем. а вот почему? ну хз. так уж сделано.

Ilsor 08.07.2008 10:49

А ещё никто у Sony оригинальный SKD не спиратил? :)

l3VGV 08.07.2008 11:20

Пока нет :( по крайней мере в торентах не ищутся.


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

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