netlib.narod.ru< Назад | Оглавление | Далее >

Выбор граней

Теперь мы знаем, как можно использовать порт просмотра для выбора сеток. Но что делать, если мы хотим выбирать отдельные грани сетки? Никаких проблем. Фактически, необходимый для этого код будет очень похож на код, который использовался при выборе сеток.

Приложение FacePick

Приложение FacePick отображает на экране сетку и позволяет выбирать отдельные ее грани. Выбранная грани меняет свой цвет на тот, который указан в меню Colors. Сетку можно поворачивать, выбрав любую часть порта просмотра, которая не занята сеткой и перемещая мышь. Это позволяет менять ориентацию сетки и дает возможность менять цвет любой грани сетки. Кроме того, меню File позволяет загружать и сохранять сетки. Внешний вид окна приложения FacePick показан на рис. 9.3.


Рис. 9.3. Приложение FacePick

Рис. 9.3. Приложение FacePick


Приложение FacePick демонстирирует использование следующих технологий:

Класс FacePickWin

В классе FacePickWin сосредоточена основная функциональность приложения FacePick:

class FacePickWin : public RMWin
{
public:
    FacePickWin();
    BOOL CreateScene();
protected:
    //{{AFX_MSG(FacePickWin)
    afx_msg void OnRenderWireframe();
    afx_msg void OnRenderGouraud();
    afx_msg void OnRenderFlat();
    afx_msg void OnUpdateRenderWireframe(CCmdUI* pCmdUI);
    afx_msg void OnUpdateRenderFlat(CCmdUI* pCmdUI);
    afx_msg void OnUpdateRenderGouraud(CCmdUI* pCmdUI);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnColorsFace();
    afx_msg void OnColorsMesh();
    afx_msg void OnFileOpen();
    afx_msg void OnFileSave();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
private:
    static void UpdateDrag(LPDIRECT3DRMFRAME, void*, D3DVALUE);
    int PickFace(const CPoint& point);
    void OnIdle(long);
private:
    LPDIRECT3DRMMESHBUILDER meshbuilder;
    LPDIRECT3DRMFRAME meshframe;
    D3DCOLOR pickcolor;
    D3DVALUE meshscale;
    static BOOL drag;
    static BOOL end_drag;
    static int last_x, last_y;
};

В классе объявлены две открытые функции: конструктор и функция CreateScene(). Конструктор используется для инициализации динамических переменных класса. Функция CreateScene() создает начальную сцену приложения.

Далее объявлены двенадцать защищенных функций. Первые шесть из них предназначены для обработки сообщений меню Render, присутствующего в большинстве демонстрационных приложений. Функции OnLButtonDown() и OnLButtonUp() используются для реакции приложения на изменение состояния кнопок мыши.

Функции OnColorsFace() и OnColorsMesh() реализуют функциональность меню Colors. Обе функции выводят диалоговое окно выбора цвета с помощью класса MFC CColorDialog.

Функции OnFileOpen() и OnFileSave() используют класс MFC CFileDialog чтобы позволить пользователю выбрать или ввести имя файла.

Кроме того объявлены три закрытые функции: UpdateDrag(), PickFace() и OnIdle(). Функция UpdateDrag() — это функция обратного вызова, используемая для изменения ориентации сетки. Функция PickFace() подобна функции PickMesh(), которую мы использовали в приложении PickMesh. PickFace() отвечает за выполнение операции выбора граней.

Функция FacePickWin::CreateScene()

Сцена приложения FacePick конструируется в функции FacePickWin::CreateScene(), код которой показан в листинге 9.3.

Листинг 9.3. Функция FacePickWin::CreateScene()

