Since CollieMouse just popped up again in a different topic, here's an issue I have been fighting since quite some time: What is the correct code for redrawing the views during an ongoing "camera movement operation", like "clicking and dragging on the camera movement icons in the view window"?
Yes, I know it's DrawViews() but I have never been able to make it work satisfactorily under all circumstances. Here's what I do:
-
I have a Space Mouse which sends messages (through the Windows window API) to an invisible window that is polled in a different thread (as I cannot receive Windows messages through the C4D API, and polling in the main thread with the usual loop would lock it up). This part is working fine.
-
This thread translates the coordinate systems, evaluates the camera settings and moves the camera according to the Space Mouse movement, and then sends a "do a refresh" message to my C4D Dialog which receives it through the CoreMessage() method. Works fine too, at first glance.
-
The following code is handling the redraw
BaseDocument* doc = GetActiveDocument();
if (doc != nullptr)
{
BaseContainer* storage = CollieMousePrefs::GetCurrentSettings();
if (storage != nullptr)
{
Float64 currentTime = GeGetMilliSeconds();
BaseDraw* basedraw = doc->GetActiveBaseDraw();
if (basedraw != nullptr)
{
DRAWFLAGS flags = DRAWFLAGS_0 | DRAWFLAGS_NO_THREAD;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_ONLY_BASEDRAW, STORAGEDEFAULT_DRAWFLAGS_ONLY_BASEDRAW)) flags |= DRAWFLAGS_ONLY_BASEDRAW;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_INMOVE, STORAGEDEFAULT_DRAWFLAGS_INMOVE)) flags |= DRAWFLAGS_INMOVE;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_NO_REDUCTION, STORAGEDEFAULT_DRAWFLAGS_NO_REDUCTION)) flags |= DRAWFLAGS_NO_REDUCTION;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_NO_EXPRESSIONS, STORAGEDEFAULT_DRAWFLAGS_NO_EXPRESSIONS)) flags |= DRAWFLAGS_NO_EXPRESSIONS;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_INDRAG, STORAGEDEFAULT_DRAWFLAGS_INDRAG)) flags |= DRAWFLAGS_INDRAG;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_ONLY_CAMERAEXPRESSION, STORAGEDEFAULT_DRAWFLAGS_ONLY_CAMERAEXPRESSION)) flags |= DRAWFLAGS_ONLY_CAMERAEXPRESSION;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_ONLY_HIGHLIGHT, STORAGEDEFAULT_DRAWFLAGS_ONLY_HIGHLIGHT)) flags |= DRAWFLAGS_ONLY_HIGHLIGHT;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_NO_HIGHLIGHT_PLANE, STORAGEDEFAULT_DRAWFLAGS_NO_HIGHLIGHT_PLANE)) flags |= DRAWFLAGS_NO_HIGHLIGHT_PLANE;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_FORCEFULLREDRAW, STORAGEDEFAULT_DRAWFLAGS_FORCEFULLREDRAW)) flags |= DRAWFLAGS_FORCEFULLREDRAW;
if (storage->GetBool(IDD_COLLIEMOUSEDIALOG_DRAWFLAGS_NO_ANIMATION, STORAGEDEFAULT_DRAWFLAGS_NO_ANIMATION)) flags |= DRAWFLAGS_NO_ANIMATION;
DrawViews(flags, basedraw);
// EventAdd();
Int32 timerms = (Int32)storage->GetFloat(IDD_COLLIEMOUSEDIALOG_REDRAWAFTER, STORAGEDEFAULT_REDRAWAFTER);
SetTimer(timerms);
}
lastTime = currentTime;
}
}
This is what I'd expect to be the most basic C4D redraw -- you can ignore the timer code, as it only serves to trigger a global refresh after n milliseconds to emulate a "mouse release" or "key release" which naturally don't exist in a Space Mouse. The flags are read from the user interface so I can experiment with them. Other than that, there is nothing special.
And under simple circumstances, this works fine. In fact, I had been working with the plugin for quite a while until I came to the point where the redraw started to show a distinctly worse behavior than C4D's own view buttons.
If there is an animated character (like the ones provided in the content library), the views start lagging, the reduced view with only the boxes is shown, and the status bar starts to show the progress bar for a fraction of a second. So, the system is clearly doing something that takes a lot of time which I do not want the system to do.
Here's what I know:
- The NO_ANIMATION flag needs to be set, otherwise C4D would evaluate the animation and overwrite any camera movement with the camera's current animation values.
- FORCEFULLREDRAW is normally not set. NO_REDUCTION and INMOVE are the flags I do set by default.
- The HIGHLIGHT flags are not what I want.
- The NO_EXPRESSIONS and ONLY_CAMERAEXPRESSION flags do what I think they do, but they do not have an effect on the slow redraw as far as my experiments went.
- It's not an issue of the amount of polygons - I can redraw millions of polys in a static scene without issue.
- It's not an issue of getting the values from the Preferences container either, or the issue would always be present.
- I am redrawing only the active window (any secondary view will be refreshed when the timer runs out) so the amount of redrawing should be minimized already.
- C4D is able to do the refresh on my system in the required way with no issues - as the C4D view buttons prove. If I use these, the refresh happens as expected.
- I do not need to EventAdd() after the redraw.
- DrawViews() must be called from the main thread, and due to the Windows polling the Space Mouse must be connected to a parallel thread so there is no way around the internal message sending to trigger the refresh.
Here's what I do not know, even after trying out many, many combinations of flags in the call:
- Which combination of flags is exactly to be used when I redraw the view in the middle of a user-driven camera movement? In other words, what exactly is the code for the redraw e.g. when I continuously use the move/rotate/scale icons in the view window frame, or any keyboard/mouse combinations to the same effect?
- I do not see the status bar showing a progress bar when I use C4D's own icons, so clearly in my code the system tries to do something really compute-intensive. But with NO_ANIMATION set, what would that be? (And more important, how do I get rid of it?)
- Is there perhaps any basic issue with calling DrawViews() in this way, from a dialog, in CoreMessage, triggered by a different thread? I would not expect so but perhaps there are side effects.
- Are there hidden flags that I need to set? I would not expect so either.
I am currently still compiling for the R19, but I don't think it makes a difference, as all previous C4D versions react similarly (as far as I still was able to verify).
Thanks for looking into the issue.