Текущий раздел:

Описания RDS

Руководство программиста

Глава 2. Создание моделей блоков

§2.10. Программное рисование внешнего вида блока

§2.10.4. Панели блоков в окне подсистемы

Полный исходный текст на языке C++ двух библиотек (DLL) с моделями блоков, создающих панели в окне родительской подсистемы.

Первая библиотека содержит модель, создающую и обслуживающую пустую панель (во второй библиотеке будет добавлено формирование на этой панели трехмерного изображения с помощью OpenGL).

      // Панели блоков в окне подсистемы - первый пример
      #include <windows.h>
      #include <RdsDef.h>
      // Подготовка описаний сервисных функций
      #define RDS_SERV_FUNC_BODY GetInterfaceFunctions
      #include <RdsFunc.h>

      // Глобальная переменная для значения ошибки
      double DoubleErrorValue;

      //========== Главная функция DLL ==========
      int WINAPI DllMain(HINSTANCE /*hinst*/,
                               unsigned long reason,
                               void* /*lpReserved*/)
      { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
          { // Получение доступа к функциям RDS
            if(!GetInterfaceFunctions())
              RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS
            else
              rdsGetHugeDouble(&DoubleErrorValue);

          }
        return 1;
      }
      //========= Конец главной функции =========

      //=================================================
      // Личная область данных блока
      //=================================================
      class TOpenGLInstr
      { private:
          RDS_TIMERID RefreshTimer; // Таймер обновления

        public:
          RDS_HOBJECT Panel;        // Объект-панель

          // Сохранение параметров блока
          void SaveText(void);
          // Загрузка параметров блока
          void LoadText(char *text);

          // Создание таймера обновления
          void CreateRefreshTimer(RDS_BHANDLE parent);

          // Конструктор класса
          TOpenGLInstr(void);
          // Деструктор класса
          ~TOpenGLInstr();
      };
      //=================================================

      // Конструктор класса личной области данных
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      TOpenGLInstr::TOpenGLInstr(void)
      { // Создаем панель в окне подсистемы
        Panel=rdsPANCreate(0,0,0,300,300,
                           RDS_PAN_F_SCALABLE|RDS_PAN_F_BORDER|
                           RDS_PAN_F_SIZEABLE|RDS_PAN_F_MOVEABLE|
                           RDS_PAN_F_CAPTION|RDS_PAN_F_HIDDEN|
                           RDS_PAN_F_PAINTMSG,
                           "Прибор");
        // Инициализируем идентификатор еще не созданного таймера
        RefreshTimer=NULL;
      }
      //=================================================

      // Деструктор класса личной области данных
      TOpenGLInstr::~TOpenGLInstr()
      { // Удаление панели
        if(Panel)
          rdsDeleteObject(Panel);
        // Удаление таймера
        if(RefreshTimer)
          rdsDeleteBlockTimer(RefreshTimer);
      }
      //=================================================

      // Создание таймера обновления панели
      void TOpenGLInstr::CreateRefreshTimer(RDS_BHANDLE parent)
      { // Структура для получения переметров окна подсистемы
        RDS_EDITORPARAMETERS WinParams;
        // Определение интервала обновления окна подсистемы
        WinParams.servSize=sizeof(RDS_EDITORPARAMETERS);
        rdsGetEditorParameters(parent,&WinParams);
        // Интервал - в WinParams.RefreshDelay

        // Создание таймера
        RefreshTimer=rdsSetBlockTimer(RefreshTimer, // Идентификатор
                       WinParams.RefreshDelay,      // Интервал
                       RDS_TIMERM_LOOP | RDS_TIMERS_WINREF |
                       RDS_TIMERF_FIXFREQ,          // Режим и флаги
                       TRUE);                       // Запустить таймер
      }
      //=================================================

      // Функция сохранения параметров блока
      void TOpenGLInstr::SaveText(void)
      { RDS_HOBJECT ini; // Идентификатор вспомогательного объекта

        // При сохранении блока в отдельный файл на диске параметры
        // панели записывать не нужно
        if(rdsGetSystemInt(RDS_GSISAVELOADACTION)==RDS_LS_SAVETOFILE)
          return;

        // Создание вспомогательного объекта для работы с данными
        ini=rdsINICreateTextHolder(TRUE);

        // Параметры записываются в секцию "[Window]"
        rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Window");

        // Получение параметров панели и запись их в объект
        rdsINIWriteInt(ini,"Left",rdsGetObjectInt(Panel,RDS_PAN_LEFT,0));
        rdsINIWriteInt(ini,"Top",rdsGetObjectInt(Panel,RDS_PAN_TOP,0));
        rdsINIWriteInt(ini,"Width",rdsGetObjectInt(Panel,RDS_PAN_WIDTH,0));
        rdsINIWriteInt(ini,"Height",rdsGetObjectInt(Panel,RDS_PAN_HEIGHT,0));
        rdsINIWriteInt(ini,"Visible",rdsGetObjectInt(Panel,RDS_PAN_VISIBLE,0));

        // Сохранение получившегося текста в файл, в который в данный
        // момент идет запись
        rdsCommandObject(ini,RDS_HINI_SAVEBLOCKTEXT);

        // Удаление вспомогательного объекта
        rdsDeleteObject(ini);
      }
      //=================================================

      // Функция загрузки параметров блока
      void TOpenGLInstr::LoadText(char *text)
      { RDS_HOBJECT ini; // Идентификатор вспомогательного объекта

        // Создание вспомогательного объекта для работы с данными
        ini=rdsINICreateTextHolder(TRUE);

        // Запись в объект полученного от RDS текста с параметрами блока
        rdsSetObjectStr(ini,RDS_HINI_SETTEXT,0,text);

        // Установка "[Window]" в качестве текущей секции и чтение
        // из нее пяти целых параметров
        if(rdsINIOpenSection(ini,"Window"))
          { rdsSetObjectInt(Panel,RDS_PAN_LEFT,0,
                            rdsINIReadInt(ini,"Left",0));
            rdsSetObjectInt(Panel,RDS_PAN_TOP,0,
                            rdsINIReadInt(ini,"Top",0));
            rdsSetObjectInt(Panel,RDS_PAN_WIDTH,0,
                            rdsINIReadInt(ini,"Width",0));
            rdsSetObjectInt(Panel,RDS_PAN_HEIGHT,0,
                            rdsINIReadInt(ini,"Height",0));
            rdsSetObjectInt(Panel,RDS_PAN_VISIBLE,0,
                            rdsINIReadInt(ini,"Visible",0));
          }
        // Удаление вспомогательного объекта
        rdsDeleteObject(ini);
      }
      //=================================================

      // Модель блока с панелью
      extern "C" __declspec(dllexport) int RDSCALL OpenGLInstr(
            int CallMode,
            RDS_PBLOCKDATA BlockData,
            LPVOID ExtParam)
      { // Указатель на личную область, приведенный к нужному типу
        TOpenGLInstr *data=(TOpenGLInstr*)(BlockData->BlockData);
        // Вспомогательная – указатель на структуру параметров при
        // действиях с панелью (будет использована в реакциях)
        RDS_PPANOPERATION param;

        switch(CallMode)
          { // Инициализация блока
            case RDS_BFM_INIT:
              // Создание личной области данных
              // (при этом в конструкторе будет создана панель)
              BlockData->BlockData=data=new TOpenGLInstr();
              break;

            // Очистка данных блока
            case RDS_BFM_CLEANUP:
              // В деструкторе класса панель будет уничтожена
              delete data;
              break;

            // Запуск расчета
            case RDS_BFM_STARTCALC:
              // Создание таймера обновления
              data->CreateRefreshTimer(BlockData->Parent);
              break;

            // Вызов функции настройки или двойной щелчок
            // левой кнопки мыши
            case RDS_BFM_SETUP:
            case RDS_BFM_MOUSEDBLCLICK:
              // Показать панель
              rdsSetObjectInt(data->Panel,RDS_PAN_VISIBLE,0,1);
              break;

            // Сохранение параметров блока
            case RDS_BFM_SAVETXT:
              data->SaveText();
              break;

            // Загрузка параметров блока
            case RDS_BFM_LOADTXT:
              data->LoadText((char*)ExtParam);
              break;

            // Действия с панелью
            case RDS_BFM_BLOCKPANEL:
              // Приведение указателя на структуру, переданного в
              // ExtParam, к нужному типу
              param=(RDS_PPANOPERATION)ExtParam;
              // Разные действия в зависимости от операции с панелью
              switch(param->Operation)
                { // Создание оконного объекта для панели
                  case RDS_PANOP_CREATE:
                    // Здесь будет инициализация рисования на панели
                    break;
                  // Уничтожение оконного объекта панели
                  case RDS_PANOP_DESTROY:
                    // Здесь будет очистка инициализированного
                    break;
                  // Размер панели изменен
                  case RDS_PANOP_RESIZED:
                    // Здесь будет реакция на изменение размера
                    // и перерисовка панели
                    break;
                  // Необходимо перерисовать изображение
                  case RDS_PANOP_PAINT:
                    // Здесь будет перерисовка панели
                    break;
                }
              break;

           // Необходимо обновить окна блока (вызывается таймером)
           case RDS_BFM_WINREFRESH:
              // Здесь будет перерисовка панели
              break;
          }
        return RDS_BFR_DONE;
      }
      //=================================================