BOOL FacePickWin::CreateScene()
{
    // ------- СЕТКА --------
    D3DRMLOADRESOURCE resinfo;
    resinfo.hModule = NULL;
    resinfo.lpName = MAKEINTRESOURCE(IDR_D3DMESH);
    resinfo.lpType = "MESH";
    d3drm->CreateMeshBuilder(&meshbuilder);
    meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
            NULL, NULL);
    meshbuilder->SetQuality(D3DRMRENDER_FLAT);
    ScaleMesh(meshbuilder, D3DVALUE(25));

    //------- ФРЕЙМ ------
    d3drm->CreateFrame(scene, &meshframe);
    meshframe->SetRotation(scene,
            D3DVALUE(1), D3DVALUE(0), D3DVALUE(0),
            D3DVALUE(.05));
    meshframe->AddVisual(meshbuilder);
    meshframe->AddMoveCallback(UpdateDrag, NULL);

    // --------- СВЕТ --------
    LPDIRECT3DRMLIGHT dlight;
    d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
            D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00),
            &dlight);

    LPDIRECT3DRMLIGHT alight;
    d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT,
            D3DVALUE(0.40), D3DVALUE(0.40), D3DVALUE(0.40),
            &alight);

    LPDIRECT3DRMFRAME lightframe;
    d3drm->CreateFrame(scene, &lightframe);
    lightframe->AddLight(dlight);
    lightframe->AddLight(alight);
    lightframe->SetOrientation(scene,
            D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));

    dlight->Release();
    dlight = 0;
    alight->Release();
    alight = 0;
    lightframe->Release();
    lightframe = 0;

    //------ КАМЕРА ----------
    d3drm->CreateFrame(scene, &camera);
    camera->SetPosition(scene,
            D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50));
    d3drm->CreateViewport(device, camera, 0, 0,
            device->GetWidth(), device->GetHeight(),
            &viewport);

    return TRUE;
}

Функция CreateScene() выполняет четыре действия:

  1. Создание сетки.
  2. Создание фрейма для сетки.
  3. Создание двух источников света.
  4. Создание порта просмотра.

Код, выполняющий первое действие, выглядит так:

D3DRMLOADRESOURCE resinfo;
resinfo.hModule = NULL;
resinfo.lpName = MAKEINTRESOURCE(IDR_D3DMESH);
resinfo.lpType = "MESH";
d3drm->CreateMeshBuilder(&meshbuilder);
meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
        NULL, NULL);
meshbuilder->SetQuality(D3DRMRENDER_FLAT);
ScaleMesh(meshbuilder, D3DVALUE(25));

Используемая по умолчанию сетка хранится в ресурсах приложения и идентифицируется константой IDR_D3DMESH. Хотя функция CreateScene() загружает эту внутреннюю сетку автоматически, сетка может быть заменена с помощью команды Open меню File. Обратите внимание, что функция SetQuality() используется, чтобы изменить метод визуализации сетки на плоский. Плоский метод выбран потому, что при его использовании отдельные грани сетки выделяются более четко, чем в других методах.

На втором этапе выполняется создание фрейма для сетки:

d3drm->CreateFrame(scene, &meshframe);
meshframe->SetRotation(scene,
        D3DVALUE(1), D3DVALUE(0), D3DVALUE(0),
        D3DVALUE(.05));
meshframe->AddVisual(meshbuilder);
meshframe->AddMoveCallback(UpdateDrag, NULL);

Указатель meshframe является членом класса FacePickWin и поэтому не объявлен в функции CreateScene(). Инициализацию указателя выполняет функция CreateFrame() интерфейса Direct3DRM. Функция SetRotation() назначает фрейму начальные атрибуты вращения. Эти атрибуты могут быть в любой момент изменены путем перетаскивания сетки с помощью мыши (мы увидим как это делается, когда будем обсуждать функцию UpdateDrag()). После вызова функции SetRotation(), к новому фрейму присоединяется созданная ранее сетка с помощью функции AddVisual(). Затем вызывается функция AddMoveCallback() для установки функции обратного вызова UpdateDrag().

На следующем этапе создаются два источника света:

LPDIRECT3DRMLIGHT dlight;
d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
        D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00),
        &dlight);

LPDIRECT3DRMLIGHT alight;
d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT,
        D3DVALUE(0.40), D3DVALUE(0.40), D3DVALUE(0.40),
        &alight);

LPDIRECT3DRMFRAME lightframe;
d3drm->CreateFrame(scene, &lightframe);
lightframe->AddLight(dlight);
lightframe->AddLight(alight);
lightframe->SetOrientation(scene,
        D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
        D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));

Источники направленного и рассеянного света создаются функцией CreateLightRGB() интерфейса Direct3DRM. Источник рассеянного света будет испускать серый свет, поскольку при его создании были указаны уменьшенные значения RGB. Потом создается фрейм и источники света присоединяются к нему с помощью функции AddLight(). В завершение вызывается функция SetOrientation(), чтобы задать ориентацию источника направленного света. На источник рассеянного света ориентация фрейма не оказывает никакого влияния.

