Hi,
It seems the changes related to the R21 GUI have introduced quite a lag in the messaging system to draw GeUserArea
. I have this following dummy plugin, consisting of a DescriptionTool
and a GeUserArea
which is running fine on R20, but has quite some lag when the same code is running in R21. The R20 version of the plugin is even a debug build, while the R21 one is a release, just to make sure ...
Main.cpp
// ========================
// Cinema 4D C++ plugin
//
// PluginName: Test
// Dummy "empty" plugin
// ========================
// Main.cpp
#include "c4d.h"
#include "MyUserArea.h"
#include "MyDescriptionTool.h"
// ====================================
// Plugin Main
// ====================================
Bool PluginStart(void)
{
ApplicationOutput("Test"_s);
RegisterCommandPlugin(MYCOMMAND_PLUGIN_ID, "Test"_s, 0, AutoBitmap("icon.png"_s), "Test"_s, NewObjClear(MyCommand));
RegisterToolPlugin(MYDESCRIPTIONTOOL_PLUGIN_ID, "MyDescriptionTool"_s, 0, AutoBitmap("icon.png"_s), "MyDescriptionTool"_s, NewObjClear(MyDescriptionTool));
return true;
}
void PluginEnd(void)
{
}
Bool PluginMessage(Int32 id, void * data)
{
switch (id) {
case C4DPL_INIT_SYS:
if (!g_resource.Init())
return false;
return true;
case C4DMSG_PRIORITY:
return true;
case C4DPL_BUILDMENU:
break;
case C4DPL_ENDACTIVITY:
return true;
}
return false;
}
UserArea.h
// MyUserArea.h
#include "c4d.h"
#include "lib_clipmap.h"
// Dummy IDs - for demonstration purposes only
#define MYCOMMAND_PLUGIN_ID 1000000
#define MYDIALOG_PLUGIN_ID 1000001
// gadget IDs
#define IDC_USERAREA 50000
// ====================================
// GeUserArea
// ====================================
class MyUserArea : public GeUserArea
{
INSTANCEOF(MyUserArea, GeUserArea)
public:
MyUserArea(void);
virtual ~MyUserArea();
virtual Bool Init(void);
virtual Bool GetMinSize(Int32& w, Int32& h);
virtual void Sized(Int32 w, Int32 h);
virtual Bool InitValues(void);
virtual void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg);
// custom methods
void SetHoveredPolygon(BaseObject* object, const Int32& polygon);
private:
Int32 mWidth;
Int32 mHeight;
AutoAlloc<GeClipMap> mClipmap;
BaseObject* mObject;
Int32 mHoveredPolygon;
};
// ====================================
// GeDialog
// ====================================
class MyDialog : public GeDialog
{
public:
MyDialog(void);
virtual ~MyDialog(void);
virtual Bool CreateLayout(void);
virtual void DestroyWindow(void);
MyUserArea mUserArea;
};
// ====================================
// CommandData
// ====================================
class MyCommand : public CommandData
{
INSTANCEOF(MyCommand, CommandData)
public:
virtual Bool Execute(BaseDocument* doc, GeDialog* parentManager);
MyDialog dlg;
};
UserArea.cpp
// MyUserArea.cpp
#include "c4d.h"
#include "lib_clipmap.h"
#include "MyUserArea.h"
// ====================================
// GeUserArea
// ====================================
MyUserArea* g_UserArea = nullptr;
MyUserArea::MyUserArea(void) : mWidth(0), mHeight(0), mObject(nullptr), mHoveredPolygon(NOTOK) {}
MyUserArea::~MyUserArea(void) {}
Bool MyUserArea::Init(void)
{
return true;
}
Bool MyUserArea::GetMinSize(Int32& w, Int32& h)
{
w = 100;
h = 100;
return true;
}
void MyUserArea::Sized(Int32 w, Int32 h)
{
mWidth = w;
mHeight = h;
}
Bool MyUserArea::InitValues(void)
{
mWidth = GetWidth();
mHeight = GetHeight();
return true;
}
void MyUserArea::DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
{
OffScreenOn();
const Int32 w = GetWidth();
const Int32 h = GetHeight();
const Int32 size = (w < h) ? w : h;
const Int32 halfsize = size / 2;
if (!mClipmap)
return;
mClipmap->Init(w, h, 32);
mClipmap->BeginDraw();
Vector color(64);
mClipmap->SetColor(SAFEINT32(color.x), SAFEINT32(color.y), SAFEINT32(color.z), 255);
mClipmap->FillRect(0, 0, w, h);
if (mObject && mObject->IsInstanceOf(Opolygon) && (mHoveredPolygon != NOTOK))
{
PolygonObject* polyObj = ToPoly(mObject);
const CPolygon* polyR = polyObj->GetPolygonR();
const Vector* pointR = polyObj->GetPointR();
const Int32 polygonCount = polyObj->GetPolygonCount();
const Int32 pointCount = polyObj->GetPointCount();
Float lenxinv, lenyinv, lenzinv;
Vector mapCenter, mapSize, vMin, vMax;
vMin.x = 100000.0;
vMin.y = 100000.0;
vMin.z = 100000.0;
vMax.x = -100000.0;
vMax.y = -100000.0;
vMax.z = -100000.0;
for (Int32 ndx = 0; ndx < pointCount; ndx++)
{
Vector pt = pointR[ndx];
if (pt.x < vMin.x) vMin.x = pt.x;
if (pt.x > vMax.x) vMax.x = pt.x;
if (pt.y < vMin.y) vMin.y = pt.y;
if (pt.y > vMax.y) vMax.y = pt.y;
if (pt.z < vMin.z) vMin.z = pt.z;
if (pt.z > vMax.z) vMax.z = pt.z;
}
mapSize.x = Abs(vMax.x - vMin.x);
mapSize.y = Abs(vMax.y - vMin.y);
mapSize.z = Abs(vMax.z - vMin.z);
mapCenter.x = vMin.x + (mapSize.x*0.5);
mapCenter.y = vMin.y + (mapSize.y*0.5);
mapCenter.z = vMin.z + (mapSize.z*0.5);
if (mapSize.x != 0.0) lenxinv = size / mapSize.x; else lenxinv = 0.0;
if (mapSize.y != 0.0) lenyinv = size / mapSize.y; else lenyinv = 0.0;
if (mapSize.z != 0.0) lenzinv = size / mapSize.z; else lenzinv = 0.0;
for (Int32 i = 0; i < polygonCount; ++i)
{
Vector pt_a = (pointR[polyR[i].a] - mapCenter);
Vector pt_b = (pointR[polyR[i].b] - mapCenter);
Vector pt_c = (pointR[polyR[i].c] - mapCenter);
Vector pt_d = (pointR[polyR[i].d] - mapCenter);
const Int32 nvert = polyR[i].IsTriangle() ? 3 : 4;
iferr(GE_POINT2D* vPoints = NewMem(GE_POINT2D, nvert))
break;
vPoints[0].x = SAFEINT32(pt_a.x*lenxinv) + halfsize;
vPoints[0].y = SAFEINT32(-pt_a.y*lenyinv) + halfsize;
vPoints[1].x = SAFEINT32(pt_b.x*lenxinv) + halfsize;
vPoints[1].y = SAFEINT32(-pt_b.y*lenyinv) + halfsize;
vPoints[2].x = SAFEINT32(pt_c.x*lenxinv) + halfsize;
vPoints[2].y = SAFEINT32(-pt_c.y*lenyinv) + halfsize;
if (nvert == 4)
{
vPoints[3].x = SAFEINT32(pt_d.x*lenxinv) + halfsize;
vPoints[3].y = SAFEINT32(-pt_d.y*lenyinv) + halfsize;
}
if (i == mHoveredPolygon)
mClipmap->SetColor(255, 255, 255, 255);
else
mClipmap->SetColor(128, 128, 128, 255);
mClipmap->FillPolygon(nvert, vPoints);
DeleteMem(vPoints);
}
}
mClipmap->EndDraw();
DrawBitmap(mClipmap->GetBitmap(), 0, 0, w, h, 0, 0, w, h, BMP_ALLOWALPHA);
}
void MyUserArea::SetHoveredPolygon(BaseObject* object, const Int32& polygon)
{
mObject = object;
mHoveredPolygon = polygon;
Redraw();
}
// ====================================
// GeDialog
// ====================================
MyDialog::MyDialog(void) {}
MyDialog::~MyDialog(void) {}
Bool MyDialog::CreateLayout(void)
{
Bool res = GeDialog::CreateLayout();
GroupBegin(0, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, ""_s, 0);
GroupBorderSpace(4, 4, 4, 4);
// userarea for drawing
GroupBegin(0, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, String(), 0);
C4DGadget* ua = AddUserArea(IDC_USERAREA, BFH_SCALEFIT | BFV_SCALEFIT, 400, 400);
if (ua)
AttachUserArea(mUserArea, IDC_USERAREA);
GroupEnd();
GroupEnd();
return res;
}
void MyDialog::DestroyWindow(void)
{
if (g_UserArea)
g_UserArea = nullptr;
}
// ====================================
// CommandData
// ====================================
Bool MyCommand::Execute(BaseDocument* doc, GeDialog* parentManager)
{
if (!dlg.IsOpen())
{
dlg.Open(DLG_TYPE::ASYNC, MYDIALOG_PLUGIN_ID, -1, -1, 0, 0, 0);
g_UserArea = &dlg.mUserArea;
}
else
{
if (g_UserArea)
g_UserArea->Redraw();
}
return true;
}
DescriptionTool.h
// MyDescriptionTool.h
#pragma once
#include "c4d.h"
// Dummy IDs - for demonstration purposes only
#define MYDESCRIPTIONTOOL_PLUGIN_ID 1000002
class MyDescriptionTool : public DescriptionToolData
{
public:
virtual Int32 GetToolPluginId() { return MYDESCRIPTIONTOOL_PLUGIN_ID; }
virtual const String GetResourceSymbol() { return String("MyDescriptionTool_desc"_s); } // return the resource description filename (without extension)
virtual Bool InitTool(BaseDocument* doc, BaseContainer& data, BaseThread* bt);
virtual void FreeTool(BaseDocument* doc, BaseContainer& data);
virtual void InitDefaultSettings(BaseDocument* doc, BaseContainer& data);
virtual Int32 GetState(BaseDocument* doc);
virtual Bool GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Float x, Float y, BaseContainer& bc);
virtual TOOLDRAW Draw(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, BaseDrawHelp* bh, BaseThread* bt, TOOLDRAWFLAGS flags);
private:
Float mX, mY;
Int32 mPolygon;
};
DescriptionTool.cpp
// MyDescriptionTool.cpp
// ===== includes =====
#include "c4d.h"
#include "MyDescriptionTool.h"
#include "MyUserArea.h"
// resources
//#include "MyDescriptionTool_desc.h"
extern MyUserArea* g_UserArea;
Bool MyDescriptionTool::InitTool(BaseDocument* doc, BaseContainer& data, BaseThread* bt)
{
if (!DescriptionToolData::InitTool(doc, data, bt))
return false;
mX = mY = -1.0f;
mPolygon = NOTOK;
return true;
}
void MyDescriptionTool::FreeTool(BaseDocument* doc, BaseContainer& data)
{
DescriptionToolData::FreeTool(doc, data);
}
void MyDescriptionTool::InitDefaultSettings(BaseDocument* doc, BaseContainer& data)
{
DescriptionToolData::InitDefaultSettings(doc, data);
}
Int32 MyDescriptionTool::GetState(BaseDocument* doc)
{
return CMD_ENABLED;
}
Bool MyDescriptionTool::GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Float x, Float y, BaseContainer& bc)
{
BaseObject* object = doc->GetActiveObject();
if (!object)
return true;
mPolygon = NOTOK;
if (bc.GetId() == BFM_CURSORINFO_REMOVE)
{
// cursor leaves the viewport
mX = -1; mY = -1;
if (g_UserArea)
g_UserArea->SetHoveredPolygon(object, mPolygon);
DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_ANIMATION, bd);
return true;
}
mX = x;
mY = y;
bc.SetString(RESULT_BUBBLEHELP, "MyDescriptionTool"_s);
// prepare the viewport select
Int32 l, t, r, b, w, h;
bd->GetFrame(&l, &t, &r, &b);
// in contrary to python, in C++ we need to add 1
// or ViewportSelect->Init will fail
w = r - l + 1;
h = b - t + 1;
if (x < 0 || x >= w || y < 0 || y >= h)
{
if (g_UserArea)
g_UserArea->SetHoveredPolygon(object, mPolygon);
DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_ANIMATION, bd);
return true;
}
AutoAlloc<ViewportSelect> viewportSelect;
if (viewportSelect && viewportSelect->Init(w, h, bd, object, Medges, true, VIEWPORTSELECTFLAGS::NONE))
{
Int32 vpsX = SAFEINT32(x);
Int32 vpsY = SAFEINT32(y);
Int32 radius = 10;
const ViewportPixel* vpPixel = viewportSelect->GetNearestPolygon(object, vpsX, vpsY, radius);
mPolygon = vpPixel ? vpPixel->i : -1;
if (g_UserArea)
g_UserArea->SetHoveredPolygon(object, mPolygon);
}
DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_ANIMATION, bd);
return true;
}
TOOLDRAW MyDescriptionTool::Draw(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, BaseDrawHelp* bh, BaseThread* bt, TOOLDRAWFLAGS flags)
{
if (mPolygon == NOTOK)
return TOOLDRAW::HANDLES | TOOLDRAW::AXIS;
if (flags == TOOLDRAWFLAGS::NONE)
{
BaseObject* object = doc->GetActiveObject();
if (object)
{
PolygonObject* polyObj = ToPoly(object);
Matrix mg = polyObj->GetMg();
const CPolygon* polyR = polyObj->GetPolygonR();
const Vector* pointR = polyObj->GetPointR();
if (polyR && pointR && (mPolygon < polyObj->GetPolygonCount()))
{
// prepare matrix for drawin in viewport, use z offset 6 to draw on top
Int32 lineZoffset = 6;
bd->SetMatrix_Matrix(polyObj, mg, lineZoffset);
const Vector selprevColor = GetViewColor(VIEWCOLOR_SELECTION_PREVIEW);
Vector p[4] = { pointR[polyR[mPolygon].a], pointR[polyR[mPolygon].b], pointR[polyR[mPolygon].c], pointR[polyR[mPolygon].d] };
Vector f[4] = { selprevColor, selprevColor, selprevColor, selprevColor };
bd->DrawPolygon(p, f, !polyR[mPolygon].IsTriangle());
}
}
}
return TOOLDRAW::HANDLES | TOOLDRAW::AXIS;
}
The description resource files are an empty .h and .res, as well as .str