I have a Direct3D11 scene set up in SlimDX in a window. The rendering is done in a separate thread.
Is there a way to keep the renderer from stretching the image when it draws to the resized control? I've tried ModeDescription.Scaling = DisplayModeScaling.Centered and it doesn't seem to have any effect. Is there something I'm missing?
(I already am updating the render target size. The reason I ask this is that when I resize the control it stretches the image to fill the control for a split second before the render target gets updated with the new size. This has the result that as I resize it, it flickers terribly. If I could reset the render target just slightly faster it might get rid the the flicker. Keeping the image in the corner without scaling it is perfectly fine since ultimately it won't be scaling at all.)
Workaround 1: One can put the render target inside a control. When the window resizes only resize the control though a special method that first stops the rendering, then update the buffers and begins rendering again. It's a bit of hack, though. I have to wait for the render cycle to complete, then block it, then resize, then unblock.
Workaround 2: A similar workaround is to check for a resize flag in the render loop rather than interrupting it. The renderer should be able to draw directly without scaling. This is much more acceptable performancewise. However, a blocking call to the UI thread must be made to execute the actual resize.
Workaround 3: Rather than resizing the control at all, one could make it as large as the maximum size it could be, but clipped (inside the window). No resize is necessary, but a scissor rectangle must be maintained in a similar manner to the workarounds above unless you don't mind rendering a whole lot of offscreen pixels. Rendering twenty or so extra rows and columns of pixels does have the favorable effect of supplying immediate image at the edge when the window is resized back larger.
Ideally the resize should be done directly from the UI thread (no fooling around with delaying it and reentering the UI thread from the render thread). It's not the render thread's responsibility and it slows it down. Likewise, the buffer resize should be done in the render thread for maximum performance (no fooling around with waiting/blocking/resizing/unblocking). The only reason this does not work is that the render thread scales if the resize is done before the buffers are resized.
So my question still stands: Is there a way to render without scaling?
I am going to answer this in terms of the raw Win32 APIs involved, which might require a bit of finesse to translate to a managed .NET environment & SlimDX.
When you are dragging or resizing a window, windows basically hijacks your message pump and creates a new one specifically designed to do the resizing logic efficiently. This operation is more or less modal until it is completed. Many messages you would normally get are quite literally blocked until the resize or drag is completed. In the app terms you get a WM_ENTERSIZEMOVE when this behavior begins, and either WM_EXITSIZEMOVE or WM_CAPTURECHANGED when it ends. You need to check both of these messages, as alt-tabing out when doing a drag will send WM_CAPTURECHANGED and never a WM_EXITSIZEMOVE!
All this means that when you get a WM_ENTERSIZEMOVE you can set a flag and know that all WM_SIZE and WM_MOVE messages that occur afterwards are for the drag operation. Typically resizing rendertargets and tracking down and de-allocating all default pool resources is a very slow operation, and well worth defering until the drag/resize has completed. This has the side effect of making the window stretch which is exactly the same problem you are describing here, and you want to fix that.
It should be possible to add special handlers in WM_SIZE, WM_MOVE, or WM_SIZING, and WM_MOVING that forces a syncronous render and repaint via SendMessage (as opposed to PostMessage) when they occur, but you will need to make sure you only do this when inside the modal loop owned by WM_ENTERSIZEMOVE.
I would recommend either forcing the window to a fixed size (which seems rather common) or not redrawing the D3D control until the changes are done (that or simply clear it black).
There seems to be a way to do what you want, as I have seen games capable of changing size with no flicker, but I've no idea how that's done, unfortunately. Locking the window size and providing a menu was the old solution.
Related
I resize a floating window, let's say to some size WxH pixels. Then I change to tiling mode, so the window gets resized automatically to some new size, let's say W'xH' pixels. Now suppose I switch the window back to floating mode.
What I Want: The window automatically resizes to the last size, i.e., WxH.
Current Situation: The window just becomes floating, but still has the size W'xH'.
Is there any way of making this happen? Like some way we can save the dimenisons of a window everytime it's resized, and whenever a window enters floating mode, apply the last known size from that application?
I know it probably sounds very dumb, I'm so sorry.
There is multiple ways. The "simple" way is to use client.connect("property::floating", function(c) if c.floating then restore(c) else save(c) end) where you implement both save and restore yourself by calling c:geometry().
The more advanced way would be to use request::geometry and awful.placement built-in geometry memento support. That's preferred since it allows to prevent the client from flickering between 2 sizes. However it is much more complicated to pull off.
You can use awesome-remember-geometry from berlam.
https://github.com/berlam/awesome-remember-geometry
I'm using QMdiSubWindow, I want to capture any input which is attempting to modify the size/shape/position of the window and filter/modify the resulting position and size so that the widget is aligned to a grid.
QResizeEvent seems to be too late, i.e. the window has already resized, layouts have already been calculated and often a complete repaint of the widget has been scheduled.
resizeEvent and eventFilter both just allow me to learn about the resize that has just occurred and 'undo' it if the change was undesirable, this is a massive performance problem for me (embedded device, slow graphics).
I'm currently catching QMouseEvents and modifying the reported cursor positions but this is messy and doesn't catch all cases where the window geometry changes.
If you are resizing by dragging window border than u should catch event like QEvent::NonClientAreaMouseButtonPress, checkout for more here -
QEvent::Type
You can install watcher for checking out of changing window sizes and having a flag about NonClientDrag(for example). But the question is what to do when user pushing "maximize" button or just a win+↑ (in WinOS), in other hand this changes are almost immediate, so you should not worry about them.
[qt 4.8]
To get correct window dimensions including its frame, I do the following (as described e.g. here, see comment from Daniel Hedberg).
mainWindow.move(-50000, -50000);
mainWindow.show();
// do something with the window dimensions
mainWindow.move(0, 0);
mainWindow.show()
This works fine, however, I have a problem with the move(0,0) call: It makes the window always appear at position (0,0), while I would like to have the default behaviour, this is, the application only suggests to the window manager that (0,0) is a good place to position the window, and the WM might decide to shift it if necessary to avoid overlapping. In other words, I would like to switch back to Qt's default behaviour as if there weren't a call to move at all.
How can I do that?
One solution is to store Windows original position and use that. For extra safety (in case screen resolution changes), check that entire window still fits on screen and move and even resize if it does not.
A hacky alternative would be to create and open empty, possibly transparent dummy window of the same size and see where it gets positioned. Then move the original there and close the dummy one. Reading your question carefully, I think this would do what you are after.
I don't know of a Qt way to ask Window Manager to reposition the window, so if you really need that, specify the OS etc details.
Looking into the source code of Qt, I can now partially answer my own question: To convert a call to move into a suggestion for positioning instead of a request, do this:
mainWindow.move(100, 100);
mainWindow.setAttribute(Qt::WA_Moved, false);
mainWindow.show();
I've tested the code under X11 using Qt 4.8.4, and hopefully it works with on other platforms too.
Unfortunately, this doesn't solve the very problem I have, namely to use show to get the (decorated) dimensions of an off-screen window which then gets moved to the screen, calling show again. It seems that the first call to show directly sets platform-specific window manager flags which aren't completely reset and reevaluated in the second call. Actually, I'm going to think that this is a bug in Qt, so I'll report it accordingly.
I have a simple Flex application that is a panel with a repeater inside of it; albeit a little simplified, it is like such:
<mx:Panel id="pnl">
<mx:Repeater id="rp">
<mx:Label text = "foo" />
</mx:Repeater>
</mx:Panel>
I am then embedding this Flex application into an HTML wrapper. I am then attempting to dynamically re size the embedded Flash object in the HTML as the Flex panel changes size (thus allowing the Flex application to consume as much of the HTML page as it needs).
I am doing this by doing the following actionscipt:
pnl.addEventListener(ResizeEvent.RESIZE,function(event:Event):void {
ExternalInterface.call("resize",event.target.height);
});
which in turn calls this javascript function:
function resize(height) {
// the embed or object that contains the flex app
var e = document.getElementById('flex_object');
if(e) e.height = height;
}
This seems to work perfect in IE, however I get strange results in Firefox / Safari, the repeater works for n number of times, and then the text seems to get cut off / disappear in the repeater, see the attached image:
alt text http://img528.imageshack.us/img528/9538/rpre0.jpg
Can anyone explain why this is happening, and if there are any workarounds / ways of doing the same thing?
I'm currently working in the same thing (a swf that dynamically changes it's height depending on the content it's currently holding). I also had a similar problem to yours trying to make a multi-line button.
I'm new to flex but I managed to solve the problem manually invoking the updateDisplayList() of the container... I think it "forces" a render somewhere... it's parameters are the width and height of some area where the changes happen. Sorry for not knowing the details... But it worked for me.
Why not simply using percent width and height on your HTML page for your Flash object ? This way you event don't have to do anything to resize your SWF...
That's very strange - it looks like Firefox/Safari are expanding the draw area of the embed, but somehow Flash is not getting the message that it needs to render the new pixels.
You could probably work around this by doing something to force Flash to update itself, but since the communication between the browsers and the embed seems to be confused it would probably be less hackish to take a different approach, that fits into the browsers' event flow without bugging.
For example, instead of resizing the embed, you might try putting Flash inside a DIV, setting the Flash's size to 100%, and then resizing the DIV. That seems a lot less likely to misbehave.
My experience is that Flex's resizing abilities are... funny. Sometimes they work the way one would expect, other times they do not. There are a couple of things you could try: first, trace the value you expect to get in Flex for the height or even ExternalInterface.call("alert",event.target.height); This will let you know if it is a JavaScript or a Flex problem for sure (but I suspect it is Flex).
Your problem might have to do with the scaling of the component:
Setting [the height] property causes a resize event to be dispatched. See the resize event for details on when this event is dispatched. If the component's scaleY property is not 100, the height of the component from its internal coordinates will not match. Thus a 100 pixel high component with a scaleY of 200 will take 100 pixels in the parent, but will internally think it is 50 pixels high.
If it is Flex and that does not help, I would try using callLater in front of the ExternalInterface call, often that will allow Flex enough time to figure out what the heck it is doing. Occasionally, setTimeout is needed, but I find that awkward.
I'm developing a Flex 2 application, and I noticed that part of the library which is responsible for moving GUI windows (TitleWindows) around when you drag them with the mouse gets confused if there is a clickable (buttonMode = true) sprite beneath them. When I say confused, I mean that the window is moved around normally for a while, but then at some point "jumps" into the upper left corner of the flash app, and makes very minor movement there. Then at some other point it jumps back. It is more difficult to explain than to experience, so please go and see for yourself. Here's how to reproduce the problem:
Go to http://www.panocast.com
In the left sidebar, choose "Real Estate"
Just below the bottom right corner of the flash window, choose "high res" by clicking on the rightmost icon.
When (part of) the video loads, click on the staircase. A TitleWindow will pop up.
Try dragging it around the screen. When the mouse cursor is moved above one of the clickable areas (like the staircase), the window is misplaced.
(Sorry, but can't give you a direct link, part of the page is generated dynamically.)
(What's makes the problem even more interesting is that for me, in "low res" mode, the problem does not occur! There is very little difference between the various modes.) I would really appreciate if someone told me what was going on here and how it can be fixed.
I'm not sure if it matters, but the underlying sprite is actually not just plain sprite, rather it is a Papervision3D renderer object with some 3D elements in it. I'm telling this because it is possible that the incorrect mouse coordinates somehow come from the texture UV mapped on the clickable objects.
I've managed to replicate this on the low res mode as well, so I don't think it's related to the resolution.
This looks to be because the MouseEvent is being handled by the TitleWindow AND the Papervision3D window. Perhaps you need to force stopImmediatePropagation() on one or the other? Or maybe switch off the MouseEvent handling for the Pv3D window when the TitleWindow pops up?
That's a tough one to debug without some source; something's apparently calling either move() or setting x and y properties on that TitleWindow and scheduling it be moved.
When I first read the post, it "smelled" like maybe a rotation miscalculation somewhere (using Math.atan vs. Math.atan2 can sometimes have that kind of effect), so you're right, it could have something to do with PaperVision, assuming you're not using Math.atan or setting rotation properties yourself anywhere. Just thought I'd mention it, though it's probably not happening in your case. You never know, though. ;)
More likely the LayoutManager is moving the component in response to a property change on the component. The Flex docs explain that in addition to setting its x and y properties, and explicit calls to move(), a UIComponent's move event can also be triggered when any of the following other properties change:
minWidth
minHeight
maxWidth
maxHeight
explicitWidth
explicitHeight
PaperVision or no, maybe that info might help you isolate the source of the move. Good luck.
I got this figured out. Apparently, this is a Papervision3D problem. There is a class deep inside Papervision3D called VirtualMouse, which is supposed to generate MouseEvents programmatically. This happens, for example, when the user interacts with any of the interactive objects on stage, e.g., a Plane with an interactive material on it (as in my case).
The problem is that the x and y coordinates of the generated event represent texture UV coordinates (just as I suspected) and not real world screen coordinates. When a TitleWindow (or any Panel object) is dragged, a "mouseMove" handler (among others) is added to the SystemManager, which then uses the stageX and stageY properties of the event object to determine the new position of the window. Unfortunately for VirtualMouse's mouse events, these are invalid, since the original x,y coordinates, which are probably used to determine the global stage coordinates are, as I said, not screen coordinates.
Honestly, I'm still unsure whether the events dispatched by VirtualMouse are used anywhere within Papervision3D itself, or they are just offered for convenience, but they sure make it difficult to integrate a viewport into a Flex program. Assuming that such events aren't necessary for PV3D itself, there is a one-liner fix for my problem, which must be added right after the creation of the viewport:
viewport.interactiveSceneManager.virtualMouse.
disableEvent(MouseEvent.MOUSE_MOVE);
BTW., there was a very similar (or rather, as it turns out, the same) bug with dragging sliders, also fixed by this line.