Эта же библиотека с добавленными функциями формирования трехмерного изображения (добавки выделены цветом).

      // Панели блоков в окне подсистемы - OpenGL
      #include <windows.h>
      #include <math.h>
      #include <gl/gl.h>
      #include <gl/glu.h>
      #include <RdsDef.h>
      // Подготовка описаний сервисных функций
      #define RDS_SERV_FUNC_BODY GetInterfaceFunctions
      #include <RdsFunc.h>

      // Глобальная переменная для значения ошибки
      double DoubleErrorValue;

      //========== Главная функция DLL ==========
      int WINAPI DllMain(HINSTANCE /*hinst*/,
                               unsigned long reason,
                               void* /*lpReserved*/)
      { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
          { // Получение доступа к функциям RDS
            if(!GetInterfaceFunctions())
              RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS
            else
              rdsGetHugeDouble(&DoubleErrorValue);

          }
        return 1;
      }
      //========= Конец главной функции =========

      //=================================================
      // Личная область данных блока
      //=================================================
      class TOpenGLInstr
      { private:
          HGLRC Hrc;                 // Контекст OpenGL
          RDS_TIMERID RefreshTimer; // Таймер обновления

        public:
          RDS_HOBJECT Panel;        // Объект-панель

          // Настройка вывода изображения на панель
          void InitWindow(HWND window);
          // Отключение OpenGL
          void Clear(void);
          // Рисование трехмерной сцены
          void RenderScene(double Dir,double List,double Pitch);
          // Сохранение параметров блока
          void SaveText(void);
          // Загрузка параметров блока
          void LoadText(char *text);

          // Создание таймера обновления
          void CreateRefreshTimer(RDS_BHANDLE parent);

          // Конструктор класса
          TOpenGLInstr(void);
          // Деструктор класса
          ~TOpenGLInstr();
      };
      //=================================================

      // Вычисление нормали к треугольнику
      // p1,p2,p3 – массивы координат вершин {x,y,z}
      // norm – массив, в котором возвращаются вычисленные
      // координаты нормали
      void NormalToTriangle(GLfloat *p1,GLfloat *p2,
                            GLfloat *p3,GLfloat *norm)
      { double m[3],a[3],b[3],R; // Вспомогательные переменные

        // Символические имена для координат векторов
        #define x 0
        #define y 1
        #define z 2

        // Вычисляем векторное произведение векторов
        // a (p1->p2) и b (p1->p3)
        for(int i=0;i<3;i++)
          { a[i]=p2[i]-p1[i];
            b[i]=p3[i]-p1[i];
          }
        m[x]=a[y]*b[z]-a[z]*b[y];
        m[y]=a[z]*b[x]-a[x]*b[z];
        m[z]=a[x]*b[y]-a[y]*b[x];

        // Длина получившегося вектора
        R=sqrt(m[x]*m[x]+m[y]*m[y]+m[z]*m[z]);

        // Приводим вектор к единичной длине
        for(int i=0;i<3;i++)
          norm[i]=(GLfloat)(m[i]/R);

        // Отмена макроопределений символических имен координат
        #undef x
        #undef y
        #undef z
      }
      //=================================================
      // Построение треугольника p1-p2-p3
      void DrawTriangleGL(GLfloat *p1,GLfloat *p2,GLfloat *p3)
      { GLfloat norm[3]; // Массив для вычисления нормали

        // Вычислить нормаль
        NormalToTriangle(p1,p2,p3,norm);
        // Установить нормаль в OpenGL
        glNormal3fv(norm);
        // Задать три точки треугольника
        glVertex3fv(p1);
        glVertex3fv(p2);
        glVertex3fv(p3);
      }
      //=================================================
      // Рисование окружности в OpenGL
      void DrawCircleGL(GLfloat R,int N,GLfloat cR,GLfloat cG,GLfloat cB)
      { double aStep=(2.0*M_PI)/N; // Шаг ломаной по углу, радиан
        // Массивы для задания материала
        GLfloat MaterialAmbDiff[4],
                MaterialSpecular[4]={1.0,1.0,1.0,1.0};
        // Запись цвета материала в массив
        MaterialAmbDiff[0]=cR;
        MaterialAmbDiff[1]=cG;
        MaterialAmbDiff[2]=cB;
        MaterialAmbDiff[3]=1.0; // Непрозрачный
        // Установка отражающих свойств (материала) фигуры
        glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,
            MaterialAmbDiff);
        glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS, 50.0);
        glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MaterialSpecular);
        // Нормаль – по оси Z (окружность в плоскости XY)
        glNormal3f(0.0,0.0,1.0);
        // Рисуем замкнутую ломаную линию
        glBegin(GL_LINE_LOOP);
          for(int j=0;j<N;j++) // Цикл по углу
            { double a=aStep*j; // Угол
              double x=R*cos(a),y=R*sin(a); // Координаты точки
              glVertex3f((GLfloat)x,(GLfloat)y,0);
            }
        glEnd();
      }
      //=================================================
      // Рисование центрального объекта блока
      void DrawArrowGL(double R,double l,double w,double h,double b)
      { // Массивы для координат точек фигуры
        GLfloat p1[3],p2[3],p3[3],p4[3];
        // Материал – дно и корма (белый цвет)
        GLfloat MaterialBack[]  = {1.0, 1.0, 1.0, 1.0};
        // Материал – левый борт (красный цвет)
        GLfloat MaterialLeft[]  = {1.0, 0.5, 0.5, 1.0};
        // Материал – правый борт (зеленый цвет)
        GLfloat MaterialRight[] = {0.5, 1.0, 0.5, 1.0};

        // Символические имена для координат точек
        #define x 0
        #define y 1
        #define z 2

        // Вычисление координат точек фигуры
        p1[x]=0;  p1[y]=R;       p1[z]=0;
        p2[x]=-w; p2[y]=R-l;     p2[z]=0;
        p3[x]=w;  p3[y]=p2[y];   p3[z]=0;
        p4[x]=0;  p4[y]=p2[y]+b; p4[z]=h;

        // Построение граней
        glBegin(GL_TRIANGLES);
          // Свойства материала – общие для всех
          glMaterialf(GL_FRONT,GL_SHININESS,20.0);
          // Свойства материала – корма и дно
          glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,MaterialBack);
          glMaterialfv(GL_FRONT,GL_SPECULAR,MaterialBack);
          // Нижний треугольник (дно)
          DrawTriangleGL(p1,p3,p2);
          // Задний треугольник (корма)
          DrawTriangleGL(p2,p3,p4);
          // Свойства материала – левый борт
          glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,MaterialLeft);
          glMaterialfv(GL_FRONT,GL_SPECULAR,MaterialLeft);
          // Левый передний треугольник
          DrawTriangleGL(p2,p4,p1);
          // Свойства материала – правый борт
          glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,MaterialRight);
          glMaterialfv(GL_FRONT,GL_SPECULAR,MaterialRight);
          // Правый передний треугольник
          DrawTriangleGL(p4,p3,p1);
        glEnd();

        // Отмена макроопределений символических имен координат
        #undef x
        #undef y
        #undef z
      }
      //=================================================
      // Конструктор класса личной области данных
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      TOpenGLInstr::TOpenGLInstr(void)
      { // Создаем панель в окне подсистемы
        Panel=rdsPANCreate(0,0,0,300,300,
                           RDS_PAN_F_SCALABLE|RDS_PAN_F_BORDER|
                           RDS_PAN_F_SIZEABLE|RDS_PAN_F_MOVEABLE|
                           RDS_PAN_F_CAPTION|RDS_PAN_F_HIDDEN|
                           RDS_PAN_F_PAINTMSG,
                           "Прибор");
        // Инициализируем идентификатор еще не созданного таймера
        RefreshTimer=NULL;
      }
      //=================================================

      // Деструктор класса личной области данных
      TOpenGLInstr::~TOpenGLInstr()
      { // Удаление панели
        if(Panel)
          rdsDeleteObject(Panel);
        // Удаление таймера
        if(RefreshTimer)
          rdsDeleteBlockTimer(RefreshTimer);
      }
      //=================================================

      // Создание таймера обновления панели
      void TOpenGLInstr::CreateRefreshTimer(RDS_BHANDLE parent)
      { // Структура для получения переметров окна подсистемы
        RDS_EDITORPARAMETERS WinParams;
        // Определение интервала обновления окна подсистемы
        WinParams.servSize=sizeof(RDS_EDITORPARAMETERS);
        rdsGetEditorParameters(parent,&WinParams);
        // Интервал - в WinParams.RefreshDelay

        // Создание таймера
        RefreshTimer=rdsSetBlockTimer(RefreshTimer, // Идентификатор
                       WinParams.RefreshDelay,      // Интервал
                       RDS_TIMERM_LOOP | RDS_TIMERS_WINREF |
                       RDS_TIMERF_FIXFREQ,          // Режим и флаги
                       TRUE);                       // Запустить таймер
      }
      //=================================================

      // Функция сохранения параметров блока
      void TOpenGLInstr::SaveText(void)
      { RDS_HOBJECT ini; // Идентификатор вспомогательного объекта

        // При сохранении блока в отдельный файл на диске параметры
        // панели записывать не нужно
        if(rdsGetSystemInt(RDS_GSISAVELOADACTION)==RDS_LS_SAVETOFILE)
          return;

        // Создание вспомогательного объекта для работы с данными
        ini=rdsINICreateTextHolder(TRUE);

        // Параметры записываются в секцию "[Window]"
        rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Window");

        // Получение параметров панели и запись их в объект
        rdsINIWriteInt(ini,"Left",rdsGetObjectInt(Panel,RDS_PAN_LEFT,0));
        rdsINIWriteInt(ini,"Top",rdsGetObjectInt(Panel,RDS_PAN_TOP,0));
        rdsINIWriteInt(ini,"Width",rdsGetObjectInt(Panel,RDS_PAN_WIDTH,0));
        rdsINIWriteInt(ini,"Height",rdsGetObjectInt(Panel,RDS_PAN_HEIGHT,0));
        rdsINIWriteInt(ini,"Visible",rdsGetObjectInt(Panel,RDS_PAN_VISIBLE,0));

        // Сохранение получившегося текста в файл, в который в данный
        // момент идет запись
        rdsCommandObject(ini,RDS_HINI_SAVEBLOCKTEXT);

        // Удаление вспомогательного объекта
        rdsDeleteObject(ini);
      }
      //=================================================

      // Функция загрузки параметров блока
      void TOpenGLInstr::LoadText(char *text)
      { RDS_HOBJECT ini; // Идентификатор вспомогательного объекта

        // Создание вспомогательного объекта для работы с данными
        ini=rdsINICreateTextHolder(TRUE);

        // Запись в объект полученного от RDS текста с параметрами блока
        rdsSetObjectStr(ini,RDS_HINI_SETTEXT,0,text);

        // Установка "[Window]" в качестве текущей секции и чтение
        // из нее пяти целых параметров
        if(rdsINIOpenSection(ini,"Window"))
          { rdsSetObjectInt(Panel,RDS_PAN_LEFT,0,
                            rdsINIReadInt(ini,"Left",0));
            rdsSetObjectInt(Panel,RDS_PAN_TOP,0,
                            rdsINIReadInt(ini,"Top",0));
            rdsSetObjectInt(Panel,RDS_PAN_WIDTH,0,
                            rdsINIReadInt(ini,"Width",0));
            rdsSetObjectInt(Panel,RDS_PAN_HEIGHT,0,
                            rdsINIReadInt(ini,"Height",0));
            rdsSetObjectInt(Panel,RDS_PAN_VISIBLE,0,
                            rdsINIReadInt(ini,"Visible",0));
          }
        // Удаление вспомогательного объекта
        rdsDeleteObject(ini);
      }
      //=================================================

      // Настройка вывода изображения на панель
      void TOpenGLInstr::InitWindow(HWND window)
      { HDC Hdc; // Контекст устройства Windows
        // Структура для установки формата изображения
        PIXELFORMATDESCRIPTOR pfd = {
          sizeof(PIXELFORMATDESCRIPTOR), // Размер структуры
          1,                             // Номер версии
          PFD_DRAW_TO_WINDOW |           // Вывод в окно
            PFD_SUPPORT_OPENGL |         // Поддержка OpenGL
            PFD_DOUBLEBUFFER,            // Двойная буферизация
          PFD_TYPE_RGBA,                 // Формат цвета – RGBA
          24,                            // Глубина цвета – 24 бита
          0,0,0,0,0,0,                   // (здесь не используется)
          0,0,0,0,0,0,0,                 // (здесь не используется)
          32,                            // Z-буфер - 32 бита
          0,0,                           // (здесь не используется)
          PFD_MAIN_PLANE,                // Главный слой
          0,                             // Зарезервировано
          0,0,                           // Маски слоев (не исп.)
        };
        int PixelFormat;

        // Получение контекста оконного объекта
        Hdc=GetDC(window);

        // Установка формата изображения по структуре pfd
        PixelFormat=ChoosePixelFormat(Hdc,&pfd);
        SetPixelFormat(Hdc,PixelFormat,&pfd);

        // Создание контекста OpenGL
        Hrc=wglCreateContext(Hdc);

        // Установка этого контекста в качестве текущего
        wglMakeCurrent(Hdc,Hrc);
      }
      //=================================================
      // Отключение OpenGL
      void TOpenGLInstr::Clear()
      { // Отключение текущего контекста OpenGL
        wglMakeCurrent(NULL,NULL);
        // Уничтожение созданного контекста
        wglDeleteContext(Hrc);
      }
      //=================================================
      // Служебная функция – настройка параметров OpenGL
      BOOL TOpenGLInstr::SetupGLParams(HDC *pHdc)
      { // Параметры перспективной проекции
        const GLfloat zNear=0.1;   // Ближняя плоскость отсечения
        const GLfloat zFar=1000.0; // Дальняя плоскость отсечения
        const GLfloat vAngle=30.0; // Угол зрения

        HDC Hdc;	// Контекст устройства (окна) Windows

        // Расположение источника освещения
        const double lightDistance=500.0; // Расстояние до объекта
        const double lightRotation=-55.0; // Азимут в градусах
        const double lightPitch=45.0;     // Угол места в градусах

        // Вспомогательные переменные
        RDS_PANDESCRIPTION descr;
        int width,height;
        GLfloat array[4];
        double l_r,l_p;

        // Получение описания панели и дескриптора ее окна
        descr.servSize=sizeof(RDS_PANDESCRIPTION);
        if(!RDS(Panel,&descr)) // Не удалось
          return FALSE;
        if(descr.Handle==NULL) // Нет оконного объекта
          return FALSE;
        // Проверка высоты и ширины панели
        if(descr.Height==0 || descr.Width==0)
          return FALSE; // Негде рисовать

        // Получение контекста окна и передача в вызвавшую функцию
        // его через параметр-указатель
        Hdc=GetDC(descr.Handle);
        if(pHdc) *pHdc=Hdc;

        // Установка контекста Hrc, созданного при инициализации,
        // в качестве текущего
        if(!wglMakeCurrent(Hdc,Hrc))
          return FALSE; // Не удалось

        // Уcтановка различных параметров, влияющих на качество рисования
        // и способ закраски многоугольников
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
        glEnable(GL_POINT_SMOOTH);
        glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

        glClearColor(0.0f,0.0f,0.0f,1.0f); // Цвет фона - черный
        glClearDepth(1.0); // Значение для очистки Z-буфера

        //----------- Установка освещения ----------
        // Общее рассеянное освещение
        array[0]=array[1]=array[2]=0.5; // Белый, интенсивность 0.5
        array[3]=1.0;
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT,array);
        // Вычисление координат источника света
        l_r=(lightRotation*M_PI)/180.0;
        l_p=(lightPitch*M_PI)/180.0;
        array[0]=(GLfloat)(lightDistance*cos(l_p)*sin(l_r)); // X
        array[1]=(GLfloat)(lightDistance*sin(l_p));          // Y
        array[2]=(GLfloat)(lightDistance*cos(l_p)*cos(l_r)); // Z
        array[3]=0.0;
        glLightfv(GL_LIGHT0,GL_POSITION,array);
        // Рассеянное освещение от источника отсутствует
        array[0]=array[1]=array[2]=0.0; // Отсутствует - интенсивность 0
        array[3]=1.0;
        glLightfv(GL_LIGHT0,GL_AMBIENT,array);
        // Другие виды освещения – белый цвет
        array[0]=array[1]=array[2]=0.5; // Белый, интенсивность 0.5
        glLightfv(GL_LIGHT0,GL_DIFFUSE,array);
        glLightfv(GL_LIGHT0,GL_SPECULAR,array);
        // Включение источника света
        glEnable(GL_LIGHT0);
        // Разрешение расчета освещения
        glEnable(GL_LIGHTING);
        // Режим расчета “затенения"
        glShadeModel(GL_SMOOTH);
        // Способ расчета освещения
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
        //------------------------------------------

        // Установка области окна для рисования
        glViewport(0,0,descr.Width,descr.Height);

        // Настройка перспективной проекции на эту область
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(vAngle,
          (GLfloat)descr.Width/(GLfloat)descr.Height,
          zNear,zFar);

        // Переключение на матрицу моделей (для рисования объектов)
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        return TRUE; // Установка параметров успешно завершена
      }
      //=================================================
      // Рисование трехмерной сцены
      void TOpenGLInstr::RenderScene(double Dir,double List,double Pitch)
      { HDC Hdc; // Контекст устройства Windows
        // Угол места камеры в градусах
        const GLfloat Camera_Pitch=-50.0;
        // Расстояние до камеры
        const GLfloat Camera_Distance=300.0;

        // Настройка параметров OpenGL и получение контекста окна
        if(!SetupGLParams(&Hdc))
          return;

        // Очистка буфера изображения и Z-буфера
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Записать матрицу трансформаций в стек
        glPushMatrix();
        // Трансформации камеры
        glTranslatef(0.0,0.0,-Camera_Distance); // Отодвигаем от камеры
        glRotatef(Camera_Pitch,1,0,0); // Поворачиваем
        // Рисование неподвижной зеленой (0,1,0) окружности
        DrawCircleGL(60,100,0.0,1.0,0.0);

        if(Dir!=DoubleErrorValue &&
           List!=DoubleErrorValue &&
           Pitch!=DoubleErrorValue) // Можно рисовать
          { // Поворот на угол курса
            if(Dir!=0.0)
              glRotatef(Dir,0,0,1);
            // Поворот на угол дифферента
            if(Pitch!=0.0)
              glRotatef(Pitch,1,0,0);
            // Поворот на угол крена
            if(List!=0.0)
              glRotatef(-List,0,1,0);

            // Рисование подвижной белой (1,1,1) окружности
            DrawCircleGL(55,100,1.0,1.0,1.0);
            // Рисование центрального объекта
            DrawArrowGL(50,80,30,10,10);
          }
        // Восстановить матрицу трансформаций из стека
        glPopMatrix();
        // Завершить незавершенное рисование, если нужно
        glFlush();
        // Поменять местами видимый и рабочий буферы
        SwapBuffers(Hdc);
      }
      //=================================================

      // Модель блока с панелью
      extern "C" __declspec(dllexport) int RDSCALL OpenGLInstr(
            int CallMode,
            RDS_PBLOCKDATA BlockData,
            LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define Dir (*((double *)(pStart+2*RDS_VSZ_S)))
      #define List (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D)))
      #define Pitch (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D)))
        // Указатель на личную область, приведенный к нужному типу
        TOpenGLInstr *data=(TOpenGLInstr*)(BlockData->BlockData);
        // Вспомогательная – указатель на структуру параметров при
        // действиях с панелью (будет использована в реакциях)
        RDS_PPANOPERATION param;

        switch(CallMode)
          { // Инициализация блока
            case RDS_BFM_INIT:
              // Создание личной области данных
              // (при этом в конструкторе будет создана панель)
              BlockData->BlockData=data=new TOpenGLInstr();
              break;

            // Очистка данных блока
            case RDS_BFM_CLEANUP:
              // В деструкторе класса панель будет уничтожена
              delete data;
              break;

            // Проверка типа переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSDDD}"))
                return RDS_BFR_BADVARSMSG;
              return RDS_BFR_DONE;
            // Запуск расчета
            case RDS_BFM_STARTCALC:
              // Создание таймера обновления
              data->CreateRefreshTimer(BlockData->Parent);
              break;

            // Вызов функции настройки или двойной щелчок
            // левой кнопки мыши
            case RDS_BFM_SETUP:
            case RDS_BFM_MOUSEDBLCLICK:
              // Показать панель
              rdsSetObjectInt(data->Panel,RDS_PAN_VISIBLE,0,1);
              break;

            // Сохранение параметров блока
            case RDS_BFM_SAVETXT:
              data->SaveText();
              break;

            // Загрузка параметров блока
            case RDS_BFM_LOADTXT:
              data->LoadText((char*)ExtParam);
              break;

            // Действия с панелью
            case RDS_BFM_BLOCKPANEL:
              // Приведение указателя на структуру, переданного в
              // ExtParam, к нужному типу
              param=(RDS_PPANOPERATION)ExtParam;
              // Разные действия в зависимости от операции с панелью
              switch(param->Operation)
                { // Создание оконного объекта для панели
                  case RDS_PANOP_CREATE:
                    // Настройка вывода изображения на панель
                    data->InitWindow(param->Panel->Handle);
                    break;
                  // Уничтожение оконного объекта панели
                  case RDS_PANOP_DESTROY:
                    // Отключение OpenGL
                    data->Clear();
                    break;
                  // Размер панели изменен
                  case RDS_PANOP_RESIZED:
                    // При изменении размера – просто перерисовка
                    data->RenderScene(Dir,List,Pitch);
                    break;
                  // Необходимо перерисовать изображение
                  case RDS_PANOP_PAINT:
                    data->RenderScene(Dir,List,Pitch);
                    break;
                }
              break;

           // Необходимо обновить окна блока (вызывается таймером)
           case RDS_BFM_WINREFRESH:
              // Перерисовка изображения
              data->RenderScene(Dir,List,Pitch);
              break;
          }
        return RDS_BFR_DONE;

      // Отмена макроопределений
      #undef Pitch
      #undef List
      #undef Dir
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=================================================