function CreateBox()
	-- We have to create a ton of small quads because the PSP fails HARD at clipping.
	local w, h = 8, 6
	local xs, ys = (2 * (16/9)) / w, 2 / h
	local us, vs = ((16/9) / w) / 2, -1 / h
	local Vtx = AllocVertices(w * h * 4)
	
	for Y=0, h - 1 do
		for X=0, w - 1 do
			local vx, vy, vu, vv = (X * xs), (Y * ys), X * us, Y * vs
			local UL = {u=vu,		v=vv,		x=vx, 		y=vy,			z=0.0, r=255, g=255, b=255, a=255} --r=X * (255 / w), g = Y * (255 / h), b = 0, a = 192}
			local LL = {u=vu,		v=vv+vs,	x=vx,		y=vy+ys,		z=0.0, r=255, g=255, b=255, a=255} --r=X * (255 / w), g = Y * (255 / h), b = 0, a = 192}
			local UR = {u=vu+us,	v=vv,		x=vx+xs,	y=vy,			z=0.0, r=255, g=255, b=255, a=255} --r=X * (255 / w), g = Y * (255 / h), b = 0, a = 192}
			local LR = {u=vu+us,	v=vv+vs,	x=vx+xs,	y=vy+ys,		z=0.0, r=255, g=255, b=255, a=255} --r=X * (255 / w), g = Y * (255 / h), b = 0, a = 192}
			SetVertices(Vtx, ((Y * w) + X) * 4, UL, LL, UR, LR)
		end
	end
	
	return Vtx
end

-- Draws a menu.
-- Inputs:
-- -MenuID: Which menu to draw.
-- Notes: Sets global SelectedItem to the key of the selected item.
function DrawMenu(MenuID)
	local i, line, x, y = 0, 0, 18, 10
	local key = MenuDispKey[MenuID]
	local Buf = MenuTextBuf[MenuID]
	
	--Clear the quad
	Image_Clear(Buf, 0, 0, 0, 0)
	
	--BitmapFont_DrawString(Buf, Font, 20, 20, FONT_DRAW_NORMAL,
	--	nil, tostring(MenuID))
	
	-- Draw the text
	--[
	for a, d in pairs(MenuTable[MenuID]) do
		if i >= Skip and i < (Skip + NumLines) then
			BitmapFont_DrawString(Buf, Font, x, y, FONT_DRAW_NORMAL,
				nil, key and d[key] or d)
			
			if i == Cursor then
				SelectedItem = a
				BitmapFont_DrawString(Buf, Font, x - 8, y,
					FONT_DRAW_NORMAL, nil, ">")
			end
			
			y = y + LineHeight
			if y >= 256 then break end
			
			line = line + 1
			if line >= NumLines then break end
		end
		i = i + 1
	end --]]
	
	-- Render the quad
	Image_Flush(Buf)
	UseTexture(Buf)
	for i=0, 47 do
		RenderVertices(Box, i * 4, 4, GU_TRIANGLE_STRIP, GU_TRANSFORM_3D)
	end
end


-- Draws builtin apps menu.
-- Notes: Sets global SelectedItem to the key of the selected item.
function DrawBuiltinAppsMenu()
	local i = 0
	local ix, iy = 0, 0
		
	for a, d in pairs(BuiltinApps) do
		ResetMatrices()
		RotateDegrees(0, (90 * (MenuID - 2)) - RotCount, 0)
		UseTexture(BuiltinAppIcons[d])
		
		-- Move to the position the icon will be drawn
		Translate((ix / 4) - 0.8, (-iy / 4) + 0.4, -1)
		
		-- Draw the icon
		RenderVertices(Icons, 0, 4, GU_TRIANGLE_STRIP, GU_TRANSFORM_3D)
		
		if i == Cursor then
			SelectedItem = a
			UseTexture(CursorImg)
			RenderVertices(Icons, 0, 4, GU_TRIANGLE_STRIP, GU_TRANSFORM_3D)
		end
		
		i = i + 1
		ix = ix + 1
		if ix >= IconGridNumCols then
			ix = 0
			iy = iy + 1
		end
	end
