I use only very little lib pvr, the code is a new version or a modified version of the code of the lib pvr.
The lib can load a 3D model, read a .tar file (equivalent to a .zip without compression), pcx, png and bmp.
Currently it can display 18-19 k triangles per frame.
It can display 26k triangles per frame, if I do a double-buffer for vertex (The rendering on Dreamcast is done in 'parrallle' so it takes a double buffer to avoid data collisions), nevertheless it takes a lot of VRAM, and it's unlikely that you will display as many 3D model without code for the game.
So the best I think is to make a 30 fps version if you want to display the 26 k triangles by frames, (and that avoids me to have a double vertex buffer) and it also allows to have the animation by skeleton with 26k triangles ^^
For the speed of display, I think I managed to be close to the limit, currently according to my test I have 45 cycles for vertex calculations and 55 cycles for the index(so triangle) and 20 cycles for the transfer.
I tested on my console (with an SD card) :
LXDREAM:
An example code (but not finished, I have to hide even more its internal functioning):
Code: Select all
int __attribute__((optimize("-O0"), noinline)) main2()
{
LMP3D_TAR tar;
LMP3D_Model *model;
LMP3D_Tar(&tar,NULL,"zack.bcm",LMP3D_TAR_OFFSET,DATA_ROM,size_DATA_ROM);
model = LMP3D_Load_Model(NULL,tar.offset,DATA_ROM,tar.size);
LMP3D_Tar(&tar,NULL,"font.png",LMP3D_TAR_OFFSET,DATA_ROM,size_DATA_ROM);
LMP3D_Texture* texture,*texture2;
texture = LMP3D_Load_Texture(NULL,tar.offset,DATA_ROM,tar.size);
LMP3D_Texture_Convert(texture,LMP3D_FORMAT_BGRA1555);
//Upload VRAM
texture->address = 0x3D0000;
LMP3D_Texture_Upload_VRAM(texture);
LMP3D_Texture_Free_Pixel(texture);
//----------
LMP3D_Tar(&tar,NULL,"ffccdif_1.png",LMP3D_TAR_OFFSET,DATA_ROM,size_DATA_ROM);
texture2 = LMP3D_Load_Texture(NULL,tar.offset,DATA_ROM,tar.size);
LMP3D_Texture_Convert(texture2,LMP3D_FORMAT_BGRA1555);
//convertTwiddle(texture);
texture2->address = 0x400000;
LMP3D_Texture_Upload_VRAM(texture2);
LMP3D_Texture_Free_Pixel(texture2);
model->position.z = 400;
model->position.y = 100;
model->rotate.x = PI/2;
char strinfo[100],strfps[50];
int tmpx,i,tmpy;
int number = 1;
int vblank = 0;
LMP3D_Event event;
while(1)
{
LMP3D_Event_Update(&event);
if(event.key[Button_Up] == LMP3D_KEY_DOWNW) model->position.z += 8;
if(event.key[Button_Down] == LMP3D_KEY_DOWNW) model->position.z -= 8;
if(event.key[Button_R1] == LMP3D_KEY_DOWN) number++;
if(event.key[Button_L1] == LMP3D_KEY_DOWN) number--;
if(event.key[Button_A] == LMP3D_KEY_DOWN) typetest++;
typetest &=3;
model->rotate.y += 0.04f;
DC_InitB(texture2->address);
for(i = 0;i < number;i++)
{
tmpx = (i&0x7)<<5;
tmpy = (i&0xF8)<<4;
model->position.x = tmpx;
model->position.y = tmpy+100;
Draw_Model(model);
}
DC_Finish();
DC_Init_Sprite(texture2->address);
DC_DrawSprite(16,64);
DC_Init_Sprite(texture->address);
Draw_Text(16,16,strinfo);
DC_Finish();
sprintf(strinfo,"Vblank :%d\nnumber %d\nTri %d ,VRAM : %x ,type %d\n",vblank,number,model->nf*number,pvr_offset,typetest);
vblank = LMP3D_VBlank();
LMP3D_FlipBuffer(NULL);
LMP3D_VBlank();
}
return 0;
}
Normally this should look like this(PC/PS2):
Code: Select all
void game(LMP3D_Buffer *buffer)
{
LMP3D_TAR tar;
LMP3D_Event event;
LMP3D_Camera camera;
camera = LMP3D_Camera_Init();
LMP3D_Event_Init(&event);
LMP3D_Model *model;
LMP3D_Tar(&tar,"DATA","zack.bcm",LMP3D_TAR_OFFSET,NULL,0);
model = LMP3D_Load_Model("DATA",tar.offset,NULL,0);
LMP3D_Tar(&tar,"DATA","font.png",LMP3D_TAR_OFFSET,NULL,0);
LMP3D_Texture *texture = LMP3D_Load_Texture("DATA",tar.offset,NULL,tar.size);
LMP3D_Texture_Upload(texture);
LMP3D_Texture_Free_Pixel(texture);
char string[100],strfps[50];
int vblank = 0;
int t_end,t_begin,fps = 0,total=0;
Vector3 p;
p.x = 0;
p.y = 0;
p.z = 0;
int i,number = 1,tmpx,tmpy;
while(event.exit == 0)
{
model->rotate.y += 0.01;
LMP3D_Event_Update(&event);
//camera
LMP3D_Camera_Perspective(camera);
LMP3D_Clear();
if(event.key[Button_Up] == LMP3D_KEY_DOWNW) p.z += 8;
if(event.key[Button_Down] == LMP3D_KEY_DOWNW) p.z -= 8;
if(event.key[Button_R1] == LMP3D_KEY_DOWN) number++;
if(event.key[Button_L1] == LMP3D_KEY_DOWN) number--;
if(event.key[Button_R2] == LMP3D_KEY_DOWN) number +=10;
if(event.key[Button_L2] == LMP3D_KEY_DOWN) number -=10;
if(event.key[Button_Start] == LMP3D_KEY_DOWN) model->test = 0;
LMP3D_Texture_Setup(model->texture[0]);
for(i = 0;i < number;i++)
{
tmpx = (i%20)*30;
//tmpy = (i/30)*140;
tmpy = 0;
model->position.x = tmpx-0;
model->position.y = 100-tmpy;
model->position.z = 400+p.z;
model->scale.x = 1;
LMP3D_Model_Draw(model);
}
LMP3D_Camera_Ortho2D();
LMP3D_Texture_Setup(texture);
sprintf(string,"Time %s\nVblank :%d\nnumber %d\nTri %d\nperf %d\n",strfps,vblank,number,model->nf*number,model->test);
bitmap_font2(string,8,8);
t_end = clock();
if(fps >= 60)
{
total += t_end-t_begin;
sprintf(strfps,"%d/%d",total,CLOCKS_PER_SEC/60);
total = 0;
fps = 0;
}
fps++;
LMP3D_FlipBuffer(buffer);
vblank = LMP3D_VBlank();
t_begin = clock();
}
}
So you have 4.3MB for VRAM (Texture) , I think I will do 4 functions for 2D (optimized so, the Dreamcast can display Quad quickly):
-Sprite
-Sprite_Array
-Text
-TileMap
The code works on Windows, Linux, PS1 / PS2.
For each platform I manage the appropriate conversions floating / fixed number, a small idea of what format is optimized for each platform:
PC: floating point number, index
PS1: fixed number, no index
PS2: fixed number, index + submesh
DC: floating point number, index
I create a converter (internal) that converts the images into the appropriate format, here are the recommended formats:
PS1, PS2: PCX
DC: PNG or VQ compressed (not done yet)
PC: PNG
(if someone wants to create a specific dreamcast .vq format I'll thank him a lot ).
For 3D format, I use my own format, a converter exists here : https://github.com/Kannagi/BCMConvert
The source code : https://github.com/Kannagi/LMP3D
And here's a video of a demo of my lib:
https://www.youtube.com/watch?v=AEwg1k-KOf4
Thanks for reading me !