Sega Saturn Development > General Jo Engine Help

Usage of GFS_NwFread (you probably expected this...)

<< < (6/6)

ponut64:
Here, this is the loading structure.
*30 FPS, by the way. My calculation of roughly 240 bytes per frame must have been at 60 FPS. It is important to know this is an extrapolation based on CDDA quality. ... it's probably wrong.


--- Code: ---
void load_test()
{

//Hesitant to add code here...
if(accelState > 0){
load_this++;
}
 jo_printf(20, 0, "(%i)", load_this);
if(load_this < 1){
//This mesh is 216 quads
currentAddress = ztFileRequest("BIN",(Sint8*)"BPONY.ZTP", currentAddress, &entities[0], 0);
}
//Left turn steps
if(load_this > 60 && load_this < 119){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN01.ZTP", currentAddress, &entities[11], 1);
}
if(load_this > 120 && load_this < 179){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN02.ZTP", currentAddress, &entities[12], 2);
}
if(load_this > 180 && load_this < 239){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN03.ZTP", currentAddress, &entities[13], 3);
}
if(load_this > 240 && load_this < 379){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN04.ZTP", currentAddress, &entities[14], 4);
}
if(load_this > 380 && load_this < 479){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN05.ZTP", currentAddress, &entities[15], 5);
}
if(load_this > 540 && load_this < 599){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN06.ZTP", currentAddress, &entities[16], 6);
}
if(load_this > 660 && load_this < 729){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN07.ZTP", currentAddress, &entities[17], 7);
}
if(load_this > 780 && load_this < 839){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN08.ZTP", currentAddress, &entities[18], 8);
}
if(load_this > 900 && load_this < 959){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN09.ZTP", currentAddress, &entities[19], 9);
}
if(load_this > 999 && load_this < 1100){
currentAddress = ztFileRequest("LTURN", (Sint8*)"LTURN10.ZTP", currentAddress, &entities[20], 10);
}

}

--- End code ---

Very simple. In a given range of numbers, the model loading code is active. I don't really need to do it that way, but I do.

This is the file request function.


--- Code: ---
void * ztFileRequest(char * dirname, Sint8 * name, void * startAddress, entity_t * model, Uint16 rqNum)
{
FilRqNm = rqNum;
if(requests[FilRqNm].file_done == true){
process_requested = false;
jo_printf(0, 0, "(-ended-)");
goto SKIP;
}
if(process_requested == false){
rd_frames = 0;
curRdFrame = 0;
ztCDsetRoot();
}
ztCDsetDir(dirname);
requests[FilRqNm].filename = GFS_NameToId(name);
requests[FilRqNm].dstAddress = startAddress;
requests[FilRqNm].tmodel = model;
process_requested = true;
jo_printf(0, 0, "(started)");
SKIP:
return requests[FilRqNm].dstAddress;
}
--- End code ---

And this explains why the model is sometimes not visible. This was my animation system for the old ZTPs using a unique mesh for each frame.


--- Code: ---
void anim_entity_state(Uint16 start, Uint8 length, Sint8 sync, Bool loop, Bool reverse)
{
if(loop == true && reverse == false){
if(anim_target < length && sync > 0){
anim_target++;
}
if(anim_target == length){
anim_target -= length;
}
display_ztp(&entities[start+anim_target]);
}

if(loop == true && reverse == true){
if(anim_target < length && sync > 0){
anim_target++;
}
if(anim_target == length){
anim_target -= length;
}
display_ztp(&entities[start+length-anim_target]);
}

if(loop == false && reverse == false){
if(anim_target < length && sync > 0){
anim_target++;
}
if(anim_target == length){
display_ztp(&entities[start]);
}
display_ztp(&entities[start+anim_target]);
}

if(loop == false && reverse == true){
if(anim_target < length && sync > 0){
anim_target++;
}
if(anim_target == length){
display_ztp(&entities[start]);
}
display_ztp(&entities[start+length-anim_target]);
}

}

--- End code ---


--- Code: ---
if(accelState == 0 && rotState[X] == 0){
anim_target = 0;
display_ztp(&entities[0]);
}
if(accelState > 0){
anim_entity_state(21, 19, evenFrame, true, false);
} else if(accelState < 0){
anim_entity_state(21, 19, evenFrame, true, true);
} else if(rotState[X] < 0){
anim_entity_state(1, 9, evenFrame, true, false);
} else if(rotState[X] > 0){
anim_entity_state(11, 9, evenFrame, true, false);
}
--- End code ---

I'm wordy but I like to leave little up to question.
Once the mesh is finished loading, no more loading is done with it.
It is important to note that if you wanted to use that entity slot for a different mesh, you can just load to that mesh address (&entitites[number]) again and it will be replaced.

And finally, the core loading loop. Note that there is a void function parameter in the function This is where you put the game loop.