На завершающем, четвертом этапе создается порт просмотра:

d3drm->CreateFrame(scene, &camera);
camera->SetPosition(scene,
        D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50));
d3drm->CreateViewport(device, camera, 0, 0,
        device->GetWidth(), device->GetHeight(),
        &viewport);

Указатель camera инициализируется функцией CreateFrame() интерфейса Direct3DRM, а затем его местоположение задается функцией SetPosition(). Созданный фрейм используется в качестве аргумента функции CreateViewport() интерфейса Direct3DRM.

Функции класса FacePickWin для работы с мышью

В приложении FacePick мышь используется не только для выбора граней, но и для вращения сетки и изменения ее ориентации. Для отслеживания состояния левой кнопки мыши класс FacePickWin использует функции OnLButtonDown() и OnLButtonUp(). Код функции OnLButtonDown() выглядит следующим образом:

void FacePickWin::OnLButtonDown(UINT nFlags, CPoint point)
{
    int faceindex = PickFace(point);
    if (faceindex != -1)
    {
        LPDIRECT3DRMFACEARRAY facearray;
        meshbuilder->GetFaces(&facearray);

        LPDIRECT3DRMFACE face;
        facearray->GetElement(faceindex, &face);
        face->SetColor(pickcolor);
        face->Release();
        facearray->Release();
    }
    else if (!drag)
    {
        drag = TRUE;
        last_x = GetMouseX();
        last_y = GetMouseY();
        SetCapture();
        ShowCursor(FALSE);
    }
    RMWin::OnLButtonDown(nFlags, point);
}

Сперва функция OnLButtonDown() вызывает функцию PickFace(), которая и реализует операцию выбора. Функция PickFace() очень похожа на функцию PickMesh() из приложения MeshPick, за исключением того, что функция PickFace() возвращает индекс выбранной грани (или –1, если ни одна грань не была выбрана).

Если грань была выбрана, ее индекс используется для изменения цвета грани. Сначала для получения массива граней используется функция GetFaces() интерфейса Direct3DRMMeshBuilder. Полученный ранее индекс используется для извлечения указателя на выбранную грань. Затем для смены цвета грани вызывается функция SetColor() интерфейса Direct3DRMFace.

Если грань не выбрана, начинается операция перетаскивания. В приложении MeshPick операция перетаскивания использовалась для переперемещения выбранной сетки. В приложении FacePick операция перетаскивания применяется для вращения сетки. В данном случае при запуске операции перетаскивания текущие координаты указателя мыши сохраняются в переменных last_x и last_y, после чего вызываются функции SetCapture() и ShowCursor().

Теперь пришло время взглянуть на функцию OnLButtonUp():

void FacePickWin::OnLButtonUp(UINT nFlags, CPoint point)
{
    if (drag)
    {
        end_drag = TRUE;
        ReleaseCapture();
        ShowCursor(TRUE);
    }
    RMWin::OnLButtonUp(nFlags, point);
}

Вы можете предположить, что функция OnLButtonUp() прекращает операцию перетаскивания (если она была начата). Однако, такое решение помешало бы реализации одной из возможностей приложения FacePick. Приложение FacePick позволяет пользователю вращать отображаемую сетку. Сетка может быть повернута в ходе операции перетаскивания, но, кроме того, может быть приведена в движение путем резкого перемещения мыши с одновременным отпусканием кнопки. Если поместить здесь код прекращения операции перетаскивания, эту возможность не удастся реализовать, поскольку код должен иметь возможность зафиксировать последние атрибуты вращения. Код установки атрибутов вращения находится в функции обратного вызова UpdateDrag(). Вместо того, чтобы дублировать этот код, мы устанавливаем флаг, сигнализирующий о завершении операции перетаскивания. Тем временем мы воосстанавливаем отображение указателя мыши и отменяем захват мыши программой, поскольку эти действия не влияют на код, связанный с атрибутами вращения.

Функция FacePickWin::PickFace()

Функция PickFace() использует функцию Pick() интерфейса Direct3DRMViewport для выполнения операции выбора. Если в результате выполнения операции выбора был возвращен объект, функция вернет индекс грани этого объекта. Код функции PickFace() выглядит следующим образом:

