How to scale texture2d in XNA with window resizing - c#

I'm developing an UI for a project for school, and I've tried similar methods to scaling my texture as listed here, but here is the issue:
Our project is developed at 1440 x 900, so I've made my own images that fit that screen resolution. When we have to demo our project in class, the projector can only render up to 1024 x 768, thus, many things on the screen goes missing. I have added window resizing capabilities, and I'm doing my scaling like this. I have my own class called "button" which has a texture 2d, and a Vector2 position contruscted by Button(Texture2d img, float width, float height).
My idea is to set the position of the image to a scalable % of the window width and height, so I'm attempting to set the position of the img to a number between 0-1 and then multiply by the window width and height to keep everything scaled properly.
(this code is not the proper syntax, i'm just trying to convey the point)
Button button = new Button(texture, .01, .01 );
int height = graphicsdevice.viewport.height * button.position.Y;
int width = graphicsdevice.viewport.width * button.position.X;
Rectangle rect = new Rectangle(0,0,width, height);
sprite.being()
sprite.draw (button.img, rect, color.white);
sprite.end
it doesn't end up scaling anything when i go to draw it and resize the window by dragging the mouse around. if i hard code in a different bufferheight and bufferwidth to begin with, the image stays around the same size regardless of resolution, except that the smaller the resolution is, the more pixelated the image looks.
what is the best way to design my program to allow for dynamic texture2d scaling?

As Hannesh said, if you run it in fullscreen you won't have these problems. However, you also have a fundamental problem with the way you are doing this. Instead of using the position of the sprite, which will not change at all during window resize, you must use the size of the sprite. I often do this using a property called Scale in my Sprite class. So instead of clamping the position of the sprite between 0 and 1, you should be clamping the Size property of the sprite between 0 and 1. Then as you rescale the window it will rescale the sprites.
In my opinion, a better way to do this is to have a default resolution, in your case 1440 x 900. Then, if the window is rescaled, just multiply all sprites' scaling factors by the ratio of the new screensize to the old screensize. This takes only 1 multiplication per resize, instead of a multiplication per update (which is what your method will do, because you have to convert from the clamped 0-1 value to the real scale every update).
Also, the effects you noticed during manual rescale of the sprites is normal. Rescaling images to arbitrary sizes causes artifacts in the rendered image because the graphics device doesn't know what to do at most sizes. A good way to get around this is by using filler art during the development process and then create the final art in the correct resolution(s). Obviously this doesn't apply in your situation because you are resizing a window to arbitrary size, but in games you will usually only be able to switch to certain fixed resolutions.

Related

Knowing the actual dimensions of a sprite after scaling it at runtime

I'm creating a 2D project and I've a particular sprite that when I import it to Unity I apply a 200 units per pixels in the importer and in runtime sometimes I scale it.
How can I know the actual dimensions of the rendered sprite?
Sprite width in pixels / pixels per unit * X scale = actual width
Do the same for height to get the size in both dimensions.
If you want to get the width of the sprite projected on the screen then you will need to modify the result depending on the camera size. I think you could just divide it by the camera size.

Diagonal Shadow with GDI+

I am trying to draw a diagonal shadow.
First I make all pixel to black:
Next with a simple for cicle this is are the result
Now I want to stretch this image diagonally to simulate a shadow.
I have tried:
Bitmap b = new Bitmap(tImage.Width + 100, tImage.Height);
Graphics p = Graphics.FromImage(b);
p.RotateTransform(30f);
p.TranslateTransform(100f, -200f);
p.DrawImage(tImage, new Rectangle(0, -20, b.Width+20, b.Height));
but the images are rotated and translated.
Please anyone have a solution for me?
I need it to look like this (created in Photoshop):
Creating a nice dropshadow is quite a task using Winforms and GDI+.
It features neither polygon scaling nor blurring; and let's not even think about 3D..! - But we can at least do a few things without too much work and get a nice result for many images..
Let's assume you already have an image that is cut out from its background.
The next step would be to turn all colors into black.
Then we most likely would want to add some level of transparency, so that the background the shadow falls on, still shines through.
Both task are done quite effectively by using a suitable ColorMatrix.
With a very transparent version we can also create simple blurring by drawing the image with offsets. For best results I would draw it nine times with 3 differents weights/alpha values..
High quality blurring is an art as you can see by even just looking at the filters and adjustments in pro software like Adobe Photoshop or Affinity Photo. Here is a nice set of interesting links..
But since we are only dealing with a b/w bitmap a simplitstic appraoch is good enough.. I use 3 alpha values of 5%, 10% and 20% for the 4 corner, the 4 edge and the 1 center drawings.
The final step is drawing the shadow with some skewing.
This is explained here; but while this is seemingly very simple it is also somewhat impractical. The three points the DrawImage overlay expects need to be calculated.
So here is a method that does just that; do note that is is a strongly simplified method:
The overlay takes three points, that is 6 floats. We only use 3 numbers:
one for the amount of skewing; 0.5 means the top is shifted to the right by half the width of the bitmap.
the other two are the scaling of the resulting bounding box. 1 and 0.5 mean that the width is unchanged and the height is reduced to 50%.
Here is the function:
public Bitmap SkewBitmap(Bitmap inMap, float skewX, float ratioX, float ratioY )
{
int nWidth = (int)(inMap.Width * (skewX + ratioX));
int nHeight = (int)(Math.Max(inMap.Height, inMap.Height * ratioY));
int yOffset = inMap.Height - nHeight;
Bitmap outMap = new Bitmap(nWidth, nHeight);
Point[] destinationPoints = {
new Point((int)(inMap.Width * skewX), (int)(inMap.Height * ratioY) + yOffset),
new Point((int)(inMap.Width * skewX + inMap.Width * ratioX),
(int)(inMap.Height * ratioY) + yOffset),
new Point(0, inMap.Height + yOffset ) };
using (Graphics g = Graphics.FromImage(outMap))
g.DrawImage(inMap, destinationPoints);
return outMap;
}
Note a few simplifications:
If you want to drop the shadow to the left you will need to not just move the first two points to the left but also to adapt the calculation of the width and also the way you overlay the object over the shadow.
If you study the MSDN example you will see that the DrawImage overlay also allows to do a rotation. I didn't add this to our function, as it is a good deal more complicated to calculate and even to just to write a signature.
If you wonder where the info of the six numbers go, here is the full layout:
3 go into our parameters
1 would be the angle of the rotation we don't do
2 could be either the rotation center point or a point (deltaX&Y) the by which the result is translated
If you look closely you can see the shadow of the left foot is a little below the foot. This is because the feet are not at the same level and with the vertical compression the base lines drift apart. To correct that we would either modify the image or add a tiny rotation after all.
Looking at your example imag it is clear that you will nee to take it apart and treat 'house' and 'tree' separately!
The signature is kept simple; this always a balance between ease of use and effort in coding. On could wish for a paramter the takes angle to control the skewing. Feel free to work out the necessary calculations..
Note that adding the functions behind the other buttons would go beyond the scope of the question. Suffice it to say that most are just one line to do the drawing and a dozen or so to set up the colormatrix..
Here is the code in the 'Skew' button:
Bitmap bmp = SkewBitmap((Bitmap)pictureBox4.Image, 0.5f, 1f, 0.5f);
pictureBox5.Image = pictureBox1.Image;
pictureBox5.BackgroundImage = bmp;
pictureBox5.ClientSize = new Size(bmp.Width, bmp.Height);
Instead of drawing the object over the shadow I make use of the extra layer of the PictureBox. You would of course combine the two Bitmaps..

Depth buffers for different screens in XNA

I don't quite understand how to handle ZBuffering for different screens in my program. I have a screenControllers class that calls a Draw method for each of my active Screen classes. The spriteBatch.Begin and spriteBatch.End calls are made in the screenController's Draw. The Screen's Draw just has a spriteBatch.Draw statement for each of the textures being drawn. I understand that I can specify depth when calling the
public void Draw (
Texture2D texture,
Rectangle destinationRectangle,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
SpriteEffects effects,
float layerDepth
)
method for spriteBatch.
But say I open one screen with textures at some given depth. Then, the second screen I open should have other textures at the same depth values as the previous but drawn in order on TOP of the previous screen. I doubt I will need this functionality because the second screen I open will probably be an options screen on top of my scene window with everything in front or it may be a portion of an interface that is not on top of the scene window but to the side. I am just wondering if this layered functionality for multiple screens can be implemented in XNA?
If you use different SpriteBatch to manage them I don't think you will have this kind of problem.
If you use the same SpriteBatch you could use a scaleFactor and an offsetValue to manage the layerDepth value of your Draws, in order to create different invervals for every sceen's screenDepth parameter.
I mean that if you have 2 screen the first's textures are drawn in the [0, 0.5) interval, the second one in [0.5, 1). If you have 3 of them the interval will be every 0.33 and so on...
The scaleFactor will be 1 / numberOfScreens of course.

MonoGame - Tiling Texture2D with SpriteBatch on iOS

Right now I'm tiling a Texture2D with 2 for-loops similar to an example from the MonoGame samples.
I was doing some reading, and I was seeing that using power of two textures (2, 4, 8, 16, 32, etc. on width & height) can be tiled with one SpriteBatch.Draw call.
Is this supported with MonoGame on iOS?
I gave it several tries, and no matter what it merely stretches the image instead of tiling it.
I am using SamplerState.LinearWrap on my SpriteBatch.Begin(), and tried using a 2048x128 png and tried it 1/4 size at 512x32, but with no luck. (Using large sizes, b/c our game runs at 2400xSomething zoomed out, b/c you can zoom in with the camera by 2.5 multiplication)
You can use the SourceRectangle parameter in the draw method. To define what part of the Texture you want to display. Lets say you have a 128x128 Texture. If you supply Rect(0, 0, 128, 128) you tell the draw method to use the whole texture, the same if you would pass null to the draw method. If you supply Rect(0, 0, 64, 64) you would use the upper left part of the texture. Your sprite will display this portion, no matter how big the sprite itself is. So if your sprite is drawn with the size of 128x128 the 64x64 texture part would be scaled.
Now you can use that for animations. If you store in your texture a sequence of animation like this, you just need to recalc the source rectangle everytime you want to display the next image in your sequence.
Besides that, you could pass in a bigger value, than your source texture. XNA now needs to wrap or clamp your texture. That way you can achieve a simple tiling. If you need more than that my guess is you need to use a manual approach, like your foreach loops.
Please note that Wrap is only supported if you use power of two textures.

Trying to draw textured cube primitive in XNA with quads

Right now I'm using XNA 4.0 with Windows Phone Developer Tools to create a textured cube using a predefined quad class on MSDN.
The front/back/left/right faces of the cube will draw fine (for every cube that I make), however the top and bottom faces won't render. The rasterizer state's cull mode is set to none and the quad that represents the top face exists, and it seems as if it would draw, but for some reason it won't.
Is there a problem with my code, or is this not happening for some other reason?
Here's the code:
Game1.cs: http://pastebin.com/RHU7jNXA
Quad.cs & Cube.cs: http://pastebin.com/P9gz5q4C
It's because your top and bottom faces have a height to them. They should have 0 height.
Here you are passing in a value as height:
Faces[4] = new Quad(topFaceOrigin, Vector3.Normalize(Vector3.Down), Up, Size, Size);
And then here in Quad constructor it's being used to give incorrect LowerLeft & LowerRight values:
LowerLeft = UpperLeft - (Up * height);
LowerRight = UpperRight - (Up * height);
I would recommend changing how you create all your quads; each face really should have different parameters. Right now all your faces are passing in practically the same stuff.

Categories