Code archives/Graphics/MaxGUI graphics mode chooser

This code has been declared by its author to be Public Domain code.

Download source code

MaxGUI graphics mode chooser by WendellM2006
This is based on part of a series of modules that I use for my current game, but it should be useful as a stand-alone way for the player to select a graphics mode before starting any BlitzMax/MaxGUI program. I don't pretend that this is the best method, but since I didn't find a similar routine in the archives, I thought that I should perhaps offer this. Though it's a "module," it can be used just by having the .bmx file in the same folder as the calling program (or by including the code for the Type within another program).

As written, it restricts resolutions from a minimum of 800 x 600 to a maximum of 1600 x 1200, though you can specify different ones. Its 'recommended' settings are those with >= 1024 x 768 resolution, with >= 24-bit color, and with an aspect ratio around 4:3 (allowing for "not exactly 4:3, but close" modes like 1360 x 1024). You can also change those 'recommended' criteria if desired.

Sept. 5 '06 update: Defaults to OpenGL in OS X and Linux (thanks to Diordna for suggestion) and tweaks appearance on those platforms. Calling example in comments improved. Destroy function changed to work better.

Rem

	PreGame module by WendellM - released September 1, 2006, updated Sept. 5, 2006
	Allows choice of graphics driver, screen mode, and settings
	Saves config file to preserve choices for future use, but works without one
	Defaults to OpenGL without displaying choice in Linux & OS X
	
	Example of use within a calling program:
	
		Import "pregame.bmx"
		Local pre:TPregame
		
		' whenever you want to set graphics:
		pre = TPregame.Create()
		pre.UserChoice
		If pre.driver = "OpenGL" Then SetGraphicsDriver GLMax2DDriver()
		If pre.driver = "DirectX" Then SetGraphicsDriver D3D7Max2DDriver()
		If pre.screen = "Windowed" Then
			Graphics pre.width, pre.height
		Else
			Graphics pre.width, pre.height, pre.depth, pre.hertz
		EndIf
		' Save graphics settings here if desired.
		TPreGame.Destroy pre
		
		WaitKey
		
End Rem

Strict
TPreGame.Test ' <- Self-contained example of use. Uncomment to use, comment out to ignore.

