home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Houseplan Collection
/
HRCD2005.ISO
/
data1.cab
/
Zusatz
/
3DS
/
DATA2.Z
/
OEMDlg.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-10-13
|
19KB
|
608 lines
// OEMDlg.cpp : implementation file
//
#include "stdafx.h"
#include "OEM.h"
#include "OEMDlg.h"
#include "ObjectListDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// COEMDlg dialog
COEMDlg::COEMDlg(CWnd* pParent /*=NULL*/)
: CDialog(COEMDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(COEMDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pArCon = NULL;
}
COEMDlg::~COEMDlg()
{
if (m_pArCon)
m_pArCon->Release();
}
void COEMDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(COEMDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(COEMDlg, CDialog)
//{{AFX_MSG_MAP(COEMDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_CLOSE()
ON_WM_SIZE()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_WM_MOVE()
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
ON_BN_CLICKED(IDC_ARCON_VISIBLE, OnArconVisible)
ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
ON_BN_CLICKED(IDC_VISIBLE, OnObjectsVisible)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Hilfsdeklarationen und Funktione
#define PI 3.1415926f
#define TWOPI (PI * 2.0f)
struct Point {
float x, y, z, u, v;
};
typedef Point ConturType[4];
static void PointsToVariant(ConturType &contur, VARIANT &v)
{
// Das C-Array in ein OLE SafeArray konvertieren
SAFEARRAY * array;
SAFEARRAYBOUND bounds[2];
bounds[0].lLbound = 0;
bounds[0].cElements = 5;
bounds[1].lLbound = 0;
bounds[1].cElements = 4;
array = SafeArrayCreate(VT_R4, 2, bounds);
void * mem = NULL;
SafeArrayAccessData(array, &mem);
memcpy(mem, contur, sizeof contur);
SafeArrayUnaccessData(array);
VariantInit(&v);
v.vt = VT_ARRAY|VT_R4;
v.parray = array;
}
// Diese Methode schlie▀t die Konstruktion eines 3D Objektes (ⁿbergeben als "const")
// ab indem es die Transformationsmatrix zur Positionierung in der Welt bildet und
// dann das Objekt entweder in die "reale" Welt einsetzt - und damit ArCon die weitere
// Verwaltung ⁿberlΣ▀t, oder es an eine 2D-Eratzdarstellung bindet, und es damit
// selbst verwaltet. Da in diesem Demo eine 2D-Ersatzdarstellung nicht wirklich gewollt
// ist, wird ein quasi unsichtbares 2D Objekt gebildet: eine Linie ohne LΣnge. Ein
// 2D Objekt, das nicht "visible" wΣre, wⁿrde nicht funktionieren, da die Sichtbarkeit
// der 2D Ersatzdarstellung auch die Sichtbarkeit des 3D Objektes steuert. Die 2D Darstellung
// kann z.B. durchaus einem Gescho▀ zugeordnet werden und nur in diesem erscheint dann das
// 3D Objekt.
void COEMDlg::InstanceIntoWorld(IObjectConstructor* constr, float x, float y, float z, BOOL intoWorld)
{
USES_CONVERSION;
// Eine Einheitsmatrix als "model to world" Transformation
float m2w[4][4];
memset(m2w, 0, sizeof m2w);
int i;
for (i = 0; i < 4; i++)
m2w[i][i] = 1.0f;
// Translation zu (x,y,z), damit nicht alles auf einem Haufen landet
m2w[3][0] = x;
m2w[3][1] = y;
m2w[3][2] = z;
// Abschlu▀ des 3D Konstruktionsvorganges
IObject3D * inst = NULL;
constr->Create(NULL, 0, &inst);
if (!inst) {
AfxMessageBox("Konstruktion des 3D-Objektes ist fehlgeschlagen!");
return;
}
inst->put_Flags(AC_3DFL_DBLCLICK | AC_3DFL_CONSTMODE | AC_3DFL_DESIGNMODE | AC_3DFL_SHOWALL);
// Transformati0onsmatrix in ein SafeArray verpacken
VARIANT v;
VariantInit(&v);
v.vt = VT_ARRAY|VT_R4;
SAFEARRAYBOUND bounds[2];
bounds[0].lLbound = 0;
bounds[0].cElements = 4;
bounds[1].lLbound = 0;
bounds[1].cElements = 4;
v.parray = SafeArrayCreate(VT_R4, 2, bounds);
void *mem = NULL;
SafeArrayAccessData(v.parray, &mem);
memcpy(mem, m2w, sizeof m2w);
SafeArrayUnaccessData(v.parray);
// Transformation setzen
VARIANT_BOOL ok;
inst->SetModelToWorldTransformation(v, &ok);
// SafeArray freigeben
SafeArrayDestroy(v.parray);
// und in die Welt einfⁿgen
if (intoWorld) {
// jetzt geh÷rt es ArCon
inst->InsertIntoWorld(0, &ok);
} else {
// Eine Linie als TrΣgerobjekt (man k÷nnte auch ein "Label" als Beschriftung verwenden).
// Diese Linie mu▀ in einer der Graphics2D Listen eingetragen sein.
ILine * line;
m_pArCon->NewLine(AC_LayerLast, &line);
line->put_Visible(VARIANT_TRUE);
IGraphics2DCollection *g;
m_pArCon->get_Graphics2D(&g);
VARIANT_BOOL ok;
g->Add(line, &ok);
// Nur wenn ein gⁿltiger Cursor ⁿbergeben wird, erscheint auch der Hinweistext
inst->SetOutline2D(line,
(long)LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_NICHT_CLICKBAR)),
A2BSTR("Diese Objekt ist nicht doppelklickbar"));
line->Release();
g->Release();
}
}
void COEMDlg::CreateOneCube(float x, float y, float z, COLORREF col, const CString &name, BOOL intoWorld)
{
IObjectConstructor * constr = NULL;
m_pArCon->NewObjectConstructor(0, TWOPI / 360 * 105, &constr);
IMaterial * mat = NULL;
m_pArCon->NewMaterial(&mat);
mat->put_AmbientCoefficient(0.2f);
mat->put_DiffuseCoefficient(0.4f);
mat->put_SpecularCoefficient(0.4f);
mat->put_DiffuseColor(col);
mat->put_SpecularColor(col);
mat->put_Transparent(0);
VARIANT v;
static Point contur[6][4] =
{
{
{ -0.5f, +0.5f, -0.5f, 0.0f, 1.0f },
{ +0.5f, +0.5f, -0.5f, 1.0f, 1.0f },
{ +0.5f, -0.5f, -0.5f, 1.0f, 0.0f },
{ -0.5f, -0.5f, -0.5f, 0.0f, 0.0f },
},
{
{ -0.5f, -0.5f, +0.5f, 0.0f, 0.0f },
{ +0.5f, -0.5f, +0.5f, 1.0f, 0.0f },
{ +0.5f, +0.5f, +0.5f, 1.0f, 1.0f },
{ -0.5f, +0.5f, +0.5f, 0.0f, 1.0f },
},
{
{ -0.5f, +0.5f, +0.5f, 0.0f, 1.0f },
{ -0.5f, +0.5f, -0.5f, 1.0f, 1.0f },
{ -0.5f, -0.5f, -0.5f, 1.0f, 0.0f },
{ -0.5f, -0.5f, +0.5f, 0.0f, 0.0f },
},
{
{ +0.5f, -0.5f, +0.5f, 0.0f, 0.0f },
{ +0.5f, -0.5f, -0.5f, 1.0f, 0.0f },
{ +0.5f, +0.5f, -0.5f, 1.0f, 1.0f },
{ +0.5f, +0.5f, +0.5f, 0.0f, 1.0f },
},
{
{ -0.5f, +0.5f, +0.5f, 0.0f, 0.0f },
{ +0.5f, +0.5f, +0.5f, 1.0f, 0.0f },
{ +0.5f, +0.5f, -0.5f, 1.0f, 1.0f },
{ -0.5f, +0.5f, -0.5f, 0.0f, 1.0f },
},
{
{ -0.5f, -0.5f, -0.5f, 0.0f, 1.0f },
{ +0.5f, -0.5f, -0.5f, 1.0f, 1.0f },
{ +0.5f, -0.5f, +0.5f, 1.0f, 0.0f },
{ -0.5f, -0.5f, +0.5f, 0.0f, 0.0f },
},
};
for (int i = 0; i < 6; i++) {
PointsToVariant(contur[i], v);
constr->SetContur(4, v);
VariantClear(&v);
constr->AddQuadriliteral(~0, mat, NULL);
}
VARIANT_BOOL ok;
constr->Finish(name.AllocSysString(), 0, ACO_DURATION_CACHEABLE, &ok);
// Konstruktion ist abgeschlossen, in die Welt damit
InstanceIntoWorld(constr, x, y, z, intoWorld);
// OLE Objekte wieder freigeben
mat->Release();
constr->Release();
}
/////////////////////////////////////////////////////////////////////////////
// Demo: erzeuge einige Wⁿrfel
void COEMDlg::CreateCubes(float dx, float dy, float dz, BOOL intoWorld)
{
int j = 1, i=rand();
for (float x=-10.0f; x<10.5f; x+=4.0f)
for (float y=-10.0f; y<11.5f; y+=4.0f)
for (float z=-10.0f; z<11.5f; z+=4.0f) {
CString name;
name.Format("Wⁿrfel # %d", j);
CreateOneCube(dx+x, dy+y, dz+z, RGB(i&1?255:0,i&2?255:0,i&4?255:0), name, intoWorld);
j++, i++;
}
}
void COEMDlg::AdjustArConWnd(int cx, int cy)
{
HWND parent = ::GetDlgItem(m_hWnd, IDC_ARCON_FRAME);
if (!parent) return; // noch nicht soweit, der Dialog wird erst aufgebaut
RECT r; POINT plt, prb;
::GetWindowRect(parent, &r);
plt.x = r.left; plt.y = r.top;
prb.x = r.right; prb.y = r.bottom;
::ScreenToClient(m_hWnd, &plt);
::ScreenToClient(m_hWnd, &prb);
::MoveWindow(parent, plt.x, plt.y, cx-plt.x-5, cy-plt.y-5, TRUE);
::GetClientRect(parent, &r);
::MoveWindow(m_arconWnd, r.left+1, r.top+1, r.right-1, r.bottom-1, TRUE);
// Wichtig: damit ArCon's interne Verwaltung der Fensterposition funktioniert,
// mu▀ es hier von seiner PositionsΣnderung informiert werden (als Child-Window
// bekommt es diese Information nicht von Windows)
m_pArCon->UpdateWindowPos();
}
/////////////////////////////////////////////////////////////////////////////
// COEMDlg message handlers
BOOL COEMDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Erzeuge ein ArCon Server Objekt
HRESULT res = CoCreateInstance(CLSID_ArCon, NULL, CLSCTX_LOCAL_SERVER, IID_IArCon, (void**)&m_pArCon);
if (FAILED(res)) {
TRACE("CoCreateInstance fehlgeschlagen: 0x%x\n", res);
AfxMessageBox("FATAL: kann ArCon OLE Schnittstelle nicht erreichen,\n"
"CoCreateInstance ist fehlgeschlagen!");
PostQuitMessage(0);
return TRUE;
}
((CButton*)GetDlgItem(IDC_ARCON_VISIBLE))->SetCheck(2);
((CButton *)GetDlgItem(IDC_VISIBLE))->SetCheck(2);;
// ArCon-Window in unseren Dialog integrieren
HWND parent = ::GetDlgItem(m_hWnd, IDC_ARCON_FRAME);
// Starte die ArCon Verbindung mit ArCon als Child
CString helpFileName(AfxGetApp()->m_pszHelpFilePath);
VARIANT_BOOL ok;
m_pArCon->StartMe2((long)m_hWnd, helpFileName.AllocSysString(), TRUE, (long)parent, &ok);
// Ermittle das ArCon Window-Handle
m_pArCon->get_ArConWindowHandle((long*)&m_arconWnd);
// ArCon richtig positionieren
CRect r;
GetClientRect(r);
AdjustArConWnd(r.right-r.left, r.bottom-r.top);
#if 0
// Alle Menⁿ's und Panels entfernen
m_pArCon->ShowMenu(AC_NoMode, FALSE, &ok);
m_pArCon->ShowMenu(AC_ModeConstruct, FALSE, &ok);
m_pArCon->ShowMenu(AC_ModeDesign, FALSE, &ok);
#endif
// Nur zur Demonstration: nur einen Menⁿpunkt entfernen:
m_pArCon->RemoveAnyMenuItem(AC_MenuDesign_Datei, &ok);
m_pArCon->ShowPanel(ACBI_UpperPannel|ACBI_ConstructionMode, FALSE, &ok);
m_pArCon->ShowPanel(ACBI_HowPannel, FALSE, &ok);
m_pArCon->ShowPanel(ACBI_LeftPannel|ACBI_ConstructionMode, FALSE, &ok);
m_pArCon->ShowPanel(ACBI_LeftPannel|ACBI_DesignMode, FALSE, &ok);
m_pArCon->ShowPanel(ACBI_LowerPannel, FALSE, &ok);
//m_pArCon->ShowPanel(ACBI_ViewPannel, FALSE, &ok);
// BetrachterStandpunkt, Gescho▀box in Viewleiste ausblenden, IDs stehen in Button-IDs.txt
m_pArCon->ShowButtonByID(ACBI_ViewPannel, 2576, 0, FALSE, &ok);
m_pArCon->ShowButtonByID(ACBI_ViewPannel, 2593, 0, FALSE, &ok);
m_pArCon->ShowButtonByID(ACBI_ViewPannel, 2592, 0, FALSE, &ok);
//m_pArCon->ShowButtonByID(ACBI_ViewPannel, 2576, 0, FALSE, &ok);
//m_pArCon->ShowPanel(ACBI_StatusPannel, FALSE, &ok);
// Ein neues Projekt erzeugen, falls gerade keines geladen ist
long mode;
m_pArCon->get_Mode(&mode);
if (mode == AC_NoMode) {
IProject * pPrj = NULL;
m_pArCon->NewProject(&pPrj);
m_pArCon->CreateProject(pPrj);
pPrj->Release();
}
// In den Designmodus schalten
m_pArCon->put_Mode(AC_ModeDesign);
// OK, jetzt kann ArCon erscheinen
m_pArCon->put_MultiUserMode(ACMU_DEFAULT);
return FALSE; // wir haben den Focus auf "ArCon" gesetzt
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void COEMDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR COEMDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void COEMDlg::OnClose()
{
VARIANT_BOOL ok = 0;
if (m_pArCon) { // Verbindung wurde aufgebaut
m_pArCon->EndArCon(&ok); // ArCon schlie▀en und freigeben
m_pArCon->Release();
m_pArCon = NULL;
}
CDialog::OnClose();
}
void COEMDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
if ((nType != SIZE_RESTORED)&&(nType != SIZE_MAXIMIZED)) return;
AdjustArConWnd(cx, cy);
}
void COEMDlg::OnButton1()
{
DWORD start = GetTickCount();
CButton * check = (CButton *)GetDlgItem(IDC_IN_WORLD);
BOOL intoWorld = check->GetCheck() == 1;
CWaitCursor hourglass;
m_pArCon->ShowWaitCursor(VARIANT_TRUE);
// Maximale Geschwindigkeit, keine Bildschirmupdates
m_pArCon->put_MultiUserMode(0);
// Demo: ein paar Wⁿrfel erzeugen und in die Welt einfⁿgen
CreateCubes(4.0f*(float)rand()/(float)RAND_MAX,
4.0f*(float)rand()/(float)RAND_MAX,
4.0f*(float)rand()/(float)RAND_MAX,
intoWorld);
// Fertig, wieder normaler Anzeigemodus
m_pArCon->put_MultiUserMode(ACMU_DEFAULT);
m_pArCon->ShowWaitCursor(VARIANT_FALSE);
DWORD end = GetTickCount();
CString msg;
msg.Format("Zeit: %lu ms", end - start);
m_pArCon->SetStatusText(msg.AllocSysString());
// ArCon den Focus geben, damit der nΣchste Klick auf einen Wⁿrfel
// funktioniert (oder nicht, wenn das nicht gewⁿnscht ist)
::SetFocus(m_arconWnd);
}
void COEMDlg::OnMove(int x, int y)
{
CDialog::OnMove(x, y);
if (m_pArCon)
m_pArCon->UpdateWindowPos();
}
// Demo: alle Namen anzeigen
void COEMDlg::OnButton2()
{
CObjectListDlg dlg(this, m_pArCon);
dlg.DoModal();
}
// ArCon anzeigen/verstecken
void COEMDlg::OnArconVisible()
{
CButton* btn = (CButton*)GetDlgItem(IDC_ARCON_VISIBLE);
HWND parent = ::GetDlgItem(m_hWnd, IDC_ARCON_FRAME);
if (btn->GetCheck() == 0) {
// ArCon verbergen
m_pArCon->SetParentWindow(0);
// Parent (Rahmen) auch ausblenden
::ShowWindow(parent, SW_HIDE);
} else {
// Parent (Rahmen) wieder anzeigen
::ShowWindow(parent, SW_SHOW);
// ArCon wieder in den Dialog einhΣngen
m_pArCon->SetParentWindow((long)parent);
// das (neue) Child-Window richtig positionieren
CRect r;
GetClientRect(r);
AdjustArConWnd(r.right-r.left, r.bottom-r.top);
// und das fertig positionierte Window anzeigen
::ShowWindow(m_arconWnd, SW_SHOW);
}
}
// Alle in die Welt eingefⁿgten Wⁿrfel l÷schen
void COEMDlg::OnButton3()
{
long count = 0;
CButton * check = (CButton *)GetDlgItem(IDC_IN_WORLD);
BOOL intoWorld = check->GetCheck() == 1;
{
CWaitCursor hourglass;
m_pArCon->ShowWaitCursor(VARIANT_TRUE);
m_pArCon->put_MultiUserMode(0);
if (intoWorld) {
IObject3DCollection * dieInstanzen;
IObject3D * derWuerfel;
long i, num;
m_pArCon->get_DesignObjects(&dieInstanzen);
dieInstanzen->get_Count(&num);
for (i = num; i > 0; i--) {
dieInstanzen->Item(i, &derWuerfel);
VARIANT_BOOL succeded;
derWuerfel->Delete(VARIANT_TRUE, &succeded);
if (succeded)
count++;
derWuerfel->Release();
}
dieInstanzen->Release();
} else {
IObjectConstructorCollection * dieObjekte;
IObject3DCollection * dieInstanzen;
IObjectConstructor * dasObjekt;
IObject3D * derWuerfel;
IGraphics2DCollection * die2DObjekte;
VARIANT_BOOL succeded;
long i, num, numInst;
m_pArCon->get_DesignObjectConstructors(&dieObjekte);
dieObjekte->get_Count(&num);
for(i=num; i > 0; i--) {
dieObjekte->Item(i,&dasObjekt);
dasObjekt->get_Objects(&dieInstanzen);
dieInstanzen->get_Count(&numInst);
for(int k = numInst; k > 0; k--) {
dieInstanzen->Item(k, &derWuerfel);
derWuerfel->Delete(VARIANT_TRUE, &succeded);
if (succeded)
count++;
derWuerfel->Release();
}
dasObjekt->Release();
dieInstanzen->Release();
}
dieObjekte->Release();
m_pArCon->get_Graphics2D(&die2DObjekte);
die2DObjekte->RemoveAll();
die2DObjekte->Release();
}
m_pArCon->put_MultiUserMode(ACMU_DEFAULT);
m_pArCon->ShowWaitCursor(VARIANT_FALSE);
}
if (count) {
CString msg;
msg.Format("%d Objekte wurden gel÷scht", count);
AfxMessageBox(msg);
} else {
AfxMessageBox("Es konnten keine Objekte gel÷scht werden!");
}
}
void COEMDlg::OnObjectsVisible()
{
CButton * check = (CButton *)GetDlgItem(IDC_VISIBLE);
VARIANT_BOOL visible = check->GetCheck() == 1 ? VARIANT_TRUE : VARIANT_FALSE;
IGraphics2DCollection * die2DObjekte;
IDispatch * pDisp;
ILine * dieLinie;
long i, num;
CWaitCursor hourglass;
m_pArCon->ShowWaitCursor(VARIANT_TRUE);
m_pArCon->put_MultiUserMode(0);
m_pArCon->get_Graphics2D(&die2DObjekte);
die2DObjekte->get_Count(&num);
for (i = 1; i <= num; i++) {
// "Aus historischen Grⁿnden" liefert die Graphics2DCollection nur generische
// Objekte vom Typ IDispatch (die Oberklasse aller ArCon Objekte), nicht die
// geeignetere Oberklasse aller 2D Grafikobjekte IGraphicsObject. Eine entsprechende
// ─nderung der Schnittstelle war ohne Bruch der BinΣrkompatibilitΣt nicht mehr
// m÷glich.
die2DObjekte->Item(i, &pDisp);
// Aus dem generischen Objekt holen wir das gewⁿnschte Interface ab - wenn wir
// nicht nur Linien erzeugen wⁿrden, mⁿ▀ten wir hier eine Reihe von if / else if
// Kaskaden schreiben, bis wir den richtigen Typ erwischen.
if (FAILED(pDisp->QueryInterface(IID_ILine, (void**)&dieLinie)))
continue; // das war keine Linie - sollte hier nie passieren
pDisp->Release(); // das pDisp war nur ein Hilfzeiger auf die Oberklasse, da wir
// jetzt die konkrete Klasse haben, brauchen wir ihn nicht mehr
// Die Sichtbarkeit der Linie Σndern
dieLinie->put_Visible(visible);
// Fertig, die Linie brauchen wir nicht mehr
dieLinie->Release();
}
die2DObjekte->Release();
m_pArCon->put_MultiUserMode(ACMU_DEFAULT);
m_pArCon->ShowWaitCursor(VARIANT_FALSE);
}