--- Code: ---
//Experimental
void ztFileServer(void(*sysframe)(void))
{
if(process_requested != true){
goto SKIP;
}
    void * workAddress;
workAddress = requests[FilRqNm].dstAddress;

//Data of read structure
    Sint32 fid = (Sint32)requests[FilRqNm].filename;
GfsHn gfsx;
Sint32 nzect;
Sint32 fsize;
//Accepted rate of reading per frame (33 ms)
//Note to self: If your data is already byte size information, do not annotate with sizeOf. Thanks.
Sint32 rt_step = 512;
Uint8 rt_sector = 1;
//Data of read-in-process
Sint32 stat;
Sint32 rdsize;
//Model Data is the destination of data in the work area.
modelData_t bufModelX;
//Destination address?
void * ptr2 = &bufModelX;
//Loading follows
gfsx = GFS_Open(fid);
//Get sectors
//HEY! SBL DOCUMENTATION IS WRONG! THIRD ITEM nzect IS GFS SECTOR COUNT. SECOND ITEM IS CD SECTOR SIZE.
GFS_GetFileSize(gfsx, NULL, &nzect, NULL);
GFS_GetFileInfo(gfsx, NULL, NULL, &fsize, NULL);
//How many frames are we reading?
if(rt_step < fsize){
rd_frames = (fsize + (rt_step - 1))/(rt_step);
}
//Skip the loop if it is finished
if(curRdFrame >= rd_frames){
if(requests[FilRqNm].file_done != true){
  // Copy gfsx payload to modelData_t bufmodel
slDMACopy(workAddress, ptr2, sizeof(modelData_t));
slDMAWait();
//ADDED
    requests[FilRqNm].tmodel->pos[X]=bufModelX.Origin[X];
requests[FilRqNm].tmodel->pos[Y]=bufModelX.Origin[Y];
requests[FilRqNm].tmodel->pos[Z]=bufModelX.Origin[Z];
    requests[FilRqNm].tmodel->length[X]=bufModelX.Length[X];
requests[FilRqNm].tmodel->length[Y]=bufModelX.Length[Y];
requests[FilRqNm].tmodel->length[Z]=bufModelX.Length[Z];
    requests[FilRqNm].tmodel->nbMeshes=bufModelX.TOTAL_MESH;

Uint16 first_texture = loadTextures(workAddress, &bufModelX);
Sint32 bytesOff = bufModelX.TEXT_SIZE+(sizeof(modelData_t));
workAddress = (workAddress + bytesOff);
workAddress = loadPDATA((workAddress), requests[FilRqNm].tmodel, &bufModelX);
workAddress = (workAddress + (bufModelX.PDATA_SIZE + sizeof(modelData_t)));
setTextures(first_texture, requests[FilRqNm].tmodel, bufModelX.TOTAL_MESH, true);
requests[FilRqNm].dstAddress = workAddress;
}
requests[FilRqNm].file_done = true;
jo_printf(0, 9, "(skipped loop)");
goto SKIP;
}

jo_printf(0, 8, "(%i)", nzect);
jo_printf(10, 8, "(sectors)");
jo_printf(0, 9, "(%i)", fsize);
jo_printf(10, 9, "(file size)");

//Read from CD to CD buffer
//CONCEPT: NwFread specifies only a fetch from CD buffer. If no such read has been specified, it will carry it out itself.
//However, if you specify a read from CD, repeats of the fetch command will only fetch from the CD buffer and will not give errors for data remainders.
GFS_SetReadPara(gfsx, rt_step);
GFS_SetTransPara(gfsx, rt_sector);
//TIP: GFS_Nw_CdRead cannot be checked for completion. Sorry!
GFS_NwCdRead(gfsx, fsize);
for( ; curRdFrame < rd_frames ; curRdFrame++){
GFS_NwFread(gfsx, rt_sector, (Uint32*)(workAddress +(curRdFrame * rt_step)), rt_step);
do{
GFS_NwExecOne(gfsx);
GFS_NwGetStat(gfsx, &stat, &rdsize);
jo_printf(0, 11, "(%i)", rdsize);
jo_printf(10, 11, "(fetched filesize)");
}while(stat != GFS_SVR_COMPLETED && rdsize < rt_step);
//Remainder of file in comparison to rt_step [%] is handled, because we do not want to repeat the loop for the end of the data anyway. Do you understand?
//Technically, a file exactly divisible by rt_step will read-loop indefinitely. Watch out for that.
sysframe();
slSynch();
jo_printf(0, 15, "(%i)", curRdFrame);
jo_printf(4, 15, "(%i)", rd_frames);
jo_printf(0, 13, "(%i)", bufModelX.TOTAL_MESH);
jo_printf(3, 13, "(%i)", bufModelX.PDATA_SIZE);
jo_printf(10, 13, "(%i)", requests[FilRqNm].tmodel->nbMeshes);
}

SKIP:
//It is important to ensure GFS is closed at all times outside the read loop.
GFS_Close(gfsx);

sysframe();
}

--- End code ---

ponut64:
Just to update you and the specifications,

clearly with the Saturn having an X2 speed CD-ROM drive, the system should be able to handle up to about 5 KB per frame (at 30 FPS) (with a good quality CD and laser?).
I must have had a bad burn that made testing at 2048 bytes per frame cause slow-down. I just did another burn and it handled 2048 bytes per frame (at 30 FPS) without a hitch.
So we can do more than I thought.

XL2:
Yeah, 2 KB sounds great. You could easily stream visibility data with this, which would allow great graphics. But you lose CDDA, so you need sequence music or pcm music, so it's a tradeoff.

Navigation

[0] Message Index

[*] Previous page

Sitemap 1 2 3 4 5 6 7 8 9 10 
Go to full version