Type TPreGame

	Field driver$, screen$, mode$
	Field width, height, depth, hertz
	Field preGame:TGadget
		Field pgPanelDriver:TGadget
			Field pgDriverDX:TGadget, pgDriverGL:TGadget
		Field pgPanelScreen:TGadget
			Field pgScreenFull:TGadget, pgScreenWindowed:TGadget
		Field pgPanelRes:TGadget
			Field pgMode:TGadget
		Field pgButtonOK:TGadget, pgButtonQuit:TGadget

	Function Create:TPreGame()
		Local t:TPreGame = New TPreGame
		Local dw = GadgetWidth( Desktop() )
		Local dh = GadgetHeight( Desktop() )
		Local w = 220
		Local h = 350
		Local in:TStream = ReadFile("graphics.dat")
		
		? MacOS
		w = 250
		?

		? Linux
		w = 250
		?
		
		If in Then
			t.driver = ReadLine(in)
			t.screen = ReadLine(in)
			t.mode = ReadLine(in)
			CloseFile in
		Else
			t.driver = "DirectX"
			t.screen = "Fullscreen"
			t.mode = "1024 x   768, 32-bit, 85 Hz *" ' try this as default if none other specified
		EndIf

		t.preGame = CreateWindow( "PreGame", (dw-w)/2,(dh-h)/2, w,h, Null, WINDOW_TITLEBAR )

		t.pgPanelDriver = CreatePanel( 10,10, w-25,47, t.preGame,PANEL_GROUP, "Driver" )
		t.pgDriverDX = CreateButton( "DirectX", 10,3, 80,19, t.pgPanelDriver, BUTTON_RADIO )
		t.pgDriverGL = CreateButton( "OpenGL", 100,3, 80,19, t.pgPanelDriver, BUTTON_RADIO )
		If t.Driver = "DirectX" Then
			SetButtonState t.pgDriverDX, True
		ElseIf t.Driver = "OpenGL" Then
			SetButtonState t.pgDriverGL, True
		Else
			SetButtonState t.pgDriverDX, True
		EndIf

		? Linux
		SetButtonState t.pgDriverGL, True
		HideGadget t.pgPanelDriver
		?
		
		? MacOS		
		SetButtonState t.pgDriverGL, True
		HideGadget t.pgPanelDriver
		?

		t.pgPanelScreen = CreatePanel( 10,65, w-25,47, t.preGame,PANEL_GROUP, "Screen Mode" )
		t.pgScreenFull = CreateButton( "Fullscreen", 10,3, 80,19, t.pgPanelScreen, BUTTON_RADIO )
		t.pgScreenWindowed = CreateButton( "Windowed", 100,3, 80,19, t.pgPanelScreen, BUTTON_RADIO )
		If t.Screen = "Fullscreen" Then
			SetButtonState t.pgScreenFull, True
		ElseIf t.Screen = "Windowed" Then
			SetButtonState t.pgScreenWindowed, True
		Else
			SetButtonState t.pgScreenFull, True		
		EndIf
		

		Local PanelResY = 120
		? Linux
			PanelResY = 150
		?

		t.pgPanelRes = CreatePanel( 10,PanelResY, w-25,70, t.preGame,PANEL_GROUP,..
			"Resolution, Color, Refresh" )
		
		CreateLabel "( * = recommended )", 10,0, w-52,15, t.pgPanelRes
		t.pgMode = CreateComboBox( 8,19, w-48, 23, t.pgPanelRes )
		Local List:TList = New TList
		Local numModes = CountGraphicsModes()
		Local index = 0, setIndex
		Local gw, ght, gd, ghz, rec$ ' graphic width, height, depth, hz, + recommended
		Local spcW$, spcH$
		Local selected  = False
		
		For Local x = 0 To numModes - 1
			GetGraphicsMode( x, gw, ght, gd, ghz )
			If gw < 1000 Then spcW = "  " Else spcW = "" ' for nice columns
			If ght < 1000 Then spcH = "  " Else spcH = ""
			' put recommendation asterisk if 1024x768 or better and near 4:3 (1.333) aspect ratio
			If gw >= 1024 And ght >= 768 And Float(gw) / ght > 1.3 And Float(gw) / ght < 1.3667 And ..
			  gd >= 24 Then rec = " *" Else rec = ""
			Local a$ = spcW + gw + " x " + spcH + ght + ", " + gd +"-bit, " + ghz + " Hz" + rec
			' don't display resolutions below 800x600 or above 1600x1200
			If gw >= 800 And gw <= 1600 And ght >= 600 And ght <= 1200 Then
				ListAddLast List, a
				AddGadgetItem t.pgMode, a
				If a = t.mode Then setIndex = index
				index :+ 1
			EndIf
		Next
		
		If setIndex Then
			SelectGadgetItem t.pgMode, setIndex
			selected = True
		EndIf
		
		If Not selected Then SelectGadgetItem t.pgMode, 0
		t.pgButtonOK = CreateButton( "OK", 20+(w-220)/2,289, 80,24, t.preGame, BUTTON_OK )
		t.pgButtonQuit = CreateButton( "Quit", 110+(w-220),289, 80,24, t.preGame )
		
		Return t
		
	End Function
	
	Function Destroy(t:TPreGame Var)
		FreeGadget t.preGame
		t = Null
		GCCollect
	End Function
	
	Method UserChoice:Int() ' updates driver, screen, width, height, depth, and hertz fields
		ActivateGadget pgButtonOK ' default focus
		Repeat
			WaitEvent
		Until ( EventID() = EVENT_WINDOWCLOSE And EventSource() = preGame ) or..
		      ( EventID() = EVENT_GADGETACTION And EventSource() = pgButtonOK ) or..
		      ( EventID() = EVENT_GADGETACTION And EventSource() = pgButtonQuit )
		If EventSource() = preGame Or EventSource() = pgButtonQuit Then End
		If EventSource() = pgButtonOK Then
			If ButtonState(pgDriverDX) Then Driver = "DirectX"
			If ButtonState(pgDriverGL) Then Driver = "OpenGL"
			If ButtonState(pgScreenFull) Then Screen = "Fullscreen"
			If ButtonState(pgScreenWindowed) Then Screen = "Windowed"
			mode = GadgetItemText( pgMode, SelectedGadgetItem(pgMode) ) ' same as: GadgetText(pgMode)
			width = Int(mode[0..5])
			height = Int(mode[7..13])
			Local comma = mode.find(",")
			depth = Int(mode[comma+2..comma+4])
			comma = mode.find(",", comma+3)
			hertz = Int(mode[comma+2..comma+4])
			Local out:TStream = WriteFile("graphics.dat")	
			WriteLine out, driver
			WriteLine out, screen
			WriteLine out, mode
			CloseFile out
			Return True
		EndIf
		Notify "Event handling exception in PreGame:UserChoice", True; End
	End Method

	Function Test()
		Local e:TPreGame = TPreGame.Create()
		If e.UserChoice() Then Notify e.driver +", "+ e.screen +", "+ ..
		                              e.width +","+ e.height +","+ e.depth +","+ e.hertz
		TPreGame.Destroy e
	End Function

End Type

Comments

Booticus2006
I said it before and I'll say it again: This is a great little nugget of elegance and ease of use. Exactly what I was after!


Pragun2006
Thanks buddy! I was thinking about making one of these for myself but no point in reinventing the wheel!


Code Archives Forum