Scrollable background: how?

Graphic based area of development (Graphics Processing Unit), including the Geometry Transform Engine (GTE), TIM, STR (MDEC), etc.
Post Reply
jman
Rookie Programmer
Rookie Programmer
Posts: 110
Joined: Aug 13, 2013

Scrollable background: how?

Post by jman » November 3rd, 2013, 9:11 am

Hello,

I'm trying to make a simple scrollable background.
I'm quite confused on how to accomplish this. There seems to be two ways to manage a background:

1) Load a single TIM file representing the whole "world" and generate a GsSPRITE from the resulting GsIMAGE. I should manually manage the number of "tpage"of the sprite. Am I able to scroll a background created like this? How do I change the [u,v] values of the GsSPRITE when I "cross" from one texture page to another? Possibly this is the efficient solution if the background size is under the screen limits and I don't need to scroll?

2) Create a tileset of GsCELL items, build a GsMAP and put it in a GsBG. This is easily scrollable but I don't know if it's the right thing when I have a background that is a big landscape image (that's the idea).
How do I create a tileset map and "position" all the items in the right place? Orion_ does it in his tutorial but the map looks to be an opaque object, I don't understand how to create such a map object.

Please could anyone amend my statements and hopefully clear things up a bit for me (in the meanwhile I'll keep on RTFM...)?
I hope I could explain the matter clear enough.

thanks

User avatar
inc^lightforce
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 248
Joined: Mar 07, 2013
I am a: Programmer Windows+PS1, GFX Artist
PlayStation Model: Black
Location: Germany

Post by inc^lightforce » November 4th, 2013, 10:15 am

the rectangle code can be replaced with your background image.
feel free to use my code

Also give a Try to this MapBuilder: http://rapidshare.com/share/34A2D16781A ... DA7F10C6CB

HERE: CODING RECTANGLE & LINES with Code...

Grab all Files incl. a Demo for PS1 EMU here

Image

Code: Select all

//***************************************************************
//    THIS WAS OUR LOADER FOR Medal of Honor 2 - Underground PAL
//    ===========================================================
//    Many Lines i removed !!!
//    Original Source:   27/10/2000
//
//***************************************************************
//--------------------------------------------------------------------------
// I N C L U D E S
//--------------------------------------------------------------------------
#include <sys/types.h>
#include <stdlib.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <libgs.h>
#include <libsnd.h>
#include <libmath.h>
#include <libspu.h>
#include "hitmod.h" // For Sound
#include "pad.h" // PAD
#include "sinuss.h" // Sinus made with Sinuslab by Hitmen
#include "Sinstuff.h" // Sinus made with Sinuslab by Hitmen

#define	MAXCHAR	42
#define DEVELOPEMENT
#define ORDERING_TABLE_LENGTH (5)
#define MAX_NO_PACKETS  (3000)
#define	rnd(max)	((rand()*(max))/(32768)+1)
//--------------------------------------------------------------------------
// G L O B A L S
//--------------------------------------------------------------------------
GsOT		othWorld[2];
GsOT_TAG	otWorld[2][1<<ORDERING_TABLE_LENGTH];
PACKET		out_packet[2][(MAX_NO_PACKETS * 24)];
int		currentBuffer;	
u_long		PADstatus=0;	// Save PAD STATUS
int             v_countGFX=0, v_countCODE=0; // HSync Counter
u_char          HZMode=MODE_NTSC;

int Xangle,Yangle,depth;
int Xangle2,Yangle2;
int iScrollOffset=0;
extern char shades[]; // sound file

//-------------------------
// Font-Sprites & Textures
//-------------------------
GsBOXF		mybox[6]; // 2D RECTANGLE
GsLINE      line[360];
GsGLINE		line2[4];
int Video_MODE=0;

//--------------------------------------------------------------------------
// P R O T O T Y P E S
//--------------------------------------------------------------------------

void InitialiseGraphics(int,int,int); // Width, Height, MODE
void UpdateWorld();
void RenderWorld(char cClear);
void LoadTIMData (u_long *tMemAddress); // RAM -> VRam
void SetSpriteInfo(GsSPRITE *tSprite, u_long tMemAddress, long tX, long tY, int tCut);
void init_line(void);
void do_line(void);  // INIT LINE
void do_bar(void);   // INIT RECTANGLE
void init_bar(void); // INIT RECTANGLE
void init_Kloetze(void); // 2D RECTANGLE

int sin1=0;
int sin2=0;

int main()
  {
  u_long lTmp1;
  int i,j,k;
  int temp,temp1;
  int iTmp1,iTmp2,iTmp3,iTmp4;
	iTmp1=-60;
	iTmp2=-280;
	iTmp3=320;
	iTmp4=500;
	Xangle=Yangle=1;	//init x angle and y angle

	PadInit(0);     // Joypad Init

// CHECKS AUTO REGION , INPUT VALUES FOR PAL or NTSC PATCH HERE	
 if (*(char *)0xbfc7ff52=='E')	// E(urope) --> PAL; A(merica) and J(apan) both use NTSC
	{
		HZMode=MODE_PAL;
	}
	else
	{
		HZMode=MODE_NTSC;
	}

 
 InitialiseGraphics(320,240,HZMode); // GFX Init, inkl. Init akt. Buffer...

	MOD_Init(); // Sound Check
  	MOD_Load((u_char *) shades); // load Sound
  	MOD_Start(); // play Sound

	init_line(); // INIT LINE
	init_bar();  // 2D RECTANGLE
	init_Kloetze(); // 2D RECTANGLE

for (i=0;i<140;i++)
// ------------------------------------
// --------   M A I N    --------
// ------------------------------------
while(1)
 {
PADstatus=PadRead(4);
	if(PADstatus&Pad1x){Video_MODE=1; break;	} 
	if(PADstatus&Pad1crc){Video_MODE=2; break;	}

	do_line(); // GO FOR LINE
	do_bar(); // GO FOR RECTANGLE

	// Define RECTANGLE MOVEMENT
	iTmp1+=1;
	iTmp2+=1;
	iTmp3-=1;
	iTmp4-=1;
		if(iTmp1>320) iTmp1=-50;
		if(iTmp2>320) iTmp2=iTmp1-200;
		if(iTmp3<-150) iTmp3=320;
		if(iTmp4<-150) iTmp4=iTmp3+190;

mybox[0].x=iTmp1;
mybox[1].x=iTmp2;
mybox[2].x=iTmp2+40;
mybox[3].x=iTmp3;
mybox[4].x=iTmp4;
mybox[5].x=iTmp4;

GsSortBoxFill(&mybox[0],&othWorld[currentBuffer],2);
GsSortBoxFill(&mybox[1],&othWorld[currentBuffer],2);
GsSortBoxFill(&mybox[2],&othWorld[currentBuffer],2);
GsSortBoxFill(&mybox[3],&othWorld[currentBuffer],2);
GsSortBoxFill(&mybox[4],&othWorld[currentBuffer],2);
GsSortBoxFill(&mybox[5],&othWorld[currentBuffer],2);
	
RenderWorld(60);

    }
// ======================================================
// NOT IMPORTANT. THIS IS THE REST, A SNIPPET OF OUR CRACKS
// ======================================================
	SpuInit();
	SpuQuit();
 	MOD_Stop();
	MOD_Free();
	//VSync(3);
	PadStop();
  	ResetGraph(0);
  	StopCallback();
// ======================================================
// ===============================================	
}
void InitialiseGraphics(int SCRWidth,int SCRHeight,int HZMode)
  {
  SetVideoMode(HZMode);

  if ((HZMode == MODE_NTSC) && (SCRHeight==256)) SCRHeight=240;
    
  GsInitGraph(SCRWidth, SCRHeight, GsNONINTER|GsOFSGPU, 0, 0);

  GsDefDispBuff(0, 0, 0, SCRHeight);
// Correct Error in Library
  if (SCRHeight == 256) GsDISPENV.screen.h=256;

  othWorld[0].length = ORDERING_TABLE_LENGTH;
  othWorld[1].length = ORDERING_TABLE_LENGTH;
  othWorld[0].org = otWorld[0];
  othWorld[1].org = otWorld[1];
  GsClearOt(0,0,&othWorld[0]);
  GsClearOt(0,0,&othWorld[1]);

// Get the current Buffer
  currentBuffer=GsGetActiveBuff();

// set Address for Packet
  GsSetWorkBase((PACKET*)out_packet[currentBuffer]);
  }

void RenderWorld(char cClear)
  {
// ------------------------------------ " AN OLD LIST"

  v_countCODE=VSync(1);
  DrawSync(0);
  v_countGFX = VSync(1);
  VSync(0);	// wait until GPU are finished OLD LIST

    // swap both Buffers (Display / Drawing)
  GsSwapDispBuff();

// ------------------------------------ "ACTUAL LIST"

// "Register" a "ClearScreen"- Command in OT
//  R, G, B
  if (cClear==1)  GsSortClear(0, 0, 0,&othWorld[currentBuffer]);  // here can be changed the screen background Color
  if (cClear==60) GsSortClear(78, 0, 92,&othWorld[currentBuffer]); // here can be changed the screen background Color
  if (cClear==255)  GsSortClear(255, 255, 255,&othWorld[currentBuffer]); // here can be changed the screen background Color


// start drawing  ( GPU is now drawing the OT in Background)
  GsDrawOt(&othWorld[currentBuffer]);
  FntFlush(-1);

// ------------------------------------ "NEW LIST"

// init next OT !!!
// get the actual Buffer
  currentBuffer=GsGetActiveBuff();

// set Address for Packets
  GsSetWorkBase((PACKET*)out_packet[currentBuffer]);

// erase Content of OT
  GsClearOt(0, 0, &othWorld[currentBuffer]);

// OT is now ready for new OT Commands
  }

void LoadTIMData(u_long *tMemAddress)
  {
  RECT tRect;
  GsIMAGE tTim;

  DrawSync(0);
  tMemAddress++;
  GsGetTimInfo(tMemAddress, &tTim);   // SAVE TIM-Information to tTim
  tRect.x = tTim.px;
  tRect.y = tTim.py;
  tRect.w = tTim.pw;
  tRect.h = tTim.ph;
  LoadImage(&tRect, tTim.pixel);		// Load TIM-Data in VideoRam
  DrawSync(0);

  if ((tTim.pmode >> 3) & 0x01)
    {
    tRect.x = tTim.cx;
    tRect.y = tTim.cy;
    tRect.w = tTim.cw;
    tRect.h = tTim.ch;
    LoadImage(&tRect, tTim.clut);		// load CLUT in VideoRam
    };

  DrawSync(0);					// wait until GPU is ready
  }

void SetSpriteInfo(GsSPRITE *tSprite, u_long tMemAddress, long tX, long tY, int tCut)
  {
  GsIMAGE tTim;					// TIM image Information

  tMemAddress += 4;				// Pointer to Data
  GsGetTimInfo((u_long *) tMemAddress, &tTim);	// get TIM Information in tTim

  tSprite->x = tX;				// set Cordinates
  tSprite->y = tY;				// set Cordinates

  switch (tTim.pmode & 3)			// X-Value depends on BitDepht
    {
    case 0: tSprite->w = tTim.pw << 2;
            tSprite->u = (tTim.px & 0x3f) * 4;
            break;
    case 1: tSprite->w = tTim.pw << 1;
            tSprite->u = (tTim.px & 0x3f) * 2;
            break;
    default: tSprite->w = tTim.pw;
             tSprite->u = tTim.px & 0x3f; 
    };

  tSprite->h = tTim.ph;
  tSprite->v = tTim.py & 0xff;

  tSprite->tpage = GetTPage((tTim.pmode & 3),0,tTim.px,tTim.py);

  tSprite->attribute = (tTim.pmode & 3) << 24;

  tSprite->cx = tTim.cx;			// set CLUT of Sprite
  tSprite->cy = tTim.cy;

  tSprite->r = tSprite->g = tSprite->b = 128;	// Colour intensity
// set to Standart
  tSprite->mx = tSprite->w/2;			// Ref-POINT to the CENTER of a Sprite
  tSprite->my = tSprite->h/2;			

  tSprite->scalex = tSprite->scaley = ONE;	// Scale to 1 (real Size)
  tSprite->rotate = 0;				// rotation angle to 0 ZERO

  if (tCut)					// Cut Sprite if a Sprite have an illegal size
    tSprite->w -= tCut;				
  };
//===============================================
// REGISTER ALL LINES (position + rgb)
//===============================================
void init_line()
{
	line2[0].x0=0;
	line2[0].y0=65;
	line2[0].x1=160;
	line2[0].y1=65;
   
	line2[2].x0=160;
	line2[2].y0=65;
	line2[2].x1=320;
	line2[2].y1=65;
	
	line2[1].x0=0;
	line2[1].y0=179;
	line2[1].x1=160;
	line2[1].y1=179;

	line2[3].x0=160;
	line2[3].y0=179;
	line2[3].x1=320;
	line2[3].y1=179;
	
}

//======================================================
// DRAW THE LINES
//======================================================
void do_line()
{	
	GsSortGLine(&line2[0],&othWorld[currentBuffer],3);
    line2[0].r0=78;
	line2[0].g0=0;
	line2[0].b0=92;
	line2[0].r1=255;
	line2[0].g1=255;
	line2[0].b1=255;
	
	GsSortGLine(&line2[2],&othWorld[currentBuffer],3);
	
	line2[2].r0=255;
	line2[2].g0=255;
	line2[2].b0=255;
	line2[2].r1=78;
	line2[2].g1=0;
	line2[2].b1=92;
	
	GsSortGLine(&line2[1],&othWorld[currentBuffer],3);

	line2[1].r0=78;
	line2[1].g0=0;
	line2[1].b0=92;
	line2[1].r1=255;
	line2[1].g1=255;
	line2[1].b1=255;
	
	GsSortGLine(&line2[3],&othWorld[currentBuffer],3);

	line2[3].r0=255;
	line2[3].g0=255;
	line2[3].b0=255;
	line2[3].r1=78;
	line2[3].g1=0;
	line2[3].b1=92;
}

void do_bar()
{
int i,j;
if(sin1>=359)	sin1=0;	
sin2=sin1=sin1+1;

for(i=0;i<359;i++)
	{
	j=i+1;
	line[i].attribute=(1<<28)+(1<<27)+(2<<24)+(0<<28)+(1<<30);
	line[i].r=32;
	line[i].g=0;
	line[i].b=41;
	line[i].x0=150;
	line[i].x1=165+(scalesin[j]+scalesin2[sin2]/2);
	line[i].y0=120;
	line[i].y1=120+(scalesin2[j]/2);

	GsSortLine(&line[i],&othWorld[currentBuffer],3);
	sin2+=2;
	if(sin2>=360)	sin2-=360;
	}
}

void init_bar()
{
int k;
for(k=0;k<360;k++)
	{
	line[k]=line[0];
	line[k].y0=60;
	line[k].y1=100;
	line[k].r=line[k].b=line[k].g=128;
	}

}

void init_Kloetze() // 2D RECTANGLE
{int iTmp1,iTmp2,iTmp3,iTmp4;
	iTmp1=-60;
	iTmp2=-280;
	iTmp3=320;
	iTmp4=500;
		mybox[0].w=31;
		mybox[0].h=24;
		mybox[0].y=10;
		mybox[0].r=104;mybox[0].g=0;mybox[0].b=122;
		mybox[1].w=76;
		mybox[1].h=20;
		mybox[1].y=45;
		mybox[1].r=104;mybox[1].g=0;mybox[1].b=122;
		mybox[2].w=20;
		mybox[2].h=55;
		mybox[2].y=5;
		mybox[2].r=104;mybox[2].g=0;mybox[2].b=122;
		mybox[3].w=56;
		mybox[3].h=51;
		mybox[3].y=180;
		mybox[3].r=104;mybox[3].g=0;mybox[3].b=122;
		mybox[4].w=20;
		mybox[4].h=58;
		mybox[4].y=180;
		mybox[4].r=104;mybox[4].g=0;mybox[4].b=122;
		mybox[5].w=135;
		mybox[5].h=20;
		mybox[5].y=206;
		mybox[5].r=104;mybox[5].g=0;mybox[5].b=122;
}
have Fun while Coding. Questions? ASK .

inc.
Last edited by inc^lightforce on November 8th, 2013, 6:13 am, edited 1 time in total.

jman
Rookie Programmer
Rookie Programmer
Posts: 110
Joined: Aug 13, 2013

Post by jman » November 7th, 2013, 9:50 am

inc^lightforce wrote:the rectangle code can be replaced with yout background image.
feel free to use my code
just stopped by to say thank you. Hope I'll have time this weekend to check your examples.
The background now is ok, but when I send to the framebuffer (GsSortSprite) another sprite I have a second "ghost" sprite appearing at [0,0]. This does not happen without background.
I need to go back to the blackboard and study the ordering tables usage better. I'm surely mixing up something with the priority or I'm not invoking DrawSync() at the right moment.

Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests