THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/07/2004 at 15:53, xxxxxxxx wrote:
Finally I have something that works. Using a dummy scene hook and a dummy shader, it is possible to display a custom object (a torus) in the material preview. The scene hook is needed to make a connection between the shader and the current document, using InsertShader(), otherwise the preview won't render (there are other ways to do this, for example inserting the shader into an object or tag or whatever). The shader is needed to intercept the messages from the preview.
There is some untangling to do, so that you can have more than one in the dialog for example, but the basic concept is there. Please ask if you have any questions how it works. Here's the code:
// Use unique IDs for these!
const LONG OBJECT_PREVIEW_HOOK_ID = 1000001;
const LONG OBJECT_PREVIEW_SHADER_ID = 1000002;
#include "customgui_matpreview.h"
class ObjectPreviewShader : public ShaderData
{
public:
virtual Bool Message(GeListNode* node, LONG type, void* data)
{
switch (type)
{
case MATPREVIEW_GET_OBJECT_INFO:
{
MatPreviewObjectInfo* info = static_cast<MatPreviewObjectInfo*>(data);
info->bHandlePreview = TRUE;
info->bNeedsOwnScene = TRUE;
info->bNoStandardScene = FALSE;
info->lFlags = MATPREVIEW_FLAG_HIDE_SCENES |
MATPREVIEW_FLAG_HIDE_ANIMATE |
MATPREVIEW_FLAG_HIDE_SCENE_SETTINGS |
MATPREVIEW_FLAG_HIDE_OPEN |
MATPREVIEW_FLAG_HIDE_SIZE;
return TRUE;
}
break;
case MATPREVIEW_MODIFY_CACHE_SCENE:
{
MatPreviewModifyCacheScene* scene = static_cast<MatPreviewModifyCacheScene*>(data);
// Kidnap original object...
BaseObject* obj = scene->pDoc->SearchObject("Object");
obj->SetRenderMode(MODE_OFF);
obj->SetEditorMode(MODE_OFF);
// ...and insert our own
AutoAlloc<BaseObject> torus(Otorus);
torus->GetDataInstance()->SetReal(PRIM_TORUS_INNERRAD, 20.0);
torus->GetDataInstance()->SetReal(PRIM_TORUS_OUTERRAD, 60.0);
torus->SetRenderMode(MODE_ON);
torus->SetEditorMode(MODE_ON);
scene->pDoc->InsertObject(torus.Release(), obj, NULL);
}
return TRUE;
case MATPREVIEW_PREPARE_SCENE:
{
MatPreviewPrepareScene* prepare = static_cast<MatPreviewPrepareScene*>(data);
prepare->bScenePrepared = FALSE;
}
return TRUE;
case MATPREVIEW_GENERATE_IMAGE:
{
MatPreviewGenerateImage* image = static_cast<MatPreviewGenerateImage*>(data);
if (image->pDoc)
{
LONG w = image->pDest->GetBw();
LONG h = image->pDest->GetBh();
BaseContainer bcRender = image->pDoc->GetActiveRenderData()->GetData();
bcRender.SetLong(RDATA_XRES, w);
bcRender.SetLong(RDATA_YRES, h);
bcRender.SetLong(RDATA_ANTIALIASING, ANTI_GEOMETRY);
if (image->bLowQuality)
{
bcRender.SetBool(RDATA_RENDERASEDITOR, TRUE);
}
image->pDest->Clear(0, 0, 0);
image->lResult = RenderDocument(image->pDoc, bcRender, NULL, NULL, image->pDest,
RENDERFLAG_EXTERNAL | RENDERFLAG_PREVIEWRENDER, image->pThread);
}
return TRUE;
}
case MATPREVIEW_GET_PREVIEW_ID:
{
LONG* id = static_cast<LONG*>(data);
*id = 0;
}
return TRUE;
}
return TRUE;
}
virtual Vector Output(PluginShader *sh, ChannelData *cd)
{
return Vector(1.0, 0.2, 0.0);
}
static NodeData *Alloc(void) { return gNew ObjectPreviewShader; }
};
class ObjectPreviewHook : public SceneHookData
{
AutoAlloc<PluginShader> shad;
public:
ObjectPreviewHook() : shad(OBJECT_PREVIEW_SHADER_ID) {}
virtual Bool Init(GeListNode* node)
{
if (shad)
{
static_cast<PluginSceneHook*>(node)->InsertShader(shad);
}
return TRUE;
}
virtual void Free(GeListNode* node)
{
shad->Remove();
}
Bool InitPreviewData(MaterialPreviewData* preview_data, LONG dirtyCount)
{
return preview_data->Init(shad, dirtyCount);
}
static NodeData *Alloc(void) { return gNew ObjectPreviewHook; }
};
class ObjectPreviewDialog : public GeModalDialog
{
enum
{
PREVIEW_ID = 1000,
GROUP_ID = 1001,
MIN_WIDTH = 100,
MIN_HEIGHT = 100,
};
private:
MaterialPreviewCustomGui* preview;
LONG dirtyCount;
public:
ObjectPreviewDialog() : preview(NULL), dirtyCount(0) {}
virtual void DestroyWindow()
{
preview = NULL;
}
virtual Bool CreateLayout()
{
BaseContainer settings;
settings.SetLong(MATPREVIEW_MIN_WIDTH, MIN_WIDTH);
settings.SetLong(MATPREVIEW_MIN_HEIGHT, MIN_HEIGHT);
//settings.SetBool(MATPREVIEW_NO_BORDER, TRUE);
GroupBegin(GROUP_ID, BFH_FIT | BFV_FIT, 1, 1, "Torus", 0);
GroupBorderSpace(2,2,2,2);
GroupBorder(BORDER_NONE | BORDER_WITH_TITLE);
{
preview = static_cast<MaterialPreviewCustomGui*>(
AddCustomGui(PREVIEW_ID, CUSTOMGUI_MATPREVIEW,
"", BFH_FIT | BFV_FIT,
SizePix(MIN_WIDTH), SizePix(MIN_HEIGHT),
settings));
}
GroupEnd();
SetPreviewData(dirtyCount);
return preview != NULL;
}
virtual Bool InitValues()
{
if (preview == NULL) return FALSE;
preview->SetLayoutMode(LAYOUTMODE_MAXIMIZED);
return TRUE;
}
virtual Bool Command(LONG id, const BaseContainer &msg)
{
if (id == PREVIEW_ID)
{
SetPreviewData(++dirtyCount);
}
return TRUE;
}
void SetPreviewData(LONG dirtyCount)
{
if (preview == NULL) return;
TriState<GeData> t = preview->GetData();
GeData data = t.GetValue();
MaterialPreviewData* preview_data =
static_cast<MaterialPreviewData*>(
data.GetCustomDataType(CUSTOMDATATYPE_MATPREVIEW));
if (preview_data)
{
static_cast<ObjectPreviewHook*>(
GetActiveDocument()->
FindSceneHook(OBJECT_PREVIEW_HOOK_ID)->
GetNodeData())->InitPreviewData(preview_data, dirtyCount);
preview_data->SetPreviewSize(MatPreviewSizeDefault);
preview_data->SetPreviewType(MatPreviewUser);
}
preview->SetData(data);
}
};
class MenuTest : public CommandData
{
public:
virtual Bool Execute(BaseDocument *doc);
};
Bool MenuTest::Execute(BaseDocument *doc)
{
ObjectPreviewDialog dlg;
dlg.Open();
return TRUE;
}
Bool RegisterMenuTest(void)
{
RegisterSceneHookPlugin(OBJECT_PREVIEW_HOOK_ID,
"Object Preview", PLUGINFLAG_HIDE,
ObjectPreviewHook::Alloc, EXECUTION_INITIAL, 0);
RegisterShaderPlugin(OBJECT_PREVIEW_SHADER_ID,
"Object Preview", PLUGINFLAG_HIDE,
ObjectPreviewShader::Alloc, "", 0);
String name=GeLoadString(IDS_MENUTEST);
if (!name.Content()) return TRUE;
return RegisterCommandPlugin(1000956,name,0,"icon.tif",
"C++ SDK Menu Test Plugin",gNew MenuTest);
}