int FacePickWin::PickFace(const CPoint& point)
{
    HRESULT r;
    LPDIRECT3DRMPICKEDARRAY pickarray;

    viewport->Pick(point.x, point.y, &pickarray);

    int faceindex = -1;
    DWORD numpicks = pickarray->GetSize();
    if (numpicks > 0)
    {
        LPDIRECT3DRMVISUAL visual;
        LPDIRECT3DRMFRAMEARRAY framearray;
        D3DRMPICKDESC pickdesc;

        r = pickarray->GetPick(0, &visual, &framearray, &pickdesc);
        if (r == D3DRM_OK)
        {
            faceindex = pickdesc.ulFaceIdx;
            visual->Release();
            framearray->Release();
        }
    }
    pickarray->Release();
    return faceindex;
}

Сперва вызывается функция Pick() интерфейса Direct3DRMViewport. В первых двух аргументах этой функции передаются текущие координаты указателя мыши. Третий аргумент — это адрес указателя на интерфейс Direct3DRMPickedArray.

Затем вызывается функция GetSize(), чтобы определить, был ли выбран какой-либо объект. Если массив пуст, указатель pickarray освобождается и функция возвращает –1. Если в массиве есть элементы, первый из них извлекается с помощью функции GetPick(). Нам необходим только первый элемент, поскольку элементы массива отсортированы по значению координаты Z, а нас интересует самый близкий к зрителю объект.

Функция GetPick() инициализирует два указателя и структуру. Первый указатель указывает на видимый объект, который был выбран. В нашем случае указатель visual будет указывать на сетку, созданную в функции CreateScene() (поскольку эта сетка является единственным видимым объектом сцены). Однако указатель на видимый объект нас не интересует. Он мог бы потребоваться, если бы сцена содержала несколько сеток (как в приложении MeshPick). Второй указатель, инициализируемый функцией GetPick() — это указаетль на массив фреймов. Эти данные нас также не интересуют, по рассмотренным выше причинам.

Данные, в которых мы нуждаемся, — это индекс выбранной грани. Функция GetPick() сохраняет это значение в поле ulFaceIdx структуры D3DRMPICKDESC. Функция PickFace() сохраняет это значение и возвращает его после освобождения своих локальных указателей, завершая тем самым свою работу.

Между прочим, структура D3DRMPICKDESC содержит еще два поля, которые могут оказаться полезными:

Функция FacePickWin::UpdateDrag()

Функция UpdateDrag() является функцией обратного вызова, устанавливаемой в функции CreateScene(). Функция UpdateDrag() отвечает за вычисление новых атрибутов вращения сетки во время операции перетаскивания. Код функции приведен ниже:

void FacePickWin::UpdateDrag(LPDIRECT3DRMFRAME frame, void*, D3DVALUE)
{
    if (drag)
    {
        double delta_x = GetMouseX() - last_x;
        double delta_y = GetMouseY() - last_y;
        last_x = GetMouseX();
        last_y = GetMouseY();
        double delta_r = sqrt(delta_x * delta_x + delta_y * delta_y);
        double radius = 50;
        double denom = sqrt(radius * radius + delta_r * delta_r);

        if (!(delta_r == 0 || denom == 0))
            frame->SetRotation(0,
                    D3DDivide(-delta_y, delta_r),
                    D3DDivide(-delta_x, delta_r),
                    D3DVALUE(0.0),
                    D3DDivide(delta_r, denom));
    }

    if (end_drag)
    {
        drag = FALSE;
        end_drag = FALSE;
    }
}

Для вычисления вектора и скорости вращения функция использует текущую позицию указателя мыши и позицию указателя мыши в момент начала операции перетаскивания. Говоря по существу, перемещение мыши в двух измерениях преобразуется в вектор, а разница между старыми и новыми координатами мыши используется для вычисления скорости вращения. Полученные значения устанавливаются с помощью функции SetRotation() интерфейса Direct3DRMFrame.

Обратите внимание, что при каждом вызове функции UpdateDrag() проверяется флаг end_drag. Этот флаг устанавливается в функции, чтобы указать, что операция перетаскивания должна быть завершена. Если флаг end_drag установлен, операция перетаскивания прерывается.