end


-- Checks and resets the IgnoreCursor flag.
function CheckIgnoreCursor()
	if IgnoreCursor then
		-- If all above buttons are released then the cursor can respond again
		-- "if ... then else" is shorter than writing "and not" several times
		-- when checking that several variables are false
		if Buttons.up or Buttons.down or Buttons.left or Buttons.right
		or Buttons.l or Buttons.r or Buttons.accept or Buttons.cancel
		or Buttons.triangle or Buttons.square then else
			IgnoreCursor = false
		end
		return true
	end
	return false
end


-- Validates cursor position and menu ID.
function CheckCursorPos()
	-- Ensure we're in a menu that exists
	if MenuID > NumMenus then MenuID = 1
	elseif MenuID < 1 then MenuID = NumMenus
	end
	
	-- If we just switched to the file selector for the first time,
	-- read the file list.
	if MenuID == FileMenuID and not Files then ReadCurDir() end
	
	-- Ensure the cursor is visible and within the menu
	if MenuID == BuiltinAppMenuID and Use3DIconRing then
		if Cursor < 0 then Cursor = NumBuiltinApps + Cursor
		elseif Cursor >= NumBuiltinApps then
			Cursor = Cursor - NumBuiltinApps
		end
	else
		if Cursor < 0 then Cursor = MenuNumOpts[MenuID] - 1
		elseif Cursor >= MenuNumOpts[MenuID] then Cursor = 0
		end
	end
		
	if MenuID == BuiltinAppMenuID then return end
	
	if Cursor < Skip then Skip = Cursor
	elseif Cursor >= (Skip + NumLines)
	then Skip = (Cursor - NumLines) + 1
	end
end


-- Handles menu controls.
function DoMenuControls()
	if CheckIgnoreCursor() then return end
	
	local Moved = true
	if Buttons.up then
		Cursor = Cursor - 1
		SoundEffect_Replay(CursorSound)
	elseif Buttons.down then
		Cursor = Cursor + 1
		SoundEffect_Replay(CursorSound)
	elseif Buttons.left then
		Cursor = Cursor - 10
		SoundEffect_Replay(CursorSound)
	elseif Buttons.right then
		Cursor = Cursor + 10
		SoundEffect_Replay(CursorSound)
	elseif Buttons.l then
		Cursor = 0
		MenuID = MenuID - 1
		RotCount = -90
		SoundEffect_Replay(LSwitchSound)
	elseif Buttons.r then
		Cursor = 0
		MenuID = MenuID + 1
		RotCount = 90
		SoundEffect_Replay(RSwitchSound)
	elseif Buttons.accept then MenuAcceptFunc[MenuID]()
	elseif Buttons.cancel then MenuCancelFunc[MenuID]()
	elseif Buttons.triangle then MenuTriangleFunc[MenuID]()
	elseif Buttons.square then MenuSquareFunc[MenuID]()
	else Moved = false end
	
	if Moved then IgnoreCursor = true end -- Don't move again until button is released
	CheckCursorPos()
end


