How to get correct size of OGRE::RenderWindow after its resize? - ogre

My program changes the size of OGRE::RenderWindow at some time and later I want to get the current size of the window. But, when I use getWidth() or getHeight() on the window, they return the original size of the window.
Example code:
OGRE::RenderWindow* win;
// ... OGRE is initialized
// Window is drawn 1024x768 using size from ogre.cfg
// ... lots of code ...
// Window size is changed and it works
win->resize(800, 600);
// ... lots of code ...
// Window is still visibly 800x600, but this call
// returns 1024x768 (the original size)
int w = win->getWidth(); // Returns 1024
int h = win->getHeight(); // Returns 768
How to get correct size of the window?

There is getActualWidth() and getActualHeight() methods in Ogre::Viewport class, so you code would look like:
Ogre::WindowEventUtilities::messagePump();
int w = win->getViewport(0)->getActualWidth();
int h = win->getViewport(0)->getActualHeight();
Here we assume that there is only 1 viewport (indexed by 0).
When you use Ogre's rendering loop, you don't have to call this messagePump() as far as I know.

Related

Unity windowed mode size is different on different screen resolutions

So I want the window size in the build to be of a certain size and it works great when displayed on 1920 x 1080 screen resolution, anything more or less than that, and the window becomes too big or too small. Is there any way for the window to be of the same window to screen size resolution?
I have used the following settings:
My build settings
Afaik you can set the resolution depending on the Display screen size using Screen.currentResolution and Screen.SetResolution somewhat like e.g.
public class ScreenSizeController : MonoBehaviour
{
// how much space (percentage) of the screen should your window fill
[Range(0f,1f)]
public float fillX;
[Range(0f,1f)]
public float fillY;
private void Awake()
{
// Get actual display resolution
var res = Screen.currentResolution;
// calculate target resolution using the fill
var targetX = fillX * res.width;
var targetY = fillY * res.height;
// Set player resolution
Screen.SetResolution(targetX, targetY, false);
}
}
Note: Typed on smartphone but I hope the idea gets clear
Wouldn't changing the screen width/height in the resolution and presentation menu to 1920 x 1080 fix it

How can I get rid of artifacts in ImageSource created with SkiaSharp

I created an app in which I want to display text on top of google maps. I chose to use custom markers, but they can only be images, so I decided to create an image from my text utilizing SkiaSharp.
private static ImageSource CreateImageSource(string text)
{
int numberSize = 20;
int margin = 5;
SKBitmap bitmap = new SKBitmap(30, numberSize + margin * 2, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
SKCanvas canvas = new SKCanvas(bitmap);
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.StrokeAndFill,
TextSize = numberSize,
Color = SKColors.Red,
StrokeWidth = 1,
};
canvas.DrawText(text.ToString(), 0, numberSize, paint);
SKImage skImage = SKImage.FromBitmap(bitmap);
SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100);
return ImageSource.FromStream(data.AsStream);
}
The images I create however have ugly artifacts on the top of the resulting image and my feeling is that they get worse if I create multiple images.
I built an example app, that shows the artifacts and the code I used to draw the text. It can be found here:
https://github.com/hot33331/SkiaSharpExample
How can I get rid of those artifacts. Am I using skia wrong?
I got the following answer from Matthew Leibowitz on the SkiaSharp GitHub:
The chances are you are not clearing the canvas/bitmap first.
You can either do bitmap.Erase(SKColors.Transparent) or canvas.Clear(SKColors.Transparent) (you can use any color).
The reason for this is performance. When creating a new bitmap, the computer has no way of knowing what background color you want. So, if it was to go transparent and you wanted white, then there would be two draw operations to clear the pixels (and this may be very expensive for large images).
During the allocation of the bitmap, the memory is provided, but the actual data is untouched. If there was anything there previously (which there will be), this data appears as colored pixels.
When I've seen that before, it's been because the memory passed to SkiaSharp was not zeroed. As an optimization, though, Skia assumes that the memory block passed to it is pre zeroed. Resultingly, if your first operation is a clear, it will ignore that operation, because it thinks that the state is already clean. To resolve this issue, you can manually zero the memory passed to SkiaSharp.
public static SKSurface CreateSurface(int width, int height)
{
// create a block of unmanaged native memory for use as the Skia bitmap buffer.
// unfortunately, this may not be zeroed in some circumstances.
IntPtr buff = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(width * height * 4);
byte[] empty = new byte[width * height * 4];
// copy in zeroed memory.
// maybe there's a more sanctioned way to do this.
System.Runtime.InteropServices.Marshal.Copy(empty, 0, buff, width * height * 4);
// create the actual SkiaSharp surface.
var colorSpace = CGColorSpace.CreateDeviceRGB();
var bContext = new CGBitmapContext(buff, width, height, 8, width * 4, colorSpace, (CGImageAlphaInfo)bitmapInfo);
var surface = SKSurface.Create(width, height, SKColorType.Rgba8888, SKAlphaType.Premul, bitmap.Data, width * 4);
return surface;
}
Edit: btw, I assume this is a bug in SkiaSharp. The samples/apis that create the buffer for you should probably be zeroing it out. Depending on the platform it can be hard to repro as the memory alloc behaves differently. More or less likely to provide you untouched memory.

