Viewport + virtualresolution + tileimage
Archives Forums/BlitzMax Bug Reports/Viewport + virtualresolution + tileimage
| ||
This code reproduces the issue:Graphics(800, 600) SetVirtualResolution(400, 300) Local image:TImage = LoadImage("block0101.png") SetViewport(100, 100, 300, 100) While Not KeyHit(KEY_ESCAPE) Cls TileImage(image, 100, 100) Flip Wend The image is never drawn, or it is drawn with artifacts. Tested with a small PNG but I can see this being reproduced with any image, using any Max driver DX9, DX7 and GL. |
| ||
Ha! This is gonna be *very* tricky to get right (knew I was gonna regret TileImage!) as viewport is in 'window coords', while image and supposedly tile x,y params are in 'virtual coords'. There are therefore several ways to interpret what it should be doing. Perhaps modifying viewport so it's in virtual coords too would be preferable? Time to think about letter boxing too perhaps? |
| ||
I think modifing SetViewport would be a good idea but, anyway, in the example above we should see at last a 300x100 square of tiled images, but nothing is shown in my computer. Sometimes it works, but changing the width and height of the viewport does show the error. This is what I get without SetViewPort: And this with viewport uncommented: We should, at last, see a square of tiles. I mean, coords could be wrong if it is using screen coords, but it should at last display a 300x100 square, shouldn't it? [EDIT] Even using a 'virtual resolution' viewport I get the same issues: 'Armitage 1982 function for virtualviewport: Function SetVirtualViewport(X:Double, Y:Double, width:Double, Height:Double) Local gcw:Double = VirtualResolutionWidth() / GraphicsWidth() Local gch:Double = VirtualResolutionHeight() / GraphicsHeight() X:/gcw Y:/gch width:/gcw Height:/gch SetViewport(ccRound(X, 0), ccRound(Y, 0), ccRound(width, 0), ccRound(Height, 0)) End Function rem bbdoc: This function rounds a decimal value with a given digits precision. end rem Function ccRound:Double(number:Double, decimals:Byte) Local t:Long = 10 ^ decimals Local result:Double = Long(number * t + 0.5:Double * Sgn(number)) Return result / Double(t) End FunctionSo no idea what can be happening here... |
| ||
Having the viewport use virtual coordinates seems more consistent. Something goes wrong when viewport x,y exceed the image width, height. ' Does two trials. The first is with ordinary graphics. ' The second uses SetVirtualResolution. In the second case ' SetViewPort gets confused about width and height. Graphics( 800, 600) HideMouse Global image:TImage = CreateImage( 100, 100 ) BuildImage Local x:Int = 0 Local trial:Int = 0 While True SetViewport( 0, 0, 800, 600 ) Cls SetViewport( x, x, 200, 200 ) x :+ 5 If x = 400 And trial = 0 x = 0 trial = 1 SetVirtualResolution( 400, 300) End If TileImage(image, 0, 0) Flip Delay 100 If x = 400 And trial = 1 Then End Wend Function BuildImage( ) Cls Local x:Int, y:Int For x = 0 To 99 For y = 0 To 99 SetColor 20 + x + y, 30 + 1.5*x, 40 + 2*y Plot x, y Next Next GrabImage image, 0, 0 End Function |
| ||
Yes, that's another very good example of the same bug. It has nothing to do with the coordinates being used in viewport. The command itself with any values does not work properly when virtual resolution is "on" |
| ||
Hi, Ok, Changing SetViewport in max2d.bmx to work with virtual coords fixes it (I think): Function SetViewport( x,y,width,height ) gc.viewport_x=x gc.viewport_y=y gc.viewport_w=width gc.viewport_h=height Local x0=Floor( x / gc.vres_mousexscale ) Local y0=Floor( y / gc.vres_mouseyscale ) Local x1=Ceil( (x+width) / gc.vres_mousexscale ) Local y1=Ceil( (y+height) / gc.vres_mouseyscale ) _max2dDriver.SetViewport x0,y0,(x1-x0),(y1-y0) End Function Note: Wont work with d3d7 driver as-is - you'll also need to change SetResolution in d3d7max2d.bmx to: Method SetResolution( width#,height# ) Local gw=GraphicsWidth() Local gh=GraphicsHeight() Local world#[]=[.. gw/width,0.0,0.0,0.0,.. 0.0,gh/height,0.0,0.0,.. 0.0,0.0,1.0,0.0,.. 0.0,0.0,0.0,1.0 ] device.SetTransform D3DTS_WORLD,world Local proj#[]=[.. 2.0/gw,0.0,0.0,0.0,.. 0.0,-2.0/gh,0.0,0.0,.. 0.0,0.0,1.0,0.0,.. -1-(1.0/gw),1+(1.0/gh),1.0,1.0] device.SetTransform D3DTS_PROJECTION,proj End Method |
| ||
It fix the visual bug :D BUT, In the other hand, it seems that sometimes the conversion of coordinates is one pixel smaller than it should be, I supose this is caused by rounding/truncation or something like that. Is this possible? |
| ||
This is a sample showing the one pixel artifacts after latest fix: |
| ||
Hi, Can you put together some sample code? I have no idea what graphics/virtualgraphics/viewport etc settings you're using. [edit]Actually, try changing the 'Ceils' to 'Floors' too[/edit] |
| ||
I'll provide some source code to you tomorrow (it is too late here and I should be sleeping since some hours ago). Thanks for taking a look to this. |
| ||
@marksibly: While trying to write sample of the one pixel issue, I've noticed that if I ensure everything was properly rounded (instead of being truncated) in the game itself the issue seems to not replicate. So not sure there's anything to fix there, but I'll make further tests in the forthcoming days. UPDATE: It seems like, as a side effect of this, when a graphics canvas is resized, the virtual resolution has to be set again, to maintain drawing properly. |
| ||
Yes, I discovered that as well. If you resize your canvas, you need to resize your virtual resolution. |