Letterbox code + Alien Space Beetles Test

BlitzMax Forums/BlitzMax Programming/Letterbox code + Alien Space Beetles Test

sswift(Posted 2008) [#1]
The code I posted below allows you to easily design your game for one particular resolution and aspect ratio, but allow it to run in any.

It will both scale the graphics to fit higher or lower resolutions than your "virtual" resolution, and perform letterboxing for screens which have a different aspect ratio than the one the game was designed for.

In other words, using this code, you can design your game around am 800x500 virtual resolution (yes, 500), and a 16:10 aspect ratio (that of widescreen PC monitors). Then when your game is played at 1600x1200 on a 4:3 screen, the graphics will will fill the screen, and have black bars on the top and bottom to maintain the widescreen aspect ratio.

Or, when your game is played on a 1920x1080 16:9 screen like an HDTV, the sides of the screen will have black bars because that aspect ratio is wider than the one you specified.

You also don't have to design the game for a 16:10 aspect ratio, or for an 800xwhatever pixel resolution. You can design it around 1024x768 and a 4:3 aspect ratio if you want, and then on widescreen PC monitors you'll get those same black bars on the side as in the HDTV example above.

Alternatively, you can simply have the code stretch the graphics on screens which are too tall or wide, but based on all the complaints I got when I suggested that I might take that route for my game, that might not be the best idea.



And here is a new test of my Alien Space Beetles game.

http://raccoonrocket.com/blitz/asb-064.zip


It's actually game-like now, though enemies just spawn at random and few as of yet have any special behaviors.

Space switches backgrounds, PGUP/DN switch weapons. I think F toggles fullscreen/windowed, but I have not tested that in a long time and I think right now it just glitches and breaks the game. Mouse moves and fires.

The game will run at whatever your desktop resolution is set to, and should display black bars in any aspect ratio but 16:10, unless you're being funny and running your desktop at a resolution without square pixels, in which case the graphics might appear stretched... But then so would all your windows and games running in a window. So too bad. :-)

Anyway, please let me know if you're running in 4:3 or 5:4 and whether the black bars worked properly. They should, the code figures out everything with math, not with any table of resolutions, and I've tried forcing it to run in some weird resolutions and though it looks wrong on my screen when doing that, the black bars look like they're where they should be.


sswift(Posted 2008) [#2]
' ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
' This type allows you to make games that can run at any resolution.
' ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Type ProjectionMatrix
	
	Global _Width%				' The size of the screen, in BlitzMax coordinates. 
	Global _Height%				' Normally BlitzMax coordinates correspond 1:1 with pixels on the screen, but when you adjust the projection matrix, that relationship changes.
	
	Global _VirtualWidth%		' The size of the visible region in which gameplay takes place.  The area inside the letterbox.
	Global _VirtualHeight%


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function sets the scale of the projection matrix.
	'
	' If you simply wish your game to stretch vertically and horizontally to match the current resolution, and fill the screen, call this function with your desired "virtual" resolution.
	' Ie, if you want to build your game around an 800x600 resolution, then set Width and Height to 800,600.  If the game is then run at 1920x1200, it will be squashed vertically.
	'
	' If you want letterboxing however, call InitLetterbox() and then DrawLetterBox() every frame just before you flip.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function SetScale(Width%, Height%)
			
			_Width  = Width
			_Height = Height
			
			_VirtualWidth  = Width
			_VirtualHeight = Height
				
			?Win32

				Local D3D7Driver:TD3D7Max2DDriver = TD3D7Max2DDriver(_max2dDriver)
    
				If D3D7Driver
			
					Local Matrix#[] = [2.0/Width, 0.0, 0.0, 0.0,..
   		    	    			      0.0, -2.0/Height, 0.0, 0.0,..
       		    	      			  0.0, 0.0, 1.0, 0.0,..
           		    	  			  -1-(1.0/Width), 1+(1.0/Height), 1.0, 1.0]
    
				    D3D7Driver.device.SetTransform(D3DTS_PROJECTION, Matrix)

				Else
			? 
					' If on platform other than Win32, or using OpenGL run this code.
		
					glMatrixMode(GL_PROJECTION)
					glLoadIdentity()
    
					glortho(0, Width, Height, 0, 0, 1)
    
					glMatrixMode(GL_MODELVIEW)
					glLoadIdentity()
		
			?Win32

				EndIf
			?
		
		End Function


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function initializes the letterbox.
	'
	' Call it with the virtual resolution you want to use for your game after you have set the graphics mode, and then DrawLetterBox() every frame just before you flip.
	'
	' These functions will automatically handle both letterboxing on screens which are too tall, and pillarboxing on screens which are too wide.  So if you design your game for 800x600,
	' then InitLetterbox() will squash things horizontally to maintain the proper aspect ratio, and DrawLetterbox() will add black bars to the sides of the display for you.
	'
	' 
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function SetLetterbox(Width%, Height%)	

			Local NewWidth#, NewHeight#
						
			NewWidth#  = Width
			NewHeight# = Float(GraphicsHeight()) / (Float(GraphicsWidth()) / Float(Width))
		
			' If screen is wider than the desired apsect ratio...

				If NewHeight# < Height
				
					' Use pillarboxing instead of letterboxing.
										
						NewHeight# = Height
						NewWidth#  = Float(GraphicsWidth()) / (Float(GraphicsHeight())/Float(Height)) 	
				
				EndIf
			
			' Adjust the scale of the projection matrix to achieve the desired result.
				ProjectionMatrix.SetScale(NewWidth#, NewHeight#)
		
			' Store the size of the visible game region.
				_VirtualWidth  = Width
				_VirtualHeight = Height
	
		End Function 
		
		
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function draws black bars over the portions of the screen which are outside the gameplay area.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

		Function DrawLetterbox()
		
			Local Size%
			
			RenderState.Push()	
			
			If _VirtualHeight < _Height
				
				' Draw Letterbox.
				
					Size = (_Height-_VirtualHeight) / 2
				
					SetColor(0,0,0) 
							
					DrawRect(0,            0, _Width, Size)
					DrawRect(0, _Height-Size, _Width, Size)
					
			Else
				
				' Draw pillarbox.

					Size = (_Width-_VirtualWidth) / 2
				
					SetColor(0,0,0) 
							
					DrawRect(          0, 0, Size, _Height)
					DrawRect(_Width-Size, 0, Size, _Height)
				
			EndIf			
			
			RenderState.Pop() 	' Render push and pop simply resets the color and other display properties to whatever they were beforehand.  These two functions are in the code archives.
			
		End Function


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' These functions return the virtual width and height of the usuable region of the screen, inside any letterboxing.
	'
	' Basically, these functions are equivalent to GraphicsWidth() and GraphicsHeight() when using a projection matrix where coordinates don't match up 1:1 to pixels
	' and/or letterboxing is being used.
	'
	' These functions will not return useful values until either ProjectionMatrix.SetScale() is called, or ProjectonMatrix.SetLetterbox() is called!
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

		Function Width#()
			Return _VirtualWidth
		End Function
		
		Function Height#()
			Return _VirtualHeight
		End Function
		
	
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' These functions tell you where the center of the screen is when using letterboxing.  
	'
	' Note that they do not calculate this using the width and height of the visible area of the screen, but rather, the size of the whole screen including the letterboxed regions.
	' This is important, because if you draw objects using the size of the visible region only, they will be higher on the screen than they should be, or more to the left.
	'
	' In my games, what I do is create a pivot called Origin, and place it in the center of the screen, and attach all my sprites to that, so the only time I need to worry about where
	' the center of the screen really is is when I position that pivot initially. 
	'
	' Then when I've done that, the top of the screen is at -ProjectionMatrix.Height#()/2, half the height I passed to SetLetterbox(), and so on.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function CenterX#()
			Return _Width/2
		End Function
			
		Function CenterY#()
			Return _Height/2
		End Function
				
		
End Type



REDi(Posted 2008) [#3]
Run well @4:3 showing black bars top and bottom, ratio seems right to me and movement is nice and smooth. Pressing f does indeed mess things up, showing a black bar in the middle of the screen and all graphics are offset also.


sswift(Posted 2008) [#4]
I just tested it with my HDTV and it works there too, with the back bars on the sides.


Sledge(Posted 2008) [#5]
This seemed to work pretty well for me, Swifty, and sharing the code is very generous so thanks. I'm on a laptop with a 16:10 aspect ratio so on my first run it filled the screen nicely.

I took the resolution down a bit (1280*800 to 1280*768) and, right enough, I got some neat little bars down the sides of the screen and the image itself looked fine. Next I popped down to 800*600 and, this time, got bars at both the top and bottom -- the ones at the side being due to my gfx drivers being set to maintain the display's aspect ratio. So in that instance the entire display was bordered (aah, how I miss the Speccy!) but it looked perfectly scaled.

The only drawback I can see is that you can't tell whether the user's display is set to maintain aspect ratio or not, and if it isn't then you get an even more stretched display than usual! I guess your code could probably deal with that by letting the user toggle a setting -- even better if it could get the info from the gfx driver.

I like the assumption that the desktop is probably of a native resolution that is likely to suit the screen dimensions. It would worry me a bit that the desktop resolution might also be too high for the machine to comfortably handle for games though. (Not really sure what could be done about that.)

I don't want to sound too negative, mind -- I think this is a rather ace approach to a really thorny problem and I can see myself adopting it. Have a smiley. :D


sswift(Posted 2008) [#6]
Well I wanted to share it with more than just the users of my sprite system (which this code is now a part of) since it wouldn't be possible without the code someone else wrote to set the projection matrix.

As for displays where the user hasn't set the resolution so that it matches the display's aspect ratio, I'm not going to worry about those cases. I doubt more than a tiny percentage of users have their displays set that way, and if they do, then they're incapable of noticing that things are distorted, cause all the videos and photos they look at would already be messed up, so I doubt they'll complain. :-)


What concerns me more is casual gamers who are in the same demographic as people who buy fullscreen versions of DVD movies. They might assume something is wrong with the game, or simply prefer that it be distorted rather than having black bars.

But I really don't want to have to add interface crap just for changing whether it displays things with letterboxing, or stretches it. So I'm not going to bother, since this is the RIGHT way to handle things. :-)


JazzieB(Posted 2008) [#7]
It works a treat on my 4:3 system.

However, I would be a little concerned with using the same resolution as the desktop, as many people use a much higher desktop resolution than they do for games. Personally, I have my desktop set at 1600x1200, but would not currently consider going any higher than 1024x768 unless the games were a few years old and my newer system would be able to handle it. Of course, I am talking about games from the big publishers, but still.

What I do with my games now is to select a suitable resolution that matches the aspect ratio of the desktop, My current project has a target resolution of 640x480, which it selects on 4:3 displays, but selects 800x500 on a 16:10 display.

On an off-topic note, the sound lags on Vista, so you will need to change the default audio driver to OpenAL or DirectSound. I'm fairly sure I've mentioned this on a previous thread.

Other than that, it does look good and the higher res does make things look nice and smooth. The game seems to be coming on rather well as well.

Good job.


sswift(Posted 2008) [#8]
Oh one more thing...

I would like to know what people think of the scrolling/planets. Should I have just static backgrounds with planets, or should I include the scrolling as well, even though I don't have lots of cool stuff to have scroll by?


Grey Alien(Posted 2008) [#9]
Sounds like good work, I'll be checking this out soon.


Chroma(Posted 2008) [#10]
sswift, instead of just having your media free for the taking I'm sending you my zg1 encryption app. Give it a try and see if you like it.


MikeT(Posted 2008) [#11]
Works well on my system @1280x1024, the letter box works as expected. Regarding the scrolling/static issue i would be inclined to mix it up, have some static and some scrolling. Thats just my initial opinion though.

Hope this helps

Mike


sswift(Posted 2008) [#12]
I appreciate the offer, but why protect my media?

Have you ever seen someone steal the graphics from a shareware game and make another (successful) one with it? I haven't. If some kid wants to throw my art in some little shooter he's coding cause he doesn't have any art to use, I don't mind.

Plus it's too much of a bother to do convert the graphics every time I make a change and want to show people a build. I haven't even compressed the images or sound files yet. That will come when I finish the game. :-)


Sledge(Posted 2008) [#13]
I would like to know what people think of the scrolling/planets. Should I have just static backgrounds with planets, or should I include the scrolling as well, even though I don't have lots of cool stuff to have scroll by?

You're not going to like this: I think animated planets would be the most pleasing aesthetic. How busy and pervasive your background graphics can be, though, really depends on how frenetic the foreground action is. Without seeing more finalised gameplay it's hard to say what's appropriate.


sswift(Posted 2008) [#14]
I originally tried to make the planets animated, but too many frames were needed to get a smooth rotation. It would have made the game too big to download.

Also, I really don't think the planets need to be animated. I don't want the background to be too distracting.

The only reason I ask about the scrolling vs the non-scrolling is that when I toggle the levels between the two, it looks kinda weird to have it scroll after seeing it for a while without scrolling. It also looks kinda empty.


Sledge(Posted 2008) [#15]
Well you could use it transitionally -- say, complete a wave/level in front of a static planet, then the planet scrolls off and you're into a repeating starfield for the next wave, which takes place while you travel to... the next planet, where the scrolling pauses for another static wave. And so on.


sswift(Posted 2008) [#16]
Sledge:
Well, that was the plan actually. Or one of them anyway. Except the scrolling off the screen part. It was just going to scroll on, and then display a tally or whatever for the level and go to the next section.

Another plan I had would be to always show the planet but display it larger and larger as the player progressed through four or five "waves", and then have the boss battle when it was at maximum size. I had the artist create special art for the asteroid field to allow this to work for that since it would have required a really high res image otherwise.

I also tried having the planet sit in the middle of the screen, but keep the stars scrolling, as if the planet itself is moving through space, but that ended up giving me motion sickness, and I never get motion sickenss playing games. :-)

And the last plan I had was to simply have scrolling sections and then just transition to the still planet without scrolling it onto the screen. That being the easiest to code.


Sledge(Posted 2008) [#17]
How are you getting the desktop resolution, incidentally? MaxGUI?


sswift(Posted 2008) [#18]
Yep.

ClientWidth(Desktop()), ClientHeight(Desktop())


MGE(Posted 2008) [#19]
Hi sswift - The letter box code seems to work well. No problems found, thanks for sharing!

Re: Space Beetles Test

Your earlier demo rocked. Everything nice and smooth. This demo is really lacking in the frame rate/timing department. Very choppy. While I understand your line of thinking, you may want to have options for lower res full screen/windowed modes as well where you can get a better render speed and hopefully a more constant frame rate. With 2D games, especially shooters, I think it's better to have code that is aware of the choppiness and try to compensate for that by locking into a averaged frame rate. It's better to play a game at a constant 20fps, then to have it fluctuate from 15,20,30,60,30,15, etc, etc. IMHO. ;)

Now if I was coding a puzzle type game, then 100% I would go with your line of thinking of just running it in the desktop mode and be done with it. ;)


sswift(Posted 2008) [#20]
MGE:
What res are you running your desktop at, and what kind of video card do you have?


Grey Alien(Posted 2008) [#21]
Works well here on my 4:3 CRT, black bars at top and bottom. Hey the game has come a long way since I last checked, nice one.

Oh, btw, I agree with your view on protecting the media, it's too much hassle and if anyone actually tried to use it commercially they wouldn't have a leg to stand on in court, so they just wouldn't bother.


MGE(Posted 2008) [#22]
sswift: 1152x864x32, Onboard Intel Extreme Graphics. It's the same system I develop on. Runs my stuff fine, Grey's stuff fine, etc. Obviously there isn't alot you can do about the render speed when going with the default desktop resolution.

For the amount of sprites, background, bars, etc, that you're rendering every frame, your render speed is typical for my box. That's not the problem I'm seeing. What is a problem to my eyes at least is the jitterness, chopiness of the sprite movement.

I just ran it again with Fraps on and the frame rate flucuates between 15-30fps. This combined with your timing code could be the problem. The only solution I would offer in this scenario when the frame rate is lower than expected, is to monitor the frame rate for a while and then lock the frame rate at the average speed. This will give the user a much more statisfying experience in my opinion because the visual timing, etc, will be much more consistant. This is vital in a 2D shooter. I think 2D shooters should run at the fastest constant speed they are capable of.

re: Protected media. Keep in mind, I've seen "free" games use stolen media. It's a very grey area. Then you have coders that write these free games using stolen media and they make money by including advertising, etc, in their distributions. errr..


popcade(Posted 2008) [#23]
That reminds me saw many free games rip sprites from protected game like StarCraft, or rip some casual games like Zuma, if you want to play em simply google some freegame sites.

Benefit of pack the media is to reduce obsolete files.... I know some guy very skillful on extract medias, I hate them, but I can do nothing against them(hint: google and see the bloody truth).

Back to the topic, the rendersing speed is decided by the desktop, if it's possible to enum available resolutions and let the player to choose, should be better.


Grey Alien(Posted 2008) [#24]
I used to rip stuff out of Amiga games when I was a kid (pictures, music modules, samples etc) and so did lots of other people, but they never made it into any commercial titles of course.


MGE(Posted 2008) [#25]
"the rendersing speed is decided by the desktop"

Oh that's quite inaccurate. Your desktop may have a 60hz refresh rate but your game loop may be updating only 20 times per second due to cpu/gpu requirements.


sswift(Posted 2008) [#26]
MGE:
I created a special framerate smoothing algorithm a while back which worked great, but didn't make my game appear to run any smoother on my system. But the game was already running at a very high framerate on my system so the fluctuations might have been tiny.

I'll try re-implementing that code and upload a new version tonight, and hopefully it will make it run better for you.

It's not as simple as just calculating the average speed and running at that because the framerate could drop at any time. So what my code did, if I remmeber correctly, is allow the framerate to drop instantly, and then climb back up over the next few frames if the framrate goes back up. So basically what it did was it would run at whatever the lowest framerate of the last five or so frames was, and keep checking to see if it could step the framerate up a bit.


sswift(Posted 2008) [#27]
MGE:

What yoko said was:
"Back to the topic, the rendersing speed is decided by the desktop"

By which he meant:
"Back to the topic: 'your game running at the desktop resolution'... if it's possible to enum available resolutions and let the player to choose, should be better."

He was just saying he thinks I should let the player choose the resolution. Which I would rather not do because it means creating windows dialogs to choose it and casual gamers don't understand all that crap, so they won't even get that lowering the res will make it run faster.

Hopefully this change I will make will allow the game to run on those built in graphics chips more smoothly.


Gabriel(Posted 2008) [#28]
I tested it at 1280x1024 ( which is 5:4 ) and it was absolutely perfect. It's very generous of you to share the code and I hope plenty of people use it because it's going to help them a lot in the long run.


MGE(Posted 2008) [#29]
sswift: yoko: oh! Sorry! I agree that you should allow the end user to select a lower res, windowed or full screen. That would potentially allow the game to run at full refresh rate at lower resolutions.

sswift: "I created a special framerate smoothing algorithm a while back which worked great, but didn't make my game appear to run any smoother on my system. But the game was already running at a very high framerate on my system so the fluctuations might have been tiny."

Ah, well there you go. Developing on a low end system like I do allows you to see every jitter, system hiccup, etc, as they occur. ;) I agree the smoothing algo's don't do diddly when the game runs at full refresh rate. They really only come into play when you start missing vblanks, etc, etc.

"It's not as simple as just calculating the average speed and running at that because the framerate could drop at any time."

One thing I'm going to do if/when I release a Blitzmax game is, when the game first runs, you could say "calibrating the graphics" and throw about as many sprites on the screen as your game would ever do, run the loop for about 10-20 seconds or so, then throttle the game so it never runs faster than the calculated result. That combined with jitter code control should provide the best case scenario for your game.


sswift(Posted 2008) [#30]
MGE, and anyone else who has a slow video card:

Try sticking this exe into the game directory and running it instead, and tell me if this makes things smoother for you. It should, I let tons of aliens spawn on my system till the FPS dropped to 16, and I could see it was smoothing things out for me.

http://raccoonrocket.com/blitz/main-065.exe

If you hold TAB you can see the framerate, and if you hold S then the game will run as it did before, without any framerate limiting, other than waitng for the vertical refresh which generally keeps it around 60fps on faster systems. Also if you hold S while holding tab, then you should see the numbers fluctuate more.

This is the code which performs the magic:

	' Smooth out framerate.
				
				If Not KeyDown(KEY_S)
				
					' Find the longest amount of time a frame took to render over the last few frames.	
								
						Max_FrameTime = 0
						For Frame = 0 To Frames-1
							If FrameTime[Frame] > Max_FrameTime Then Max_FrameTime = FrameTime[Frame]
						Next
					
					' Shift all times toward the end of the array by one to free up the first slot for a new time.
						
						For Frame = Frames-1 To 1 Step -1
							FrameTime[Frame] = FrameTime[Frame-1]
						Next					
					
					' Resize the array to have 1/8 as many elements as we are rendering frames per second.
					
						' The reason we do this is so that no matter what the framerate is, the system will adjust to big changes in framerate within 1/8
						' of a second.  The response time is only a concern so far as the system would render at a lower framerate for longer than it
						' really needs to.
					
						If Max_FrameTime > 0 Then Frames = Floor((1000.0 / Max_FrameTime) / 8.0)
						If Frames = 0 Then Frames = 1
										
						FrameTime = FrameTime[..Frames]						
					
					' Calculate how long this frame took to render.
						Time_Delta = MilliSecs()-System_Time
					
					' Add this frame's time to the start of the array.
						FrameTime[0] = Time_Delta
				
					' Delay this frame to make it last as long as the longest frame in our timeframe.
						If Max_FrameTime < 70
							While Time_Delta < Max_FrameTime
								Time_Delta = MilliSecs()-System_Time
							Wend
						EndIf
						
				EndIf



MGE(Posted 2008) [#31]
sswift: I've been a/b'ing the 2 versions and it's hard to tell the difference. But it does appear the updated version is a little more constant. The fps report still fluctates alot.

If you don't mind me asking, how are you rendering your sprites? (custom render, built in image functions, etc.)


sswift(Posted 2008) [#32]
MGE:
The built in image functions. And I hope you weren't trying to compare the two by running this exe and the old one. As I said, if you just hold down S, it will render using the old method instead. Much easier to compare that way.

I guess I'll try hooking my laptop up and try running it on that and see how well it works there.


MGE(Posted 2008) [#33]
sswift: I did a reboot to make sure everything was in order and re-did the tests. The 2nd version has a more consistant frame rate. This version feels alot better to play. So your smoothing code seems to be working well. I also played the game using a desktop of 800x600x32 and the game ran at 50-60fps (just like your older full screen demos ran), so perhaps adding an option for a lower res full screen mode is worth while?

re: Rendering your sprites with the built in image functions. I did alot of tests a few months back, when running on decent gpus' the builit in image functions are fine, plenty fast. But on less powered gpu's like the onbaord intels, switching over to a system where all the sprites are rendered off a single texture, made a huge difference. But to be honest, in 2008 and beyond, it's becoming less and less a problem. ;)


sswift(Posted 2008) [#34]
With the number of frames my sprite have, it wouldn't make sense to put them in a single texture. If you assume people have crappy video hardware, and need that, you must also assume their crappy video hardware won't support big textures.

Anyway, I'm glad it's running well for you now.

Unfortunately for me, my $600 laptop, the cheapest one I could find last year, is just too awesome, and has a Radeon chipset in it. So it runs the game at 30fps easily. And if I turn on full screen antialiasing and anistropic filtering, the framerate drops to 15fps, but everything still looks smooth enough, regardless of which method I use to time it.

So right now, I'm not seeing any choppiness and I can't improve my algorithm if I can't see what's going wrong.

But I'm glad you think the new version runs smoother. I know it does on my PC when I have hundreds of enemies on screen causing the framerate to fluctuate a lot. But I can't imagine that anyone would have massive fluctuations like that on any normal system under normal game conditions. Regardless though, the new algorithm smooths that right out, so I guess I needen't worry about it any more for now.


sswift(Posted 2008) [#35]
Oh, and even though I do not currently plan to support switching resolutions and all the issues that brings up, like needing external programs to allow the user to reset it if there's any problems and having to make dialog boxes for setting it up, I do plan to fix the windowed mode which is currently broken, and since that will run at something like 800x500, if a user does find that fullscreen is too choppy, they can always fall back to windowed mode.


MGE(Posted 2008) [#36]
The Radeon chipset is miles above the onboard intel's. ;) If your game's virtual res is 800x500, then I would at least add some kind of support for a full screen 800x600 mode. Otherwise running full screen @ desktop res or windowed at virtual res seems like a very smart thing to do. ;) Good luck with the game!


sswift(Posted 2008) [#37]
How old is your PC anyway that you have only onboard video, and it's an Intel chipset?


MGE(Posted 2008) [#38]
This is my dev system:
Hewlett Packard Celeron CPU 2.93Ghz
512k Ram
Intel Extreme Graphics 82845G/GL/GE/PE/GV Graphics Controller
Brand new in 2005

It runs Blitzmax games faster than my daughter's brand spanking new Vista Laptop. Go figure on that one. ;) If you research this controller you'll find out it's installed in alot of computers.


popcade(Posted 2008) [#39]
My spec is

Celeron 1.2G
512MB Ram
GeForce FX5200

Thechically ways much slower than MGE's system, but I can run sswift's example at 60 FPS, I want to know what happended to MGE's PC.

Another test on a crap Office PC still has 60fps, if MGE's problem was not hardware thing I have many interest to find out the myth.


MGE(Posted 2008) [#40]
I have a GeForce FX5200 in one of my older test PC's. I LOVE that card. Runs everything I throw at very smoothly. I don't dev on it because I'm afraid of being too spoiled. :) As for the "myth" comment (wtf?), I suggest you research the older onboard Intel GPU (shared memory) chipsets. CPU speed is fairly irrelevent when it comes to rendering graphics. For the hell of it, I just ran the latest ASB test on my old(er) 600mhz CPU with a TNT2 GPU and it ran at 60fps in 800x600x32 mode. ;)


Gabriel(Posted 2008) [#41]
As for the "myth" comment (wtf?)

From memory, I'm pretty sure that English is not Yoko's first language. ( IIRC his website is .tw which I guess is Taiwan? )
In which case I think he probably meant mystery.


Chroma(Posted 2008) [#42]
Oh, btw, I agree with your view on protecting the media, it's too much hassle and if anyone actually tried to use it commercially they wouldn't have a leg to stand on in court, so they just wouldn't bother.
Lol GA, like you or sswift have the money to actually take someone to a lengthy court battle (you plan on them not bothering to take the media just like they plan you on not having the money to sue them...). And, I'm guessing this code will show up in your framework soon if history repeats itself hehe. :)

Now back to the meaningful side of life. This code is really nice. With the resolution set to 1280x1024 and virtual to 800x600 I get the bars at the top and bottom. I'll definitely be using this thanks. And I guess it pretty much solves the widescreen and horrible 800x600 problem eh?


Chroma(Posted 2008) [#43]
Hmm...I'm setting the graphics to 1280x1024 and virtual to 800x600 and SetLetterBox to 800x600 and I draw a 5x5 DrawRect at 0,0 and I can't see it...

So I guess a
SetOrigin ProjectionMatrix.CenterX()-(ProjectionMatrix.Width()/2), ProjectionMatrix.CenterY()-(ProjectionMatrix.Height()/2)
would be appropriate.


sswift(Posted 2008) [#44]
Of course you can't see it. 0,0 is in the letterbox region. :-)

When you use this code the center of the screen is at ProjectionMatrix.CenterX(), ProjectionMatrix.CenterY()

If you subtract half the virtual height and half the virtual width from those values, then that will tell you where the top right corner of the visible region is.

In my games, I just stick a pivot at the center location, and I position everything relative to that, so using -250 for my Y coordinate would give me the top of the screen, and 0,0 would be in the center.

Attaching everything to a pivot allows me to do screen shake effects easily, and makes it less of a pain in the ass to fix things if I decide to change resolutions, or do stuff like this with the letterboxing.

But you don't need to use a pivot if you don't want to. You do however need to know how much you need to offset your objects for a given resolution, and that would be CenterX()-_VirtualWidth/2, CenterY()-_VirtualHeight/2. Add that to the coordinates of everything in your game, and you can use 0,0 as the upper left corner of the visual region.

There's no way to fix this, because it's Max's coordinate system.


sswift(Posted 2008) [#45]
Yoko:
The Geforce is a much better and faster graphics chip than the Intel that MGE has. That is why the game runs smoothly for you, but not for him.

The CPU speed does not matter a whole lot.


sswift(Posted 2008) [#46]
Chroma:
If you use SetOrigin, then the code to draw the rects for the letteboxing will draw them in the wrong location. So you will need to SetOrigin in that part of the code back to 0,0. I think RenderState.Push() and Pop() will then reset that back to whatever you had it set to in your main program, unless I forgot to include that in the functions.


Chroma(Posted 2008) [#47]
If you do a :
SetOrigin ProjMatrix.CenterX()-ProjMatrix.Width()/2, ProjMatrix.CenterY()-ProjMatrix.Height()/2

at the beginning of the loop and a
SetOrigin 0,0
right before the
ProjMatrix.DrawLetterBox()
that seems to work also. I'm not sure what kind of performance hit if any but it makes it really simple to place your objects on the normal 0-800 and 0-600 coordinates.


sswift(Posted 2008) [#48]
I doubt there's any performance hit for doing that. And that's basically what the modification I suggested would do.


Chroma(Posted 2008) [#49]
The GetOrigin and SetOrigin are in the Push and Pop fuctions. If you could alter it so it would set the origin so you could use normal 0-graphics width etc instead of doing the centerX-virtualwidth/2 way I think it'd be much more intuitive and also keep a lot of people from redoing their position code. They could just leave it as is. It'd be more of a 'drop-in' solution.

You could use set origin to do camera shake too I imagine. I haven't really had a need to do that though so I haven't really thought about it.

EDIT: So basically at the Push you SetOrigin to 0,0 and at the Pop SetOrigin to the centerX blah blah. Already changed mine and lovin' it.

Ater you create the ProjectionMatrix and LetterBox add this line:
SetOrigin ProjMatrix.CenterX()-ProjMatrix.Width()/2, ProjMatrix.CenterY()-ProjMatrix.Height()/2

and find this line in your Push Function:
GetOrigin(RS.Origin_X#, RS.Origin_Y#)
and change it to:
GetOrigin(RS.Origin_X#, RS.Origin_Y#) ; SetOrigin 0,0
Wa la!


sswift(Posted 2008) [#50]
I suppose I could do that. Will work just as well in my own game. But what if people are using SetOrigin to do their own screen shake effects? Then the code would interfere with that.


sswift(Posted 2008) [#51]
"So basically at the Push you SetOrigin to 0,0 and at the Pop SetOrigin to the centerX blah blah. Already changed mine and lovin' it."


Um, if you're talking about the suggestion I made, what you would actually do is SetOrigin to the centerX in your code, and then in my function after the Push, SetOrigin to 0,0. Then the push stores the CenterX origin, and the Pop restores it automatically once the letterbox is done drawing. That's what Push and Pop are for. They let you modify render settings in a function and then restore them to what they were when you exit the function, so you don't screw up any other code which expects them to not have changed.


Chroma(Posted 2008) [#52]
If you change the code to mirror my above post, it's lets you use regular coordinates that range from 0 to your virtual width. That's all I was suggesting a few posts up. I really hate the thought of the center screen being 0,0. It's just more intiutive to me to have the upper left be 0,0 I guess. To be honest, that's how I expected the code to work in the first place and I was kinda puzzled that it didn't.

Plus by doing it that way you don't have to rewrite all your positioning points etc.

I can see what you mean about the SetOrigin being a problem for people using it for screenshaking effects. You 'could' attach a shakex and shakey field to your sprite type to take care of that problem though.


sswift(Posted 2008) [#53]
Chroma:
Sure, it's more intuitive initially, but when you start attaching one object to another, and moving an object in the space of the another object, and using the space of an object to determine where other objects are relative to that object... It just makes sense to make the center of the screen be the origin, because it's more consistent.

The center of a parent is its origin, and since the screen is a parent of all the objects in my game because they're attached to my origin pivot for screen shaking, it makes sense to treat it the same way.

It also makes certain calculations easier. For example:

-400+64 = 64 pixels in from the left side of the screen. 400-64 = 64 pixels in from the right side of the screen.

And the sign of the X and Y coordinate of an object tells you the quadrant of the screen the object is in. I use this in my game to decide which direction powerups should go in when they fly out of the top of an enemy, so that they're onscreen for as long as possible, allowing the player time enough to catch them, rather than leaving the screen almost immediately.

Once you use it for a little while it's not really any more difficult to conceptualize.


Chroma(Posted 2008) [#54]
Right, I guess it also depends on what kind of game you're making too. As for me it's a slow paced clicker so the position of 0,0 is irrelevant. An asteroids type shooter where the ship starts at the center of the screen etc then yeah I can see what you mean.
Either way, the code rocks and thanks for sharing.


MGE(Posted 2008) [#55]
I do alot of tile map rendering with layers, sprites with layers, etc, etc, makes sense to have 0,0 reference the top left pixel of your game screen. I will make the mod to add this to the code. Thanks sswift and Chroma!


MGE(Posted 2008) [#56]
Chroma - I'm doing sumpin wrong, could you please outline in detail what mods to make to the initially posted proj code and the push/pop routines to make it work so everything is referenced at 0,0? Thanks!


Chroma(Posted 2008) [#57]
Sure np. Here's the code with the Push and Pop from the archives and also with the changes to make 0,0 at the upper left.

I am really diggin' this code btw. I can't wait to try it on my widescreen monitor but it's on its way to Korea (and so am I in another week).




MGE(Posted 2008) [#58]
Chroma: Seems to be working well. Thanks! Any quick addition to convert mousex(),mousey() to virtualmousex(),virtualmousey() ? Sorry if it's obvious, I'm working on an all nighter here. lol.. ;)


Chroma(Posted 2008) [#59]
Ah good idea. I didn't even think of that heh.


Chroma(Posted 2008) [#60]
Here's a kludged fix for it. There's probably a more accurate way to do this though. With this method, sometimes 2 pixels are represented as 1 due to the scaling. I'm not sure if there's a way around that though.




Chroma(Posted 2008) [#61]
sswift, if 2 pixels can represent 1 coordinate using this method, what's keeping it from adding jerkiness to the movement?


sswift(Posted 2008) [#62]

and find this line in your Push Function:

GetOrigin(RS.Origin_X#, RS.Origin_Y#)

and change it to:

GetOrigin(RS.Origin_X#, RS.Origin_Y#) ; SetOrigin 0,0

Wa la!




Whaaaat? You shouldn't do that! That defeats the whole purpouse of the Push and Pop functions.

Push pushes the current state onto the stack.
Pop pops that state back off the stack.

If push stores the current origin, and then sets the origin to 0,0, then if you use Push in any other functions in your game before doing some operation that you want to undo once the operation is over with, then during that function the origin will be set to 0,0. But since you are doing this speciifcally because you DON'T want the origin to be at 0,0, this change would force you to set the origin after every operation you do that changes any graphics state where you might want to use push and pop to save and restore the state.

In other words, you've made a modification to those functions which makes them useless for any other purpouse, and you might as well just delete the calls to them from the original functions and delete those functions, and just reset the color to 255,255,255 after the lettterbox function or whatever you want it set to.

You should just make the change I suggested. Put a SetOrigin 0,0 in my letterbox function after the call to Push. Then put a setorigin which sets the origin however you want it somewhere in your code after you set the graphics mode. Doesn't need to be called over and over in the main loop. That's all you need to do to make it work, and you'll still be able to use the push and pop functions elsewhere in your code without issues.


Chroma(Posted 2008) [#63]
Ok sounds good. I made the changes.
Doesn't need to be called over and over in the main loop.
Nope, never called it over and over.

But what about the mouse scaling problem? How are you handling getting MouseX() and MouseY() that correspond to your virtual width and height?


sswift(Posted 2008) [#64]
"sswift, if 2 pixels can represent 1 coordinate using this method, what's keeping it from adding jerkiness to the movement?"

Everything is drawn using floating point values. So let's say my game's virtual resolution is 800x500. If the screen's resolution is 1600x1000, then that means that 0..0.5 in virtual coordinates maps to 0..1 on the real screen, and 0.5..1 in virtual coordinates maps to 1..2 on the real screen. So in this setup, half a virtual pixel maps to one whole pixel on the real screen. And one whole virtual pixel is represented with two pixels on the real screen.

If you were to move an object horizontally in whole virtual pixel increments, then it would move two pixels on the real screen. However, that only applies to a resolution where the ratio is 2:1. That's not likely to be the case most of the time. In that case, if you move the object whole virtual pixels, then sometimes it will be drawn pixel aligned at the true resolution, and sometimes it will be drawn misaligned with each pixel of the texture halfway under one screen pixel, and halfway under another. The 3D card would use the mipmaps to filter the pixel in that case, and the object might appear blurrier depending on just how high res it was in the first place.

What I'm trying to say, in as simple terms as I can muster, is that the sprites are filtered when they're drawn, so when they're halfway under a pixel they're drawn as if they're halfway under a pixel, they're not shifted to a whole pixel boundary. Also BlitzMax supports floating point coordinates for drawing images, and I draw and move all my sprites using floating point coordinates, so even when I was making the game specifically for 800x600 res, the sprite would still be drawn halfway under a pixel much of the time. That's how 3D games work, and while it does make the graphics a little blurrier, the movement looks smoother.

In short, it's not an issue. And when you're trying to calculate the mouse coordinates, if you're scaling 1024x768 to 800x600, yes, if you round everything to integers some mouse coordinates will share the same virtual pixel coordinate, but if you don't use integers then every pixel will map to a unique virtual location, which won't neccessarily be pixel aligned. But if you draw your mouse cursor using floating point coordinates, it will draw right where it should draw, halfway over a pixel if need be, so you won't see any issues.

I hope that explains things. This sort of code isn't intended for applications like a paint program where pixel perfect accuracy for everything is desirable. :-)


Chroma(Posted 2008) [#65]
Great, but are you using the same method I posted above for getting the virtual MouseX() and MouseY()?


sswift(Posted 2008) [#66]
As for:

How are you handling getting MouseX() and MouseY() that correspond to your virtual width and height?


I'm not. I didn't even consider whether there would be issues with MouseX() and MouseY(). My code just worked when I plugged this in, because I simply subtract the last mouse position from the current position to get the mouse speed, and then use the mouse speed to adjust the velocity of my ship in each direction. (The ship's controlled with physics, not directly by the mouse, so it has a little bit of inertia. It would feel like a mouse pointer otherwise.)

Which does answer something I'd been wondering about... Whether the mouse moved faster on higher resolution screens so that the distance it moved on the screen was constant regardless of the resolution. Apparently it does not, and instead moves at a constant rate in pixels... controlled only by the mouse cursor speed slider in windows. So identical mouse cursor speeds would move the mouse a shorter distance on the screen on identically sized screens with one being set to a higher resolution than the other. For me, that works out great, but for some kinds of games, I guess that could be an issue, but I can't think of which sorts.

Anyway... You're probably wondering how I'd fix the problem of moving the mouse about on the screen if I wanted a mouse pointer.

This is how I handle the mouse in my code:

' -----------------------------------------------------------------------------------------------------------------------------------------------------------
' These functions override the standard mouse visibility functions so that we can keep track of the mouse visible state.
'
' For ShowMouse:
'
' If Force% is False, then the mouse will not be shown if the current state indicates it is visible.  This is to avoid mouse flicker which is caused by
' showing the mouse over and over.
'
' If Force% is True, the mouse is shown regardless of what state MouseVisible indicates it is in.  This is used during fullscreen/window mode switches where
' the mouse is hidden by the system automatically.
' -----------------------------------------------------------------------------------------------------------------------------------------------------------

	Global MouseDown_Left%, MouseDown_Right%, MouseDown_Middle%
	Global MouseHit_Left%, MouseHit_Right%, MouseHit_Middle%
	Global Mouse_X#, Mouse_Y#
	Global Old_Mouse_X# = MouseX()
	Global Old_Mouse_Y# = MouseY()
	Global Mouse_Speed_X#, Mouse_Speed_Y#
	Global MouseVisible% = True
	Global Mouse_ForceRecenter% 


	Function ShowMouse(Force%=False)
		If (MouseVisible = False) Or (Force = True)
			MouseVisible = True
			Brl.System.ShowMouse()
		EndIf
	End Function

	
	Function HideMouse()
		MouseVisible = False
		Brl.System.HideMouse()	
	End Function
	
	
	Function AutoRecenterMouse(Recenter%=False) 
		
		Mouse_ForceRecenter = Recenter
		
		Select Recenter
		
			Case True  
				HideMouse()
				MoveMouse App.Width/2, App.Height/2
				
			Case False 
				ShowMouse()
			
		End Select
		
	End Function
	
	
' -----------------------------------------------------------------------------------------------------------------------------------------------------------
' This function gets the mouse input for this frame.
' -----------------------------------------------------------------------------------------------------------------------------------------------------------

	Function UpdateMouse()								
		
		Const SAFEZONE_RADIUS# = 100		
				
		Mouse_X# = MouseX()
		Mouse_Y# = MouseY()
			
		Mouse_Speed_X# = Mouse_X# - Old_Mouse_X#
		Mouse_Speed_Y# = Mouse_Y# - Old_Mouse_Y#

		MouseDown_Left   = MouseDown(1)
		MouseDown_Right  = MouseDown(2)
		MouseDown_Middle = MouseDown(3)	
				
		MouseHit_Left    = MouseHit(1)
		MouseHit_Right   = MouseHit(2)
		MouseHit_Middle  = MouseHit(3)
		
		' Recenter mouse if desired.
		' Recentering the mouse allows Mouse_Speed to work consistently.

			If Mouse_ForceRecenter 
				
				If (Abs(App.Width/2 - Mouse_X#) > SAFEZONE_RADIUS#) Or (Abs(App.Height/2 - Mouse_Y#) > SAFEZONE_RADIUS#)
			
					MoveMouse App.Width/2, App.Height/2
				
					Old_Mouse_X# = App.Width/2  - Mouse_Speed_X#
					Old_Mouse_Y# = App.Height/2 - Mouse_Speed_Y#
					
				Else
				
					Old_Mouse_X# = Mouse_X#
					Old_Mouse_Y# = Mouse_Y#
									
				EndIf			
				
			EndIf
	
	End Function


' -----------------------------------------------------------------------------------------------------------------------------------------------------------
' This function checks for events in the event queue and acts upon them.
' -----------------------------------------------------------------------------------------------------------------------------------------------------------

	Function EventHandler()

		MouseHit_Left   = False
		MouseHit_Right  = False
		MouseHit_Middle = False

		While PollEvent() <> 0
		
			'DebugLog("EventID: " + EventID())
			'If Scoreboard.TEXT_AngerMeter <> Null 
			'	If EventID() <= 258 Then Scoreboard.TEXT_AngerMeter.Set(EventID()) 
			'EndIf
			
			Select EventID()
					
				Case EVENT_APPSUSPEND 		' Application suspended. Triggered when window is minimized.
					
					' Pause music.
						If Sound.MusicChannel <> Null Then Sound.MusicChannel.SetPaused(True)
				
				
				Case EVENT_APPRESUME  		' Application resumed.
				
					' Resume music.
						If Sound.MusicChannel <> Null Then Sound.MusicChannel.SetPaused(False)
				
				 
				Case EVENT_APPTERMINATE 	' Application wants to terminate. 
				Case EVENT_KEYDOWN 			' Key pressed. Event data contains keycode. 
				Case EVENT_KEYUP 			' Key released. Event data contains keycode. 
				Case EVENT_KEYCHAR 			' Key character. Event data contains unicode value. 
				
				Case EVENT_MOUSEDOWN 		' Mouse button pressed. Event data contains mouse button code.
				
					Select EventData()
					
						Case 1 
							MouseDown_Left   = True
							MouseHit_Left    = True
							
						Case 2 
							MouseDown_Right  = True
							MouseHit_Right   = True
							
						Case 3 
							MouseDown_Middle = True
							MouseHit_Right   = True
							
					End Select
					
					
				Case EVENT_MOUSEUP 			' Mouse button released. Event data contains mouse button code. 
				
					Select EventData()
						Case 1 	MouseDown_Left   = False
						Case 2 	MouseDown_Right  = False
						Case 3 	MouseDown_Middle = False
					End Select
				
				
				Case EVENT_MOUSEMOVE 		' Mouse moved. Event x and y contain mouse coordinates.
				
					Mouse_X = EventX()
					Mouse_Y = EventY()
				
						 
				Case EVENT_MOUSEWHEEL 		' Mouse wheel spun. Event data contains delta clicks. 
				Case EVENT_MOUSEENTER 		' Mouse entered gadget area. 
				Case EVENT_MOUSELEAVE 		' Mouse left gadget area. 
				Case EVENT_TIMERTICK 		' Timer ticked. Event source contains timer object. 
				Case EVENT_HOTKEYHIT 		' Hot key hit. Event data and mods contains hotkey keycode and modifier.
				Case EVENT_MENUACTION 		' Menu has been selected. 
				Case EVENT_WINDOWMOVE 		' Window has been moved. 
				Case EVENT_WINDOWSIZE 		' Window has been resized.
				 
				Case EVENT_WINDOWCLOSE 		' Window close icon clicked. 
					End
					
				Case EVENT_WINDOWACTIVATE	' Window activated. 
				Case EVENT_WINDOWACCEPT 	' Drag and drop operation was attempted. 
				Case EVENT_GADGETACTION 	' Gadget state has been updated. 
				Case EVENT_GADGETPAINT 		' A canvas gadget needs to be redrawn. 
				Case EVENT_GADGETSELECT		' A treeview node has been selected. 
				Case EVENT_GADGETMENU 		' User has right clicked a treeview node or textarea gadget. 
				Case EVENT_GADGETOPEN 		' A treeview node has been expanded. 
				Case EVENT_GADGETCLOSE 		' A treeview node has been collapsed. 
				Case EVENT_GADGETDONE 		' An HTMLview has completed loading a page. 

			End Select

		Wend

	End Function



As you can see the Mouse_X and Mouse_Y variables I grab are just the raw coordinates. But to solve this issue, what you could do is change where the Mouse_X and Y are being stored, and then use the mouse speed calculated each frame to output a virtualizedMouse_X and Mouse_Y. In other words, change all the Mouse_X and Mouse_Y references in that code to New_Mouse_X, New_Mouse_Y and then add Mouse_Speed_X to Mouse_X each frame to calculate that instead of returning the true coordinate, making sure to truncate Mouse_X if it goes below 0 or above the virtual graphics width.

Not a particularly pretty solution, but if just scaling MouseX() and MouseY() doesn't give you the results you were looking for, then this will. The only issue might be that the user's mouse might move faster than they're used to if your virtual coordinates are less than the real resolution, because now you move the mouse 5 pixels in virtual space, and it moves 10 pixels on the screen, whereas before the mouse was 1:1 with the onscreen pixels.

So, if the user has 1600x1200 res, and the game has 800x600 virtual res, then moving the mouse 0.5 pixels in virtual space for every 1 pixel it actually moves would be a good thing if you want to keep the mouse speed consistent with what the user expects. And to do this you just scale the mouse coordinates. But if you want the mouse to move pixel perfect on an 800x600 virtual screen, then make those modifcations to my code I suggested, but keep in mind the mouse will move at half the speed the user expects.

I reccomend just scaling the position personally, and drawing stuff at floating point coordinates.


Chroma(Posted 2008) [#67]
Seems my method above for calculating the virtual mouse coords gives inaccurate results when the letterbox is being used. :(


sswift(Posted 2008) [#68]
Chroma I just noticed your mouse code deletes some directory when it starts. Why would you post code like that? What if someone has a directory with that name and runs your example? You should fix that.

I'm looking into solving the mouse issue. I think you did the math operations in your code backwards. You scaled the mouse coordinates AFTER you subtracted the origin in virtual space from them, and I'm pretty sure you should be scaling the coordinates before you do that.


sswift(Posted 2008) [#69]
I haven't solved the issue yet, but I also just noticed something else weird with your code:

Local ProjMatrix:ProjectionMatrix = New ProjectionMatrix


This is uneccessary. There is no need to create a projectionmatrix object, because the type has only functions and global variables. So you can just access the functions like so: X = ProjectionMatrix.CenterX().

The only reason one needs to use New with a type, is if one intends to have multiple instances of said type, and if said type has some local variables with which said instances can differentiate themselves from one another, and, generally, methods to act upon said variables.


sswift(Posted 2008) [#70]
Okay I solved the problem. Run this. I purpousefully left out three lines to help you understand the issue here:

Global Mouse_X#, Mouse_Y#
Global Mx#, My#

Local OriginX%, OriginY% 
Local ScaleX#, ScaleY# 


Graphics 1024,768,32

ProjectionMatrix.SetLetterBox(800,500)

ScaleX# = ProjectionMatrix.Width()  / GraphicsWidth()
ScaleY# = ProjectionMatrix.Height() / GraphicsHeight()

OriginX = ProjectionMatrix.CenterX() - ProjectionMatrix.Width()/2
OriginY = ProjectionMatrix.CenterY() - ProjectionMatrix.Height()/2

SetOrigin OriginX, OriginY


Repeat 
	
	SetClsColor 0, 0, 63
	Cls
	
	'VirtualMouseX = (MouseX() - OriginX) * ProjX
	'VirtualMouseY = (MouseY() - OriginY) * ProjY

	' Transform mouse coordinates from screen space to virtual space via scaling.

		Mx# = MouseX()
		My# = MouseY()

		Mouse_X# = Mx#*ScaleX#
		Mouse_Y# = My#*ScaleY#

	DrawText Mx#, 16, 16*1
	DrawText My#, 16, 16*2

	DrawText Mouse_X#, 16, 16*4
	DrawText Mouse_Y#, 16, 16*5
	
	ProjectionMatrix.DrawLetterBox()

	Flip 1

Until KeyDown(KEY_ESCAPE) Or AppTerminate()



' ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
' This type allows you to make games that can run at any resolution.
' ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Type ProjectionMatrix
	
	Global _Width%				' The size of the screen, in BlitzMax coordinates. 
	Global _Height%				' Normally BlitzMax coordinates correspond 1:1 with pixels on the screen, but when you adjust the projection matrix, that relationship changes.
	
	Global _VirtualWidth%		' The size of the visible region in which gameplay takes place.  The area inside the letterbox.
	Global _VirtualHeight%


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function sets the scale of the projection matrix.
	'
	' If you simply wish your game to stretch vertically and horizontally to match the current resolution, and fill the screen, call this function with your desired "virtual" resolution.
	' Ie, if you want to build your game around an 800x600 resolution, then set Width and Height to 800,600.  If the game is then run at 1920x1200, it will be squashed vertically.
	'
	' If you want letterboxing however, call InitLetterbox() and then DrawLetterBox() every frame just before you flip.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function SetScale(Width%, Height%)
			
			_Width  = Width
			_Height = Height
			
			_VirtualWidth  = Width
			_VirtualHeight = Height
				
			?Win32

				Local D3D7Driver:TD3D7Max2DDriver = TD3D7Max2DDriver(_max2dDriver)
    
				If D3D7Driver
			
					Local Matrix#[] = [2.0/Width, 0.0, 0.0, 0.0,..
   		    	    			      0.0, -2.0/Height, 0.0, 0.0,..
       		    	      			  0.0, 0.0, 1.0, 0.0,..
           		    	  			  -1-(1.0/Width), 1+(1.0/Height), 1.0, 1.0]
    
				    D3D7Driver.device.SetTransform(D3DTS_PROJECTION, Matrix)

				Else
			? 
					' If on platform other than Win32, or using OpenGL run this code.
		
					glMatrixMode(GL_PROJECTION)
					glLoadIdentity()
    
					glortho(0, Width, Height, 0, 0, 1)
    
					glMatrixMode(GL_MODELVIEW)
					glLoadIdentity()
		
			?Win32

				EndIf
			?
		
		End Function


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function initializes the letterbox.
	'
	' Call it with the virtual resolution you want to use for your game after you have set the graphics mode, and then DrawLetterBox() every frame just before you flip.
	'
	' These functions will automatically handle both letterboxing on screens which are too tall, and pillarboxing on screens which are too wide.  So if you design your game for 800x600,
	' then InitLetterbox() will squash things horizontally to maintain the proper aspect ratio, and DrawLetterbox() will add black bars to the sides of the display for you.
	'
	' 
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function SetLetterbox(Width%, Height%)	

			Local NewWidth#, NewHeight#
						
			NewWidth#  = Width
			NewHeight# = Float(GraphicsHeight()) / (Float(GraphicsWidth()) / Float(Width))
		
			' If screen is wider than the desired apsect ratio...

				If NewHeight# < Height
				
					' Use pillarboxing instead of letterboxing.
										
						NewHeight# = Height
						NewWidth#  = Float(GraphicsWidth()) / (Float(GraphicsHeight())/Float(Height)) 	
				
				EndIf
			
			' Adjust the scale of the projection matrix to achieve the desired result.
				ProjectionMatrix.SetScale(NewWidth#, NewHeight#)
		
			' Store the size of the visible game region.
				_VirtualWidth  = Width
				_VirtualHeight = Height
	
		End Function 
		
		
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function draws black bars over the portions of the screen which are outside the gameplay area.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

		Function DrawLetterbox()
		
			Local Size%
			
			RenderState.Push()	
			
			If _VirtualHeight < _Height
				
				' Draw Letterbox.
				
					Size = (_Height-_VirtualHeight) / 2
				
					SetColor(0,0,0) 
							
					DrawRect(0,            0, _Width, Size)
					DrawRect(0, _Height-Size, _Width, Size)
					
			Else
				
				' Draw pillarbox.

					Size = (_Width-_VirtualWidth) / 2
				
					SetColor(0,0,0) 
							
					DrawRect(          0, 0, Size, _Height)
					DrawRect(_Width-Size, 0, Size, _Height)
				
			EndIf			
			
			RenderState.Pop() 	' Render push and pop simply resets the color and other display properties to whatever they were beforehand.  These two functions are in the code archives.
			
		End Function


	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' These functions return the virtual width and height of the usuable region of the screen, inside any letterboxing.
	'
	' Basically, these functions are equivalent to GraphicsWidth() and GraphicsHeight() when using a projection matrix where coordinates don't match up 1:1 to pixels
	' and/or letterboxing is being used.
	'
	' These functions will not return useful values until either ProjectionMatrix.SetScale() is called, or ProjectonMatrix.SetLetterbox() is called!
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

		Function Width#()
			Return _VirtualWidth
		End Function
		
		Function Height#()
			Return _VirtualHeight
		End Function
		
	
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	' These functions tell you where the center of the screen is when using letterboxing.  
	'
	' Note that they do not calculate this using the width and height of the visible area of the screen, but rather, the size of the whole screen including the letterboxed regions.
	' This is important, because if you draw objects using the size of the visible region only, they will be higher on the screen than they should be, or more to the left.
	'
	' In my games, what I do is create a pivot called Origin, and place it in the center of the screen, and attach all my sprites to that, so the only time I need to worry about where
	' the center of the screen really is is when I position that pivot initially. 
	'
	' Then when I've done that, the top of the screen is at -ProjectionMatrix.Height#()/2, half the height I passed to SetLetterbox(), and so on.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function CenterX#()
			Return _Width/2
		End Function
			
		Function CenterY#()
			Return _Height/2
		End Function
				
		
End Type


Type RenderState

	Global RenderStateList:TList = CreateList()
				
	Field Alpha#
	Field Blend
	Field ClsColor_R, ClsColor_G, ClsColor_B
	Field Color_R, Color_G, Color_B
	Field Handle_X#, Handle_Y#
	Field ImageFont:TImageFont
	Field LineWidth#
	Field MaskColor_R, MaskColor_G, MaskColor_B
	Field Origin_X#, Origin_Y#
	Field Rotation#
	Field Scale_X#, Scale_Y#
	Field Viewport_X, Viewport_Y, Viewport_Width, Viewport_Height


	' -------------------------------------------------------------------------------------------------------------------------------------------------------
	' These methods allow you to save and restore the current render settings
	'
	' Each time you call the push method, the current state is placed on the stack.
	' Each time you call the pop method, the last state placed on the stack is restored and removed from the stack.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------

		
		Function Push()

			Local RS:RenderState = New RenderState

			RS.Alpha# = GetAlpha#()
			RS.Blend  = GetBlend()
			GetClsColor(RS.ClsColor_R, RS.ClsColor_G, RS.ClsColor_B)
			GetColor(RS.Color_R, RS.Color_G, RS.Color_B) 
			GetHandle(RS.Handle_X#, RS.Handle_Y#)
			RS.ImageFont = GetImageFont()
			RS.LineWidth# = GetLineWidth#()
			GetMaskColor(RS.MaskColor_R, RS.MaskColor_G, RS.MaskColor_B)
			GetOrigin(RS.Origin_X#, RS.Origin_Y#) ; SetOrigin 0,0
			RS.Rotation# = GetRotation#()
			GetScale(RS.Scale_X#, RS.Scale_Y#)
			GetViewport(RS.Viewport_X, RS.Viewport_Y, RS.Viewport_Width, RS.Viewport_Height)
		
			RenderStateList.AddLast(RS)
		
		End Function		


		Function Pop()
		
			Local RS:RenderState = RenderState(RenderStateList.RemoveLast())	
				
			SetAlpha(RS.Alpha#)
			SetBlend(RS.Blend)
			SetClsColor(RS.ClsColor_R, RS.ClsColor_G, RS.ClsColor_B)
			SetColor(RS.Color_R, RS.Color_G, RS.Color_B) 
			SetHandle(RS.Handle_X#, RS.Handle_Y#)
			SetImageFont(RS.ImageFont)
			SetLineWidth(RS.LineWidth#)
			SetMaskColor(RS.MaskColor_R, RS.MaskColor_G, RS.MaskColor_B)
			SetOrigin(RS.Origin_X#, RS.Origin_Y#)
			SetRotation(RS.Rotation#)
			SetScale(RS.Scale_X#, RS.Scale_Y#)
			SetViewport(RS.Viewport_X, RS.Viewport_Y, RS.Viewport_Width, RS.Viewport_Height)

		End Function


End Type



First, I changed your code so that it prints the true mouse position at the top, and the virtual position below it.

Second, I removed the offset you were adding to the mouse position, because it was uneccessary.

Third, I cleaned up the code. :-)


So... When you look at this initally you might think there is still a problem, because the virtual coordinates say 0,0 when the mouse is in the upper left corner of the screen, and 799,499 when it's in the lower right. I did!

You may say, "But I want the virtual coordinates to be 0,0 when the mouse is at the top left corner of the VISIBLE region inside the letterbox!


But: SURPRISE! They ARE!


You're seeing the mouse drawn at the screen coordinates, because it's the hardware mouse. So it has free reign to travel the entire screen.

But if you were to draw the mouse at the virtual coordinates after the scaling, then when the real mouse is at the top left corner of the screen, the virtual mouse would be drawn at the top left corner of the visible region inside the letterboxing. The same goes for when the real mouse is in the lower right corner, the virtual mouse would be drawn in the correct spot.

Just add these lines after the drawtext commands in the above code, and everything will become clear!

	SetColor 255, 0, 0
	DrawRect Mouse_X#, Mouse_Y#, 2, 2	
	SetColor 255, 255, 255


So you see, what you need to do if you want to have a mouse in your app using this code is to eschew the hardware mouse cursor and simply draw your own using those virtual mouse coordinates scaled to the virtual screen size.

Ta da!


Chroma(Posted 2008) [#71]
Hmm...nm checking it again...

EDIT: Ok lol. I had this right at one point but was looking at the actual mouse instead of a custom mouse that should have been drawn at the virtual mouse coordinates. /bonk

Thanks for the indepth explanation. O.o I would call this snippet 100% complete now!


MGE(Posted 2008) [#72]
Guys, first off, thank you so much for taking the time to do this. For those of less fortunate enough to understand the tech side, I have 3 final favor(s) to ask.

1) Could another topic be created just calling it "Universal Projection Matrix Handling" or something similar and then put the final code in it? Perhaps in the beginner section?

2) Could you also explain in detail in the thread how to read the mouse properly in the virtual res.

3) Could you also explain in detail the mods needed to make top left equal 0,0 just like normal BMax?

Alot more people would then realize exactly what this does. I think this is probably one of the most vital contributions to the BMax community. 100% needed for any serious game designer. Hats off to all of those involved!


Chroma(Posted 2008) [#73]
since it wouldn't be possible without the code someone else wrote to set the projection matrix.

Who's the someone else we need to thank here?


Grey Alien(Posted 2008) [#74]
prolly Indiepath.

swift: It only upscales right? Doesn't downscale (or does it do that too?). Do the scaled graphics look a bit funny though, sorta less precise/interpolated? That's my main worry and why I don't think very many commercial 2D games do this.


MGE(Posted 2008) [#75]
Grey: Assuming it does both (up/down scale) why would you think commercial games wouldn't use this? And how does this process differ from what you're doing in your latest game? (How does it work when run on letter box systems?) Thanks.


sswift(Posted 2008) [#76]
I couldn't remember, so I looked it up. The code I used was posted by Yan:

http://www.blitzbasic.com/Community/posts.php?topic=61822#690808

But I think the original source of the code was Indiepath, who posted this module:

http://modules.indiepath.com/forum/viewtopic.php?t=19


So there you have it. That's the code which lets you stretch the screen to a certain virtual resolution. The code I added figures out just how it needs to be stretched to maintain square pixels on monitors with different aspect ratios, and adds the neccessary black bars to cover the regions outside the normal play area.


Grey Alien(Posted 2008) [#77]
MGE: I think swift's code is neat (and automatic which is great) but commercial 2D games with lots of hand-drawn or pre-rendered 2D art that has to fit on precise screen layouts and HUDs doesn't look good when stretched (or shrunk) - I've tried both. And thus many casual game developers who know polish is king don't want to mess with the graphics that they've shelled out tons to get pixel perfect (except for particle effects which naturally scale all sorts of ways). Perhaps scaling suits some 2D game types better than others (ones with moving instead of static graphics), but you won't find scaling in many commercial casual games at all (go and look, you'll find BAD graphics, but that's not the same) - which is why I've never added it to my framework.

My last game didn't support widescreen at all - I brought the issue up with BFG but they really weren't bothered with supporting it. However, we may add support for the next game. Any method I end up using won't do any scaling (which surely also has a GPU overhead along with the overhead of displaying graphics at a very high resolution (TFT natural res)). I'll find the closest res to the game's res and then use black bars if need be. Just a matter of preference I guess - not saying either is correct...

Actually an interesting point is this: What looks best/worse: scale graphics shown on a TFTs natural resolution OR non-scaled graphics shown on a TFT at something OTHER than its natural resolution?


MGE(Posted 2008) [#78]
Thanks GA. "I'll find the closest res to the game's res and then use black bars if need be."

With this code, I'm assuming if your virtual screen and actual screen are the same, the scaling is non-existant?

Otherwise I plan on using this code, but like you, find the closest compatible mode available and use it and let this handler do all the letterboxing, pillar, etc, if needed. I don't think the scaling hit will be that much if at all in this scenario.

One thing I disagree with swwift's thinking however, is running the game at full desktop resolution. That's a potential "first time look" performance killer! ;)


Chroma(Posted 2008) [#79]
GA, I don't think you understand what this code is actually doing. It's not scaling the graphics in the terms you're thinking of...


sswift(Posted 2008) [#80]

Actually an interesting point is this: What looks best/worse: scale graphics shown on a TFTs natural resolution OR non-scaled graphics shown on a TFT at something OTHER than its natural resolution?



Exactly. Scaling done by 3D hardware will look better of course. Not all LCD monitors are created equal when it comes to their ability to scale an image, but all 3D cards will do the job perfectly.

So your choice is this.

1. Write your game for say, 800x600 and have it stretched and/or scaled badly when viewed on any monitor other than a CRT or 800x600 4:3 LCD display. (which is very rare)

2. Write your game for 800x600, and make it windowed. (It would be silly to display a tiny little gameplay region with blackness all around in fullscreen.)

3. Write your game for 800x600 and use the 3D card to scale it, with letterboxing so it doesn't need to be stretched. With this your graphics fill most of the screen, you're assured that they'll be scaled as nicely as possible, and they're not stretched or squashed in aspect ratios which don't match the one you designed the game for.


Also, 2D games look just fine when scaled. The only time this is an issue is when the screen's resolution is low.

But people who run their games at 800x600 really are not going to be able to tell that the game is low res, or slightly blurrier than it needs to be. My dad couldn't even tell that he was still looking at 640x480 video on his new high definition TV because he didn't get the high definition cable box he needed to provide the high definition channels.

All casual gamers want is bright colors and funny characters. They're not as fussy about things being super sharp and pixel perfect as hardcore gamers are. And the hardcore gamers will be using higher res screens, so your game will look nice on their screens with little to no blurriness.



One thing I disagree with swwift's thinking however, is running the game at full desktop resolution. That's a potential "first time look" performance killer! ;)



I haven't decided if I will support other resolutions, but using the desktop resolution ensures that I'm picking a resolution the monitor supports, and it is likely to be the highest resolution the monitor supports, so the game will look the best.

Most people who run the game will not be doing what you're doing, ie: running your desktop at 1152x864x32, when all you have is an Intel graphics chipset.

Most casual gamers would have their resolution set to 800x600 or 1024x768. Those that have higher resolutions will have newer PC's which are very likely to have decent video chipsets.

Oh and btw, here's a site which has some statistics on what resolutions people browsing the web are using:
http://www.onestat.com/html/aboutus_pressbox43-screen-resolutions.html

The stats are from mid-2006, and the numbers for 800x600 have surely gone down since then, so you're talking less than 10% of users having 800x600 res now, with the vast majority having 1024x768 or higher.


So while it's true that if I just run at the desktop res, some people will have a poor gaming experience, I would say that you're talking about maybe 1% of users having an issue, and you have to consider the extra sales that will be gained from the game requiring virtually no set up for everyone else, who has no idea what a resolution is and wouldn't know to pick a lower one, or would pick one which is too low.

I guess the most ideal solution would be to run a bunch of tests at different resolutions and pick the highest res one which is fast, but is it worth all that extra work and making people wait to play the game and potentially messing something up on their system trying to put the screen into resolutions it might not support, just so 1% of users won't have a bad experience, even though it may degrade the expeirence of the other 99% somewhat? I don't think so.


sswift(Posted 2008) [#81]
Chroma:
"If scaling your graphics is causing your game drop below 60fps then you should take some programming classes."

I have to side with GA here. The speed at which the game draws these days is due to the speed of the video hardware, not, generally, one's coding experience. Sure I could probably go way out of my way to make the code faster on systems like that, and make sure I don't blend large transparent objects. But really, it's people like MGE who have an Intel graphic chip and try to run at resolutions over 800x600 who are the problem, not the code. :-)


Chroma(Posted 2008) [#82]
That's not what I meant. GA was fussing over the overhead of scaling the graphics. Which is a moot point.

Actually I don't think BFG would allow him to use this code anyhow. He's locked into 800x600 resolution for his games.


sswift(Posted 2008) [#83]

swift: It only upscales right? Doesn't downscale (or does it do that too?). Do the scaled graphics look a bit funny though, sorta less precise/interpolated? That's my main worry and why I don't think very many commercial 2D games do this.




The code handles any scale. If you code your game for a virtual res of 800x500 widescreen, and run it on a 640x480 system, it'll still display things properly.

Do scaled graphics look a bit funny? Well any time you scale an image up or down, you're doing have have pixels combined, or new pixels added. This will make the image look blurrier to some degree.

But when you play 3D games, do the textures look bad? No. Even though they're scaled and rotated, they're interpolated nicely, and they look as good as one would expect. If you compared them side by side with a pixel perfect version that is unscaled, would the unscaled one look sharper than the one offset by a few pixels and scaled a bit? Sure. Will it look bad? Well, how bad it looks compared to the unscaled version depends on how low the resolution is, and how high res the texture was.

Most casual games I've seen would look just fine using this setup, so long as the original art wasn't designed with 1920x1200 in mind. If the original art was designed for roughly 1024x768 or 800x600, then at those resolutions it'll look pretty good. And backgrounds will look good at any res.

The main concern is high frequency details like the outlines on characters, or eyes or what have you, that you don't want scaled down too much or they just become blurry blobs. But if you have your art designed with that in mind, like I did, then it's not an issue. I had the artist on my game make things like the antenna on the aliens thicker than a couple pixels, specifically so that they would look good when scaled. That's why Mario looks how he does too, because he was designed with super low res in mind, so he ended up with big hands and large eyes and pupils.


Sledge(Posted 2008) [#84]
Most people who run the game will not be doing what you're doing, ie: running your desktop at 1152x864x32, when all you have is an Intel graphics chipset.

Untrue. You can't buy an bottom-end Inspiron without widescreen these days and their native resolution is 1280*800.


MGE(Posted 2008) [#85]
"If scaling your graphics is causing your game drop below 60fps then you should take some programming classes."

I could download probably any Blitzmax game on this site and it won't run 60fps on a brand new Dell Vista 2007 laptop running in my daughter's room unless you run it in 640x480x32 or maybe 800x600x16. If you're serious about your game, you will need to run it on the lowest system spec you would like to support and see how it works.


Grey Alien(Posted 2008) [#86]
He's locked into 800x600 resolution for his games
Am I? Wow I never knew that.

Sswift:
The main concern is high frequency details like the outlines on characters
Yeah exactly, also with fonts. Small fonts look BAD scaled. This is my concern.

MGE:
Otherwise I plan on using this code, but like you, find the closest compatible mode available and use it and let this handler do all the letterboxing, pillar, etc, if needed. I don't think the scaling hit will be that much if at all in this scenario.
Well there won't be any scaling of graphics, just a higher res used and some black bars drawn. I feel this will give the best performance.

sswift:
Most casual gamers would have their resolution set to 800x600 or 1024x768. Those that have higher resolutions will have newer PC's which are very likely to have decent video chipsets.
According to those old stats 1024x768 is standard, but there's been a whole year's worth of widescreens sold since then (with laptops outselling desktops in 2007). So many casual gamers will be using the default widescreen res their system came with. Here's a thought though: which is fastest 1) a default widescreen res on a poor GPU (plenty of laptops still have crappy onboard intel) or 2) a lower res which is closer to the game's res on a poor GPU? Depends if the GPU is optimised for the default res or not (it's probably NOT).


sswift(Posted 2008) [#87]

Untrue. You can't buy an bottom-end Inspiron without widescreen these days and their native resolution is 1280*800.



Hm... Finding benchmarks for the intel chips in those isn't easy, but I think I found one:

http://www.phoronix.com/scan.php?page=article&item=571&num=3

Which says that Wolfenstein at 1280x1024 runs at 13fps. Which is pretty good considering the level of detail in that game. My game should run at at least 30fps on such a system at that res.

So I stand by what I said. :-)



I could download probably any Blitzmax game on this site and it won't run 60fps on a brand new Dell Vista 2007 laptop running in my daughter's room unless you run it in 640x480x32 or maybe 800x600x16. If you're serious about your game, you will need to run it on the lowest system spec you would like to support and see how it works.



But... I will do some more testing if possible to be sure. :-)



Small fonts look BAD scaled. This is my concern.



How small we talking? Yeah, small fonts can look like crap. But you can also use the Text command to render text 16 or 24 pixels tall regardless of the screen res if you're worried about that. At that small size, you don't really need fancy text effects if you have a nice font either. And the casual gamers won't notice. :-)


MGE:
Of course the lower resolution will be the fastest. The main benefit of using the native resolution is that you know it's a valid mode, and it's high res.


I don't even know why people are reaslly arguing about this though. I mean, if you want your game to run at 800x600 all the time, then just do that. Set that mode. You don't even need this code. Your game will be stretched on widescren monitors of course, but what can be done about that? The only way to solve that with this code as is, would be to run in a widescreen video mode.

And this chart:
http://en.wikipedia.org/wiki/Image:Vector_Video_Standards2.svg

Indicates that the lowest res 16:10 mode (which they call 8:5 here) is 1280x800.

So you'd have to modify the code... You'd have to use the desktop resolution to guess the aspect ratio of the monitor, and then set the resolution to 800x600, and then squash the graphics horizontally and use only a portion of that 800 width, and stick black bars on the sides. So the game would actually have lower resolution on a widscreen monitor than on a 4:3 when set to the same video mode. And that's kinda sucky.


Sledge(Posted 2008) [#88]
Which says that Wolfenstein at 1280x1024 runs at 13fps. Which is pretty good considering the level of detail in that game. My game should run at at least 30fps on such a system at that res.

So I stand by what I said. :-)

Actually, give me a mo' and I'll fraps the demo you posted -- without too many other apps running it certainly didn't seem like it wouldn't be playable.


TartanTangerine (was Indiepath)(Posted 2008) [#89]
Oooo Projection Matrix, now there is a good idea :)


Sledge(Posted 2008) [#90]
main-064..exe runs between low sixties to around eighty FPS for the most part. When it's busy and scrolling fast it drops briefly down to just over fifty -- that's on a bog-standard Inspriron (1.6ghz).


sswift(Posted 2008) [#91]
Oooo Projection Matrix, now there is a good idea :)


Do you just do searches for your name constantly so you can show up the moment someone mentions you? :-)


Actually, give me a mo' and I'll fraps the demo you posted


You know you can just hit TAB to see the FPS in the game right? :-)

Thanks for testing it though. So that Inspiron, that has an intel graphics chip right?

If so, that's great. So a 2D style action game runs perfectly acceptably on one of the lowest end systems now available. And of course a puzzle game would be no problem at all.


Sledge(Posted 2008) [#92]
You know you can just hit TAB to see the FPS in the game right? :-)
Yeah, FRAPS is a lot easier to read, though, and I'd trust it over any self-benchmarking code by anyone in anything.

So that Inspiron, that has an intel graphics chip right?
Sure does.


MGE(Posted 2008) [#93]
"I don't even know why people are reaslly arguing about this though."

I don't think anyone is really arguing. I think we'll all thrilled to have this solution here! Thanks again! But I think the real debate is what's better to do:

1) Run the game at the current desktop res and take a chance on the game running choppy due to the desktop res being too large.

2) Find out which modes are available and pick the closest mode that will fit.

"If so, that's great. So a 2D style action game runs perfectly acceptably on one of the lowest end systems now available. And of course a puzzle game would be no problem at all."

Depends on the card, the graphics mode, updated drivers, OpenGl, DirectX, etc. Nothing's guaranteed, prepare for the worse, hope for the best. ;)

"So that Inspiron, that has an intel graphics chip right?"

Most of the Inspiron's available now have the newer Intel Graphics Media Accelerator X3100 or 128mb Nvida Geforce Cards. It's awesome that they're making them available with Vista or XP. ;)


Chroma(Posted 2008) [#94]
GA have you actually tested small fonts with this particular method before you call it BAD? You're kicking and screaming against this...maybe you should actually do some testing and then post what the results are? sswift's game looks spot on to me and not scaled at all. The resolution in his game is 800x500 and I ran it on my widescreen at 1680x1050. Everything was crisp and sharp. I absolutely couldn't tell it was scaled. It's not like setting the resolution of 800x600 on a native 1280x1024 and it looks slightly pixelated. It's not the kind of scaling you think it is man geez...

Do some testing, post back. I'd do the testing myself but my dev computer is on its way overseas. If I were you I'd talk to BFG and try to reason with them. I tested out your foreway card game thingy and it really looks bad fullscreen on my widescreen. We both know widescreens are coming like a freight train.


Grey Alien(Posted 2008) [#95]
Yes I tested scaling down and up of bitmap fonts and fonts drawn with DrawText on my CRT when deveoping Fairway and they never looked as good as fonts drawn at 1:1. I spent several DAYS on it.

Scaling is scaling, up or down, there's going to be some interpolation and innacuracy which I can see on my CRT. A projection matrix, clever as it is, is just not my thing (plus it will have a GPU overhead, maybe minor, maybe not, depends on the card). How bad scaled graphics look entirely depend on the graphic type (swift has made his so they look better scaled - good plan). Try scaling a nice fine detailed grid/mesh and see what happens, or a carefully crafted small stylised font. I believe that some casual game consumers will notice conciously or sub-conciously and it will affect their feeling of "quality".

Sswift's method is fine and dandy, use it if you like it. It's just maybe not for me (at the moment, but I may repent!) I'll be keeping a 1:1 scale (from 800x600 OR 1024x768 - depends on the game (I'm making 2 in 2008)) but changing the screen res to the nearest same or higher match (for increased framerate instead of scaling into a possibly bigger desktop res with slower framerate).


Chroma(Posted 2008) [#96]
Scaling isn't black and white as you presume. sswift's method at least keeps the scaling at 1:1 ratio with all resolutions. That makes the scaling barely noticeable.

but changing the screen res to the nearest same or higher match (for increased framerate instead of scaling into a possibly bigger desktop res with slower framerate
What exactly are you refering to here? Do you mean same or higher match of the native resolution or your preset game resolution? If it's the latter then that sounds like something I mentioned doing a couple months ago. I don't think there's a valid widescreen resolution that is either 600 or 768 in height is there? Personally, I'm just going to use sswift's code and run the virtual resolution at 1024x768. Then detect whether the native resolution is a normal aspect ratio or widescreen and then set the real game resolution to 1024x768 for normal or 1280x800 for widescreen. 800-768 ok so it's 32 pixels off I can live with that. Btw, my above resolutions might be a bit off...like I said, my dev comp is on it's way to a far off land.


Grey Alien(Posted 2008) [#97]
Yep I'll pick nearest to 1024x768 but I won't go lower and I won't scale, even at 1:1 because it will still have to interpolate (may not make much difference to TFT users not running at native res but will to CRT users).


MGE(Posted 2008) [#98]
GA, in a nut shell you're just picking a full screen mode that's available closest to your game screen and then drawing bars if needed? The only potential snag is picking a mode that will be stretched. Since laptops don't tell you 800x600 will be stretched. I would think you would need to first look for widescreen modes available and then if they are use them. Is that how you see it working? Thanks. ;)


Grey Alien(Posted 2008) [#99]
Yep, check the desktop res for ratio first, then find the nearest VERTICAL resolution to 600 (or 768 depending on the actual game res) and pick that if it has the same aspect ratio as the desktop res. (Worst case you end up with the desktop res anyway)