-- Handles menu controls in built-in app list.
function BuiltinAppMenuControls()
	if CheckIgnoreCursor() then return end
	
	local p = (math.pi / 180)
	local Moved = true
	if Buttons.up then
		Cursor = Cursor - IconGridNumCols
		SoundEffect_Replay(CursorSound)
		IconRingRotation = (360 / NumBuiltinApps) * -p * IconGridNumCols
	elseif Buttons.down then
		Cursor = Cursor + IconGridNumCols
		SoundEffect_Replay(CursorSound)
		IconRingRotation = (360 / NumBuiltinApps) * p * IconGridNumCols
	elseif Buttons.left then
		Cursor = Cursor - 1
		SoundEffect_Replay(CursorSound)
		IconRingRotation = (360 / NumBuiltinApps) * -p
	elseif Buttons.right then
		Cursor = Cursor + 1
		SoundEffect_Replay(CursorSound)
		IconRingRotation = (360 / NumBuiltinApps) * p
	elseif Buttons.l then
		Cursor = 0
		MenuID = MenuID - 1
		RotCount = -90
		SoundEffect_Replay(LSwitchSound)
	elseif Buttons.r then
		Cursor = 0
		MenuID = MenuID + 1
		RotCount = 90
		SoundEffect_Replay(RSwitchSound)
	elseif Buttons.accept then MenuAcceptFunc[MenuID]()
	elseif Buttons.cancel then MenuCancelFunc[MenuID]()
	elseif Buttons.triangle then MenuTriangleFunc[MenuID]()
	elseif Buttons.square then MenuSquareFunc[MenuID]()
	else Moved = false end
	
	if Moved then
		IgnoreCursor = true
		IconRotation = 0
	end -- Don't move again until button is released
	CheckCursorPos()
end


-- Read current directory.
function ReadCurDir()
	Files, e = ReadDirectory(CurDir, true)
	if not Files then Files = {"Error reading directory:", e} end
	table.sort(Files)
	MenuNumOpts[FileMenuID] = TableSize(Files)
	MenuTable[FileMenuID] = Files
end


-- Change to parent directory in file select.
function PrevDir()
	local Idx = FindLast(CurDir, "/")
	if Idx == #CurDir then
		Idx = FindLast(string.sub(CurDir, 1, #CurDir - 1), "/")
	end
	
	if Idx then
		SoundEffect_Replay(BackSound)
		CurDir = string.sub(CurDir, 1, Idx - 1)
		print(CurDir)
		if(string.sub(CurDir, -1) == ":") then CurDir = CurDir .. "/" end
		ReadCurDir()
	end
end


-- Open selected file in file select.
function OpenThisFile()
	if not Files[SelectedItem] then return end
	SoundEffect_Replay(ActivateSound)
	
	-- The kernel will puke with error 80010016 if there are any "//" in
	-- the path of a program we try to execute.
	File = string.gsub(CurDir .. Files[SelectedItem], "//+", "/")
	print("File: " .. File)
	
	-- If this is a directory, switch to it.
	if(string.sub(Files[SelectedItem], 1, 1) == '/') then
		CurDir = CurDir .. Files[SelectedItem] .. "/"
		Cursor = 0
		SelectedItem = 1
		ReadCurDir()
		return
	end
	
	
	Ext = string.lower(string.sub(File, -4))
	if Ext == ".pbp" or Ext == ".prx" then -- Program; launch it
		e = LaunchProgram(File)
		if not e == true then
			ShowError("Error " .. string.format("%X", e) .. " launching program")
		end
	
	elseif Ext == ".mp3" then -- Music; play it
		if Music then MP3_Stop(Music) end
		Music = nil -- delete so the MP3 player is shut down properly
		Music, e = LoadMP3File(File)
		if Music then
			MP3_Loop(Music, -1) --loop forever
			MP3_Play(Music)
		else ShowError(e)
		end
	end
end


-- Run selected program in app select.
function RunThisApp()
	SoundEffect_Replay(ActivateSound)
	e = LaunchProgram(AppBase .. Apps[Cursor + 1].dir .. AppExt)
	if not e == true then
		ShowError("Error " .. string.format("%X", e) ..
			" launching program " .. tostring(Apps[Cursor + 1].dir))
	end
end


-- Run selected program in built-in app select.
function RunThisBuiltinApp()
	SoundEffect_Replay(ActivateSound)
	Result, e = RunBuiltinApp(BuiltinApps[Cursor + 1].id)
	if not Result == true then
		ShowError(e)
	end
end