GetObject() on bitmap handle from LoadImage() sometimes returns incorrect bitmap size

We are seeing an intermittent problem in which owner drawn buttons under Windows XP that are using a bitmap as a backdrop are displaying the bitmap incorrectly. The window containing multiple buttons that are using the same bitmap file for the bitmap image used for the button backdrop will display and most of the buttons will be correct though in some cases there may be one or two buttons which are displaying the bitmap backdrop reduced to a smaller size.
If you exit the application and then restart it you may see the same behavior of the incorrect display of the icon on the buttons however it may or may not be the same buttons as previously. Nor is this behavior of incorrect display of icons on the buttons always seen. Sometimes it shows and sometimes it does not. Since once we load an icon for a button we just keep it, once the button is displayed incorrectly it will always be displayed incorrectly.
Using the debugger we have finally found that what appears to be happening is that when the GetObject() function is called, the data returned for the bitmap size is sometimes incorrect. For instance in one case the bitmap was 75x75 pixels and the size returned by GetObject() was 13x13 instead. Since this size is used as part of the drawing of the bitmap, the displayed backdrop becomes a small decoration on the button window.
The actual source area is as follows.
if (!hBitmapFocus) {
CString iconPath;
iconPath.Format(ICON_FILES_DIR_FORMAT, m_Icon);
hBitmapFocus = (HBITMAP)LoadImage(NULL, iconPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
if (hBitmapFocus) {
BITMAP bitmap;
int iNoBytes = GetObject(hBitmapFocus, sizeof(BITMAP), &bitmap);
if (iNoBytes < 1) {
char xBuff[128];
sprintf (xBuff, "GetObject() failed. GetLastError = %d", GetLastError ());
NHPOS_ASSERT_TEXT((iNoBytes > 0), xBuff);
}
cxSource = bitmap.bmWidth;
cySource = bitmap.bmHeight;
//Bitmaps cannot be drawn directly to the screen so a
//compatible memory DC is created to draw to, then the image is
//transfered to the screen
CDC hdcMem;
hdcMem.CreateCompatibleDC(pDC);
HGDIOBJ hpOldObject = hdcMem.SelectObject(hBitmapFocus);
int xPos;
int yPos;
//The Horizontal and Vertical Alignment
//For Images
//Are set in the Layout Manager
//the proper attribute will have to be checked against
//for now the Image is centered on the button
//Horizontal Alignment
if(btnAttributes.horIconAlignment == IconAlignmentHLeft){//Image to left
xPos = 2;
}else if(btnAttributes.horIconAlignment == IconAlignmentHRight){//Image to right
xPos = myRect.right - cxSource - 5;
}else {//Horizontal center
xPos = ((myRect.right - cxSource) / 2) - 1;
}
//Vertical Alignment
if(btnAttributes.vertIconAlignment == IconAlignmentVTop){//Image to top
yPos = 2;
}else if(btnAttributes.vertIconAlignment == IconAlignmentVBottom){//Image to bottom
yPos = myRect.bottom - cySource - 5;
}else{//Vertical Center
yPos = ((myRect.bottom - cySource) / 2) - 1;
}
pDC->BitBlt(xPos, yPos, cxSource, cySource, &hdcMem, 0, 0, SRCCOPY);
hdcMem.SelectObject(hpOldObject);
}
Using the debugger we can see that the iconPath string is correct and the bitmap is loaded as hBitmapFocus is not NULL. Next we can see that the call to GetObject() is made and the value returned for iNoBytes equals 24. For those buttons that display correctly the values in bitmap.bmWidth and bitmap.bmHeight are correct however for those that do not the values are much too small leading to an incorrect sizing when drawing the bitmap.
The variable is defined in the class header as
HBITMAP hBitmapFocus;
As part of doing the research for this I found this stack overflow question, GetObject returns strange size and I am wondering if there is some kind of an alignment issue here.
Does the bitmap variable used in the call to GetObject() need to be on some kind of an alignment boundary? While we are using packed for some of our data we are using pragma directives to only specify specific portions of code containing specific structs in include files that need to be packed on one byte boundaries.
Please read this Microsoft KB how to load a bitmap with palette information. It has a great example as well.
On the side note: I do not see anywhere in your code where you call ::DeleteObject(hBitmapFocus). It is very important to call this, as you can run out of GDI objects very quickly.
It is always a good idea to use Windows Task manager to see that your program does not exhaust the GDI resources. Just add "GDI Objects" column to the Task Manager and see that the number of objects is not constantly increasing in your app, but stays within an expected range, similar to other programs

Variable item height in TreeView gives broken lines

Wee.
So I finally figured out how the iIntegral member of TVITEMEX works. The MSDN docs didn't think to mention that setting it while inserting an item has no effect, but setting it after the item is inserted works. Yay!
However, when using the TVS_HASLINES style with items of variable height, the lines are only drawn for the top part of an item with iIntegral > 1. E.g. if I set TVS_HASLINES and TVS
Here's what it looks like (can't post images WTF?)
Should I manually draw more of the lines in response to NM_CUSTOMDRAW or something?
Yes, Windows doesn't do anything with the blank space obtained from changing the height.
From the MSDN:
The tree-view control does not draw in the
extra area, which appears below the
item content, but this space can be
used by the application for drawing
when using custom draw. Applications
that are not using custom draw should
set this value to 1, as otherwise the
behavior is undefined.
Alright, problem solved.
I failed to find an easy answer, but I did work around it the hard way. It's basically just drawing the extra line segments in custom draw:
// _cd is the NMTVCUSTOMDRAW structure
// ITEMHEIGHT is the fixed height set in TreeView_SetItemHeight
// linePen is HPEN of a suitable pen to draw the lines (PS_ALTERNATE etc.)
// indent is the indentation size returned from TreeView_GetIndent
case CDDS_ITEMPREPAINT : {
// Expand line because TreeView is buggy
RECT r = _cd->nmcd.rc;
HDC hdc = _cd->nmcd.hdc;
HTREEITEM hItem = (HTREEITEM) _cd->nmcd.dwItemSpec;
if( r.bottom - r.top > ITEMHEIGHT ) {
HGDIOBJ oldPen = SelectObject( hdc, linePen );
// Draw any lines left of current item
HTREEITEM hItemScan = hItem;
for( int i = _cd->iLevel; i >= 0; --i ) {
// Line should be drawn only if node has a next sibling to connect to
if( TreeView_GetNextSibling( getHWnd(), hItemScan ) ) {
// Lines seem to start 17 pixels from left edge of control. But no idea
// where that constant comes from or if it is really constant.
int x = 17 + indent * i;
MoveToEx( hdc, x, r.top + ITEMHEIGHT, 0 );
LineTo( hdc, x, r.bottom );
}
// Do the same for the parent
hItemScan = TreeView_GetParent( getHWnd(), hItemScan );
}
SelectObject( hdc, oldPen );
}
}
The pattern from the PS_ALTERNATE brush sometimes doesn't align perfectly with line drawn by the control, but that's hardly noticeable. What's worse is that even though I have the latest common controls and all the service packs and hotfixes installed, there are still bugs in TreeView documented way back in 2005. Specifically, the TreeView doesn't update its height correctly. The only workaround I've found for that is to force some collapsing/expanding of nodes and do a few calls to InvalidateRect.
If the variable-height nodes are at the root level, though, there doesn't appear to be anything you can do. Luckily I don't need that.

Resizing and saving an image in WinMobile and .NET CF throws OutOfMemoryException

I have a WinMobile app which allows the user the snap a photo with the camera, and then use for for various things. The photo can be snapped at 1600x1200, 800x600 or 640x480, but it must always be resized to 400px for the longest size (the other is proportional of course). Here's the code:
private void LoadImage(string path)
{
Image tmpPhoto = new Bitmap(path);
// calculate new bitmap size...
double width = ...
double height = ...
// draw new bitmap
Image photo = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(photo))
{
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, photo.Width, photo.Height));
int srcX = (int)((double)(tmpPhoto.Width - width) / 2d);
int srcY = (int)((double)(tmpPhoto.Height - height) / 2d);
g.DrawImage(tmpPhoto, new Rectangle(0, 0, photo.Width, photo.Height), new Rectangle(srcX, srcY, photo.Width, photo.Height), GraphicsUnit.Pixel);
}
tmpPhoto.Dispose();
// save new image and dispose
photo.Save(Path.Combine(config.TempPath, config.TempPhotoFileName), System.Drawing.Imaging.ImageFormat.Jpeg);
photo.Dispose();
}
Now the problem is that the app breaks in the photo.Save call, with an OutOfMemoryException. And I don't know why, since I dispose the tempPhoto (with the original photo from the camera) as soon as I can, and I also dispose the Graphics obj. Why does this happen? It seems impossible to me that one can't take a photo with the camera and resize/save it without making it crash :( Should I restor t C++ for such a simple thing?
Thanks.
Have you looked at memory usage with each step to see exactly where you're using the most? You omitted your calculations for width and height, but assuming they are right you would end up with photo requiring 400x300x3 (24bits) == 360k for the bitmap data itself, which is not inordinately large.
My guess is that even though you're calling Dispose, the resources aren't getting rleased, especially if you're calling this method multiple times. The CF behaves in an unexpected way with Bitmaps. I call it a bug. The CF team doesn't.

Resources