Функции меню Color в классе FacePickWin

Приложение FacePick поддерживает два диалоговых окна для выбора цвета. Этими диалоговыми окнами управляют функции OnColorsFace() и OnColorsMesh(). Функция OnColorsFace() предоставляет пользователю возможность выбрать цвет, в который будет окрашена выбранная грань. Функция OnColorsMesh() позволяет выбрать цвет, в который будет окрашена вся сетка. Обе функции используют класс MFC CColorDialog. Код функции OnColorsFace() выглядит так:

void FacePickWin::OnColorsFace()
{
    CColorDialog dialog(0, CC_RGBINIT);
    dialog.m_cc.rgbResult = D3DCOLOR_2_COLORREF(pickcolor);
    if (dialog.DoModal() == IDOK)
    {
        COLORREF clr = dialog.GetColor();
        pickcolor = COLORREF_2_D3DCOLOR(clr);
    }
}

Класс CColorDialog позволяет указать цвет, который будет выбран при появлении диалогового окна на экране. Благодаря этому, мы можем вывести диалоговое окно, в котором уже будет выбран текущий цвет выбираемых граней (естественно, это работает, только если указанный цвет является одним из отображаемых в диалоговом окне цветов).

Константа CC_RGBINIT используется в качестве аргумента конструктора диалогового окна, чтобы указать, что мы задаем цвет по умолчанию. Цвет по умолчанию должен быть присвоен члену данных m_cc.rgbResult. Переменная pickcolor является членом данных класса MeshPickWin, в котором хранится текущий цвет окраски выбранных граней. Член данных pickcolor относится к типу D3DCOLOR, а для диалогового окна необходимо, чтобы цвета были представлены в формате COLORREF, и чтобы присваивание было выполнено правильно, требуется функция преобразования. Для этих целей класс RMWin предоставляет функции D3DCOLOR_2_COLORREF() и COLORREF_2_D3DCOLOR() (см. главу 4).

Чтобы открывшееся окно диалога было модальным, мы используем функцию DoModal(). Если пользователь выходит из окна диалога любым способом, отличающимся от щелчка по кнопке OK, функция завершает работу не выполняя больше никаких действий. Если возвращена константа IDOK, новый цвет присваивается члену данных pickcolor.

Функция OnColorsMesh() очень похожа:

void FacePickWin::OnColorsMesh()
{
    CColorDialog dialog;
    if (dialog.DoModal() == IDOK)
    {
        COLORREF clr = dialog.GetColor();
        D3DCOLOR meshcolor = COLORREF_2_D3DCOLOR(clr);
        meshbuilder->SetColor(meshcolor);
    }
}

В отличие от функции OnColorsFace(), в функции OnColorsMesh() не указывается выбираемый по умолчанию в диалоговом окне цвет. Если пользователь щелкает по кнопке OK, новый цвет извлекается из класса диалогового окна с помощью функции GetColor(). Полученное значение типа COLORREF преобразуется функцией COLORREF_2_D3DCOLOR() и устанавливается функцией SetColor() интерфейса Direct3DRMMeshBuilder.

Функции меню File в классе FacePickWin

Приложение FacePick позволяет загружать и сохранять сетки с помощью меню File. Для этих целей в класс FacePickWin включены функции OnFileOpen() и OnFileSave(). Функция OnFileOpen() выглядит следующим образом:

void FacePickWin::OnFileOpen()
{
    static char BASED_CODE filter[] =
            "X Files (*.x)|*.x|All Files (*.*)|*.*||";
    CFileDialog opendialog(TRUE, 0, 0, OFN_FILEMUSTEXIST,
            filter, this);
    if (opendialog.DoModal() == IDOK)
    {
        CWaitCursor cur;
        CString filename = opendialog.GetPathName();

        LPDIRECT3DRMMESHBUILDER builder;
        d3drm->CreateMeshBuilder(&builder);
        HRESULT r = builder->Load((void*)(LPCTSTR)filename,
                NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
        if (r != D3DRM_OK)
        {
            CString msg;
            msg.Format("Failed to load file\n'%s'", filename);
            AfxMessageBox(msg);
            return;
        }

        meshframe->DeleteVisual(meshbuilder);
        meshbuilder->Release();
        meshbuilder = builder;
        meshframe->AddVisual(meshbuilder);
        meshscale = ScaleMesh(meshbuilder, D3DVALUE(25));
    }
}

Функция использует класс MFC CFileDialog. Обратите внимание, что в качестве аргумента конструктора класса используется строка filter. Эта строка информирует диалоговое окно о том, какие типы файлов могут быть загружены.

Для вывода диалогового окна используется функция DoModal(). Если будет возвращена константа IDOK, имя файла извлекается из класса диалогового окна с помощью функции GetPathName(). Обратите внимание, что мы не проверяем, существует ли данный файл. Это сделано потому, что при конструировании объекта диалогового окна мы указали константу OFN_FILEMUSTEXIST. Данная константа указывает классу диалогового окна, что в случае ручного ввода имени файла должен быть проверен факт существования данного файла. В результате диалоговое окно просто не позволит ввести имя несуществующего файла (эта проверка не гарантирует правильности содержимого файла, она гарантирует только его существование).

Затем функция пытается загрузить новую сетку. Если попытка завершается неудачно, выводится окно с сообщением об ошибке и функция завершает работу. Эта ошибка не вызовет проблем в работе приложения, просто и дальше будет отображаться существующая в сцене сетка.

Если новая сетка успешно загружена, существующая сетка удаляется из сцены функцией DeleteVisual() интерфейса Direct3DRMFrame, и указатель meshbuilder освобождается. Затем к сцене добавляется новый конструктор сеток с помощью функции AddVisual().

На последнем этапе вызывается функция ScaleMesh(). Мы видели, как эта функция используется в других демонстрационных программах, но в данном случае есть несколько отличий. Вспомните, что функция ScaleMesh() масштабирует сетку до желаемого размера. В данном случае мы масштабируем любую загруженную сетку до размера в 25 единиц. Это замечательно работало в других приложениях, и работает здесь, но если после масштабирования сетка будет записана на диск, ее размеры изменятся. Поэтому перед тем как записывать сетку на диск, ей необходимо вернуть первоначальные размеры. Функция ScaleMesh() возвращает значение, являющееся коэффициентом, использованным для масштабирования оригинальной сетки. Сохранение этого значения позволит нам вернуть сетке оригинальный размер. Мы увидим, как это делается, когда будем обсуждать код функции OnFileSave().

Функция OnFileSave() определена следующим образом:

void FacePickWin::OnFileSave()
{
    static char BASED_CODE filter[] = "X Files (*.x)|*.x||";
    CFileDialog opendialog(FALSE, ".x", "",
            OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter);
    if (opendialog.DoModal() == IDOK)
    {
        CWaitCursor cur;
        CString filename = opendialog.GetPathName();
        D3DVALUE restorescale = D3DVALUE(1)/meshscale;
        meshbuilder->Scale(restorescale, restorescale, restorescale);
        meshbuilder->Save(filename,
                D3DRMXOF_BINARY, D3DRMXOFSAVE_ALL);
        meshbuilder->Scale(meshscale, meshscale, meshscale);
    }
}

Функция OnFileSave() также использует класс CFileDialog, но в вызове конструктора класса диалогового окна указан другой набор констант. Константа OFN_HIDEREADONLY указывает, что в диалоговом окне не надо отображать флажок Open as Read Only. Наличие константы OFN_OVERWRITEPROMPT приведет к тому, что в случае перезаписи существующего файла программа попросит подтвердить необходимость выполнения данного действия.

Для вывода диалогового окна используется функция DoModal(). Если функция возвращает константу IDOK, текущая сетка записывается на диск. Класс CWaitCursor используется для отображения во время выполнения записи указателя мыши в форме песочных часов. Для получения имени сохраняемого или перезаписываемого файла применяется функция GetPathName(). Затем сетке возвращается ее оригинальный размер. Значение restorescale вычисляется таким образом, чтобы обратить операцию масштабирования, которой сетка подверглась при загрузке. Затем используется функция Scale() интерфейса Direct3DRMMeshBuilder чтобы масштабировать сетку согласно полученному коэффициенту restorescale. Для сохранения сетки вызывается функция Save(). Затем сетке возвращается ее предыдущий размер. Если не сделать этого, то после сохранения отображаемая сетка может стать огромной или микроскопической.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz