Ejemplo n.º 1
0
/**
 * Set the next direntry to be read via onefs_readdir() to the beginning of the
 * directory.
 *
 * @param[in] handle vfs handle given in most VFS calls
 * @param[in] dirp system DIR handle to set offset on
 *
 * @return no return value
 */
void
onefs_rewinddir(vfs_handle_struct *handle,  SMB_STRUCT_DIR *dirp)
{
	struct rdp_dir_state *dsp = NULL;
	bool same_as_last;
	int ret = -1;

	/* Fallback to default system routines if readdirplus is disabled */
	if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
	    PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
	{
		return sys_rewinddir(dirp);
	}

	/* Retrieve state based off DIR handle */
	ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
	if (ret) {
		DEBUG(1, ("Could not retrieve dir_state struct for "
			 "SMB_STRUCT_DIR pointer.\n"));
		return;
	}

	/* Reset location and resume key to beginning */
	ret = rdp_init(dsp);
	if (ret) {
		DEBUG(0, ("Error re-initializing rdp cursors: %s\n",
		    strerror(ret)));
		return;
	}

	DEBUG(9, ("Rewind DIR: %p, to location: %ld\n", dsp->dirp,
		 dsp->location));

	return;
}
Ejemplo n.º 2
0
/**
 * Create a dir_state to track an open directory that we're enumerating.
 *
 * This utility function is globally accessible for use by other parts of the
 * onefs.so module to initialize a dir_state when a directory is opened through
 * a path other than the VFS layer.
 *
 * @return 0 on success and errno on failure
 *
 * @note: Callers of this function MUST cleanup the dir_state through a proper
 * call to VFS_CLOSEDIR().
 */
int
onefs_rdp_add_dir_state(connection_struct *conn, SMB_STRUCT_DIR *dirp)
{
	int ret = 0;
	struct rdp_dir_state *dsp = NULL;

	/* No-op if readdirplus is disabled */
	if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
	    PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
	{
		return 0;
	}

	/* Create a struct dir_state */
	dsp = SMB_MALLOC_P(struct rdp_dir_state);
	if (!dsp) {
		DEBUG(0, ("Error allocating struct rdp_dir_state.\n"));
		return ENOMEM;
	}

	/* Initialize the dir_state structure and add it to the list */
	ret = rdp_init(dsp);
	if (ret) {
		DEBUG(0, ("Error initializing readdirplus() buffers: %s\n",
			 strerror(ret)));
		return ret;
	}

	/* Set the SMB_STRUCT_DIR in the dsp */
	dsp->dirp = dirp;

	DLIST_ADD(dirstatelist, dsp);

	return 0;
}
Ejemplo n.º 3
0
int angrylionRomOpen (void)
{
   /* TODO/FIXME: For now just force it to 640x480.
    *
    * Later on we might want a low-res mode (320x240)
    * for better performance as well in case screen_width
    * is 320 and height is 240.
    */
   if (screen_width < 640)
      screen_width = 640;
   if (screen_width > 640)
      screen_width = 640;

   if (screen_height < 480)
      screen_height = 480;
   if (screen_height > 480)
      screen_height = 480;

   pitchindwords = PRESCALE_WIDTH / 1; /* sizeof(DWORD) == sizeof(pixel) == 4 */
   screen_pitch  = PRESCALE_WIDTH << 2;

   rdp_init();
   overlay = ConfigGetParamBool(l_ConfigAngrylion, "VIOverlay");
   return 1;
}
int angrylionRomOpen (void)
{
   /* TODO/FIXME: For now just force it to 640x480.
    *
    * Later on we might want a low-res mode (320x240)
    * for better performance as well in case screen_width
    * is 320 and height is 240.
    */
   if (screen_width < 640)
      screen_width = 640;
   if (screen_width > 640)
      screen_width = 640;

   if (screen_height < 480)
      screen_height = 480;
   if (screen_height > 480)
      screen_height = 480;

   screen_pitch  = PRESCALE_WIDTH << 2;

   rdp_init();
   angrylion_set_vi((int)ConfigGetParamBool(l_ConfigAngrylion, "VIOverlay"));
   return 1;
}
Ejemplo n.º 5
0
EXPORT void CALL RomOpen (void)
{
	RECT bigrect, smallrect, statusrect;
	
	GetWindowRect(gfx.hWnd,&bigrect);
	GetClientRect(gfx.hWnd,&smallrect);
	int rightdiff = screen_width - smallrect.right;
	int bottomdiff = screen_height - smallrect.bottom;
	if (gfx.hStatusBar)
	{
		GetClientRect(gfx.hStatusBar, &statusrect);
		bottomdiff += statusrect.bottom;
	}
	MoveWindow(gfx.hWnd, bigrect.left, bigrect.top, bigrect.right - bigrect.left + rightdiff, bigrect.bottom - bigrect.top + bottomdiff, TRUE);
	

	DDPIXELFORMAT ftpixel;
	LPDIRECTDRAWCLIPPER lpddcl;

	res = DirectDrawCreateEx(0, (LPVOID*)&lpdd, IID_IDirectDraw7, 0);
	if(res != DD_OK) 
		fatalerror("Couldn't create a DirectDraw object");
	res = IDirectDraw_SetCooperativeLevel(lpdd, gfx.hWnd, DDSCL_NORMAL);
	if(res != DD_OK) 
		fatalerror("Couldn't set a cooperative level. Error code %x", res);

	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	
	
	res = IDirectDraw_CreateSurface(lpdd, &ddsd, &lpddsprimary, 0);
	if(res != DD_OK)
		fatalerror("CreateSurface for a primary surface failed. Error code %x", res);

	
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
	ddsd.dwWidth = PRESCALE_WIDTH;
	ddsd.dwHeight = PRESCALE_HEIGHT;
	memset(&ftpixel, 0, sizeof(ftpixel));
	ftpixel.dwSize = sizeof(ftpixel);
	ftpixel.dwFlags = DDPF_RGB;
	ftpixel.dwRGBBitCount = 32;
	ftpixel.dwRBitMask = 0xff0000;
	ftpixel.dwGBitMask = 0xff00;
	ftpixel.dwBBitMask = 0xff;
	ddsd.ddpfPixelFormat = ftpixel;
	res = IDirectDraw_CreateSurface(lpdd, &ddsd, &lpddsback, 0);
	if (res == DDERR_INVALIDPIXELFORMAT)
		fatalerror("ARGB8888 is not supported. You can try changing desktop color depth to 32-bit, but most likely that won't help.");
	else if(res != DD_OK)
		fatalerror("CreateSurface for a secondary surface failed. Error code %x", res);

	
	res = IDirectDrawSurface_GetSurfaceDesc(lpddsback, &ddsd);
	if (res != DD_OK)
		fatalerror("GetSurfaceDesc failed.");
	if ((ddsd.lPitch & 3) || ddsd.lPitch < (PRESCALE_WIDTH << 2))
		fatalerror("Pitch of a secondary surface is either not 32 bit aligned or two small.");
	pitchindwords = ddsd.lPitch >> 2;

	
	res = IDirectDraw_CreateClipper(lpdd, 0, &lpddcl, 0);
	if (res != DD_OK)
		fatalerror("Couldn't create a clipper.");
	res = IDirectDrawClipper_SetHWnd(lpddcl, 0, gfx.hWnd);
	if (res != DD_OK)
		fatalerror("Couldn't register a windows handle as a clipper.");
	res = IDirectDrawSurface_SetClipper(lpddsprimary, lpddcl);
	if (res != DD_OK)
		fatalerror("Couldn't attach a clipper to a surface.");

	
	src.top = src.left = 0; 
	src.bottom = 0;
	src.right = PRESCALE_WIDTH;

	POINT p;
	p.x = p.y = 0;
	GetClientRect(gfx.hWnd, &dst);
	ClientToScreen(gfx.hWnd, &p);
	OffsetRect(&dst, p.x, p.y);
	GetClientRect(gfx.hStatusBar, &statusrect);
	dst.bottom -= statusrect.bottom;

	rdp_init();


}
Ejemplo n.º 6
0
/**
 * Set the location of the next direntry to be read via onefs_readdir().
 *
 * This function should only pass in locations retrieved from onefs_telldir().
 *
 * Ideally the seek point will still be in the readdirplus cache, and we'll
 * just update our cursors.  If the seek location is outside of the current
 * cache we must do an expensive re-enumeration of the entire directory up
 * to the offset.
 *
 * @param[in] handle vfs handle given in most VFS calls
 * @param[in] dirp system DIR handle to set offset on
 * @param[in] offset from the start of the directory where the next read
 *	      will take place
 *
 * @return no return value
 */
void
onefs_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset)
{
	struct rdp_dir_state *dsp = NULL;
	bool same_as_last;
	bool outside_cache = false;
	int ret = -1, i;

	/* Fallback to default system routines if readdirplus is disabled */
	if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
	    PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
	{
		return sys_seekdir(dirp, offset);
	}

	/* Validate inputs */
	if (offset < 0) {
		DEBUG(1, ("Invalid offset %ld passed.\n", offset));
		return;
	}

	/* Retrieve state based off DIR handle */
	ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
	if (ret) {
		DEBUG(1, ("Could not retrieve dir_state struct for "
			 "SMB_STRUCT_DIR pointer.\n"));
		/* XXX: we can't return an error, should we ABORT rather than
		 * return without actually seeking? */
		return;
	}

	/* Short cut if no work needs to be done */
	if (offset == dsp->location)
		return;

	/* If DIR is different from last call, reset all buffers and cursors,
	 * and refill the global cache from the new DIR */
	if (!same_as_last) {
		ret = rdp_fill_cache(dsp);
		if (ret <= 0)
			goto out;
		DEBUG(8, ("Switched global rdp cache to new DIR entry.\n"));
	}

	/* Check if location is outside the currently cached entries */
	if (offset < dsp->location - dsp->stat_cursor) {
		/* offset is before the current cache */
		/* reset to the beginning of the directory */
		ret = rdp_init(dsp);
		if (ret) {
			DEBUG(0, ("Error initializing readdirplus() buffers: "
				 "%s\n", strerror(ret)));
			goto out;
		}
		outside_cache = true;
	} else if (offset >
	    dsp->location + (dsp->stat_count - 1 - dsp->stat_cursor))
	{
		/* offset is after the current cache
		 * advance the cookie to the end of the cache */
		dsp->resume_cookie = rdp_cookies[dsp->stat_count - 1];
		outside_cache = true;
	}

	if (outside_cache) {
		/* start reading from the directory, until we have the
		 * specified offset in our cache */
		do {
			dsp->location += dsp->stat_count - dsp->stat_cursor;
			ret = rdp_fill_cache(dsp);
			if (ret <= 0) {
				DEBUG(1, ("Error seeking to offset outside the "
					 "cached directory entries. Offset "
					 "%ld \n", dsp->location));
				goto out;
			}
			dsp->resume_cookie = rdp_cookies[dsp->stat_count - 1];
		} while (offset >= dsp->location + dsp->stat_count);
	}

	/* Location should be within the currently cached entries */
	if (offset < dsp->location &&
	    offset >= dsp->location - dsp->stat_cursor)
	{
		/* offset is within the current cache, before the cursor.
		 * update cursors to the new location */
		int new_cursor = dsp->stat_cursor - (dsp->location - offset);

		dsp->direntries_cursor = rdp_direntries;
		for (i=0; i < new_cursor; i++) {
			dsp->direntries_cursor +=
			    ((SMB_STRUCT_DIRENT *)
			     dsp->direntries_cursor)->d_reclen;
		}
		dsp->stat_cursor = new_cursor;
		dsp->resume_cookie = rdp_cookies[dsp->stat_cursor];
		dsp->location = offset;
	} else if (offset >= dsp->location &&
	   offset <= dsp->location + (dsp->stat_count - 1 - dsp->stat_cursor))
	{
		/* offset is within the current cache, at or after the cursor.
		 * update cursors to the new location */
		int add_to_cursor = offset - dsp->location - 1;

		for (i=0; i < add_to_cursor; i++) {
			dsp->direntries_cursor +=
			    ((SMB_STRUCT_DIRENT *)
			     dsp->direntries_cursor)->d_reclen;
		}
		dsp->stat_cursor += add_to_cursor;
		dsp->resume_cookie = rdp_cookies[dsp->stat_cursor];
		dsp->location = offset;
	}

	DEBUG(9, ("Seek DIR %p, location: %ld, cache cursor: %zu\n",
		 dsp->dirp, dsp->location, dsp->stat_cursor));

	/* FALLTHROUGH */
out:
	/* Set rdp_last_dirp at the end of every VFS call where the cache was
	 * reloaded */
	rdp_last_dirp = dirp;
	return;
}
Ejemplo n.º 7
0
EXPORT int CALL angrylionRomOpen (void)
{
#ifndef HAVE_DIRECTDRAW
   screen_width = SCREEN_WIDTH;
   screen_height = SCREEN_HEIGHT;
   blitter_buf = (uint32_t*)calloc(screen_width * screen_height, sizeof(uint32_t));
   pitchindwords = screen_width * 4;
   screen_pitch = PRESCALE_WIDTH << 2;
#else
    DDPIXELFORMAT ftpixel;
    LPDIRECTDRAWCLIPPER lpddcl;
    RECT bigrect, smallrect, statusrect;
    POINT p;
    int rightdiff;
    int bottomdiff;
    GetWindowRect(gfx.hWnd,&bigrect);
    GetClientRect(gfx.hWnd,&smallrect);
    rightdiff = screen_width - smallrect.right;
    bottomdiff = screen_height - smallrect.bottom;

    if (gfx.hStatusBar)
    {
        GetClientRect(gfx.hStatusBar, &statusrect);
        bottomdiff += statusrect.bottom;
    }
    MoveWindow(gfx.hWnd, bigrect.left, bigrect.top, bigrect.right - bigrect.left + rightdiff, bigrect.bottom - bigrect.top + bottomdiff, true);

    res = DirectDrawCreateEx(0, (LPVOID*)&lpdd, &IID_IDirectDraw7, 0);
    if (res != DD_OK)
    {
        DisplayError("Couldn't create a DirectDraw object.");
        return; /* to-do:  move to InitiateGFX? */
    }
    res = IDirectDraw_SetCooperativeLevel(lpdd, gfx.hWnd, DDSCL_NORMAL);
    if (res != DD_OK)
    {
        DisplayError("Couldn't set a cooperative level.");
        return; /* to-do:  move to InitiateGFX? */
    }

    zerobuf(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    res = IDirectDraw_CreateSurface(lpdd, &ddsd, &lpddsprimary, 0);
    if (res != DD_OK)
    {
        DisplayError("CreateSurface for a primary surface failed.");
        return; /* to-do:  move to InitiateGFX? */
    }

    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth = PRESCALE_WIDTH;
    ddsd.dwHeight = PRESCALE_HEIGHT;
    zerobuf(&ftpixel, sizeof(ftpixel));
    ftpixel.dwSize = sizeof(ftpixel);
    ftpixel.dwFlags = DDPF_RGB;
    ftpixel.dwRGBBitCount = 32;
    ftpixel.dwRBitMask = 0xff0000;
    ftpixel.dwGBitMask = 0xff00;
    ftpixel.dwBBitMask = 0xff;
    ddsd.ddpfPixelFormat = ftpixel;
    res = IDirectDraw_CreateSurface(lpdd, &ddsd, &lpddsback, 0);
    if (res == DDERR_INVALIDPIXELFORMAT)
    {
        DisplayError(
            "ARGB8888 is not supported. You can try changing desktop color "\
            "depth to 32-bit, but most likely that won't help.");
        return; /* InitiateGFX fails. */
    }
    else if (res != DD_OK)
    {
        DisplayError("CreateSurface for a secondary surface failed.");
        return; /* InitiateGFX should fail. */
    }

    res = IDirectDrawSurface_GetSurfaceDesc(lpddsback, &ddsd);
    if (res != DD_OK)
    {
        DisplayError("GetSurfaceDesc failed.");
        return; /* InitiateGFX should fail. */
    }
    if ((ddsd.lPitch & 3) || ddsd.lPitch < (PRESCALE_WIDTH << 2))
    {
        DisplayError(
            "Pitch of a secondary surface is either not 32 bit aligned or "\
            "too small.");
        return; /* InitiateGFX should fail. */
    }
    pitchindwords = ddsd.lPitch >> 2;

    res = IDirectDraw_CreateClipper(lpdd, 0, &lpddcl, 0);
    if (res != DD_OK)
    {
        DisplayError("Couldn't create a clipper.");
        return; /* InitiateGFX should fail. */
    }
    res = IDirectDrawClipper_SetHWnd(lpddcl, 0, gfx.hWnd);
    if (res != DD_OK)
    {
        DisplayError("Couldn't register a windows handle as a clipper.");
        return; /* InitiateGFX should fail. */
    }
    res = IDirectDrawSurface_SetClipper(lpddsprimary, lpddcl);
    if (res != DD_OK)
    {
        DisplayError("Couldn't attach a clipper to a surface.");
        return; /* InitiateGFX should fail. */
    }

    src.top = src.left = 0; 
    src.bottom = 0;
#if SCREEN_WIDTH < PRESCALE_WIDTH
    src.right = PRESCALE_WIDTH - 1; /* fix for undefined video card behavior */
#else
    src.right = PRESCALE_WIDTH;
#endif
    p.x = p.y = 0;
    GetClientRect(gfx.hWnd, &dst);
    ClientToScreen(gfx.hWnd, &p);
    OffsetRect(&dst, p.x, p.y);
    GetClientRect(gfx.hStatusBar, &statusrect);
    dst.bottom -= statusrect.bottom;
#endif

    rdp_init();
    overlay = 0;
    return 1;
}
Ejemplo n.º 8
0
// Creates and initializes a device.
struct cen64_device *device_create(struct cen64_device *device,
  const struct rom_file *ddipl, const struct rom_file *ddrom,
  const struct rom_file *pifrom, const struct rom_file *cart,
  const struct save_file *eeprom, const struct save_file *sram,
  const struct save_file *flashram, const struct controller *controller,
  bool no_audio, bool no_video) {

  // Initialize the bus.
  device->bus.ai = &device->ai;
  device->bus.dd = &device->dd;
  device->bus.pi = &device->pi;
  device->bus.ri = &device->ri;
  device->bus.si = &device->si;
  device->bus.vi = &device->vi;

  device->bus.rdp = &device->rdp;
  device->bus.rsp = &device->rsp;
  device->bus.vr4300 = &device->vr4300;

  // Initialize the bus.
  if (bus_init(&device->bus)) {
    debug("create_device: Failed to initialize the bus.\n");
    return NULL;
  }

  // Initialize the AI.
  if (ai_init(&device->ai, &device->bus, no_audio)) {
    debug("create_device: Failed to initialize the AI.\n");
    return NULL;
  }

  // Initialize the DD.
  if (dd_init(&device->dd, &device->bus,
    ddipl->ptr, ddrom->ptr, ddrom->size)) {
    debug("create_device: Failed to initialize the DD.\n");
    return NULL;
  }

  // Initialize the PI.
  if (pi_init(&device->pi, &device->bus, cart->ptr, cart->size, sram, flashram)) {
    debug("create_device: Failed to initialize the PI.\n");
    return NULL;
  }

  // Initialize the RI.
  if (ri_init(&device->ri, &device->bus)) {
    debug("create_device: Failed to initialize the RI.\n");
    return NULL;
  }

  // Initialize the SI.
  if (si_init(&device->si, &device->bus, pifrom->ptr,
    cart->ptr, ddipl->ptr != NULL, eeprom->ptr, eeprom->size,
    controller)) {
    debug("create_device: Failed to initialize the SI.\n");
    return NULL;
  }

  // Initialize the VI.
  if (vi_init(&device->vi, &device->bus, no_video)) {
    debug("create_device: Failed to initialize the VI.\n");
    return NULL;
  }

  // Initialize the RDP.
  if (rdp_init(&device->rdp, &device->bus)) {
    debug("create_device: Failed to initialize the RDP.\n");
    return NULL;
  }

  // Initialize the RSP.
  if (rsp_init(&device->rsp, &device->bus)) {
    debug("create_device: Failed to initialize the RSP.\n");
    return NULL;
  }

  // Initialize the VR4300.
  if (vr4300_init(&device->vr4300, &device->bus)) {
    debug("create_device: Failed to initialize the VR4300.\n");
    return NULL;
  }

  return device;
}
Ejemplo n.º 9
0
int main(void)
{
    int mode = 0;

    /* enable interrupts (on the CPU) */
    init_interrupts();

    /* Initialize peripherals */
    display_init( RESOLUTION_320x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE );
    dfs_init( DFS_DEFAULT_LOCATION );
    rdp_init();
    controller_init();
    timer_init();

    /* Read in single sprite */
    int fp = dfs_open("/mudkip.sprite");
    sprite_t *mudkip = malloc( dfs_size( fp ) );
    dfs_read( mudkip, 1, dfs_size( fp ), fp );
    dfs_close( fp );
    
    fp = dfs_open("/earthbound.sprite");
    sprite_t *earthbound = malloc( dfs_size( fp ) );
    dfs_read( earthbound, 1, dfs_size( fp ), fp );
    dfs_close( fp );

    fp = dfs_open("/plane.sprite");
    sprite_t *plane = malloc( dfs_size( fp ) );
    dfs_read( plane, 1, dfs_size( fp ), fp );
    dfs_close( fp );

    /* Kick off animation update timer to fire thirty times a second */
    new_timer(TIMER_TICKS(1000000 / 30), TF_CONTINUOUS, update_counter);

    /* Main loop test */
    while(1) 
    {
        static display_context_t disp = 0;

        /* Grab a render buffer */
        while( !(disp = display_lock()) );
       
        /*Fill the screen */
        graphics_fill_screen( disp, 0xFFFFFFFF );

        /* Set the text output color */
        graphics_set_color( 0x0, 0xFFFFFFFF );
    
        switch( mode )
        {
            case 0:
                /* Software spritemap test */
                graphics_draw_text( disp, 20, 20, "Software spritemap test" );

                /* Display a stationary sprite of adequate size to fit in TMEM */
                graphics_draw_sprite_trans( disp, 20, 50, plane );

                /* Display a stationary sprite to demonstrate backwards compatibility */
                graphics_draw_sprite_trans( disp, 50, 50, mudkip );

                /* Display walking NESS animation */
                graphics_draw_sprite_stride( disp, 20, 100, earthbound, ((animcounter / 15) & 1) ? 1: 0 );

                /* Display rotating NESS animation */
                graphics_draw_sprite_stride( disp, 50, 100, earthbound, ((animcounter / 8) & 0x7) * 2 );

                break;
            case 1:
            {
                /* Hardware spritemap test */
                graphics_draw_text( disp, 20, 20, "Hardware spritemap test" );

                /* Assure RDP is ready for new commands */
                rdp_sync( SYNC_PIPE );

                /* Remove any clipping windows */
                rdp_set_default_clipping();

                /* Enable sprite display instead of solid color fill */
                rdp_enable_texture_copy();

                /* Attach RDP to display */
                rdp_attach_display( disp );
                    
                /* Ensure the RDP is ready to receive sprites */
                rdp_sync( SYNC_PIPE );

                /* Load the sprite into texture slot 0, at the beginning of memory, without mirroring */
                rdp_load_texture( 0, 0, MIRROR_DISABLED, plane );
                
                /* Display a stationary sprite of adequate size to fit in TMEM */
                rdp_draw_sprite( 0, 20, 50 );

                /* Since the RDP is very very limited in texture memory, we will use the spritemap feature to display
                   all four pieces of this sprite individually in order to use the RDP at all */
                for( int i = 0; i < 4; i++ )
                {
                    /* Ensure the RDP is ready to receive sprites */
                    rdp_sync( SYNC_PIPE );

                    /* Load the sprite into texture slot 0, at the beginning of memory, without mirroring */
                    rdp_load_texture_stride( 0, 0, MIRROR_DISABLED, mudkip, i );
                
                    /* Display a stationary sprite to demonstrate backwards compatibility */
                    rdp_draw_sprite( 0, 50 + (20 * (i % 2)), 50 + (20 * (i / 2)) );
                }

                /* Ensure the RDP is ready to receive sprites */
                rdp_sync( SYNC_PIPE );

                /* Load the sprite into texture slot 0, at the beginning of memory, without mirroring */
                rdp_load_texture_stride( 0, 0, MIRROR_DISABLED, earthbound, ((animcounter / 15) & 1) ? 1: 0 );
                
                /* Display walking NESS animation */
                rdp_draw_sprite( 0, 20, 100 );

                /* Ensure the RDP is ready to receive sprites */
                rdp_sync( SYNC_PIPE );

                /* Load the sprite into texture slot 0, at the beginning of memory, without mirroring */
                rdp_load_texture_stride( 0, 0, MIRROR_DISABLED, earthbound, ((animcounter / 8) & 0x7) * 2 );
                
                /* Display rotating NESS animation */
                rdp_draw_sprite( 0, 50, 100 );

                /* Inform the RDP we are finished drawing and that any pending operations should be flushed */
                rdp_detach_display();

                break;
            }
        }

        /* Force backbuffer flip */
        display_show(disp);

        /* Do we need to switch video displays? */
        controller_scan();
        struct controller_data keys = get_keys_down();

        if( keys.c[0].A )
        {
            /* Lazy switching */
            mode = 1 - mode;
        }
    }
}