На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: JoeUser, Qraizer
  
> В чём секрет glut?, Не получается сделать то же самое при помощи Winapi/opengl
Всем доброго времени суток, у меня есть очередной вопрос. У меня не получается разобраться, как работает glut. Он был выбран, потому что приложение на glut32.dll корректно работает на всех моих машинах. Я хотел повторить то же самое, но без glut32.dll. Был написан код:

ExpandedWrap disabled
    #include <windows.h>
    #include <gl/GL.h>
    #pragma comment(lib, "opengl32.lib")
     
    #define CLASSNOTREGISTERED 1
    #define WINDOWNOTCREATED 2
    #define MESSAGENOTGOT 3
    #define OGLCONTEXNOTCREATED 4
    #define OGLCONTEXNOTMADECURRENT 5
     
    HWND hWnd;
    HDC hDc;
     
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
            case WM_PAINT:
                glClearColor(0.0, 0.0, 0.0, 1.0);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                glBegin(GL_TRIANGLES);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(0.25, 0.25, 0.0);
                glColor3f(0.0, 1.0, 0.0);
                glVertex3f(0.75, 0.25, 0.0);
                glColor3f(0.0, 0.0, 1.0);
                glVertex3f(0.75, 0.75, 0.0);
                glEnd();
                glFlush();
                SwapBuffers(hDc);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
     
    ATOM RegMyWindowClass(HINSTANCE hInst, LPCTSTR lpzClassName)
    {
        WNDCLASS wcWindowClass = { 0 };
        wcWindowClass.lpfnWndProc = (WNDPROC)WndProc;            // адрес ф-ции обработки сообщений
        wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;           // стиль окна
        wcWindowClass.hInstance = hInst;                         // дискриптор экземпляра приложения
        wcWindowClass.lpszClassName = lpzClassName;              // название класса
        wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);     // загрузка курсора
        wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;// загрузка цвета окон
        return RegisterClass(&wcWindowClass);                    // регистрация класса
    };
     
    int WinInit(HINSTANCE hInstance)
    {
        LPCTSTR lpzClass = TEXT("My Window Class!");
     
        if (!RegMyWindowClass(hInstance, lpzClass))
        {
            return CLASSNOTREGISTERED;
        };
     
        hWnd = CreateWindow(lpzClass, TEXT("Dialog Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInstance, NULL);
     
        if (!hWnd)
        {
            return WINDOWNOTCREATED;
        };
     
        return 0;
    }
     
    int WinLoop()
    {
        MSG msg = { 0 };
        int iGetOk = 0;
        while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
        {
            if (iGetOk == -1) return MESSAGENOTGOT;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        };
        return msg.wParam;
    };
     
    int WinOGLInit()
    {
        
        PIXELFORMATDESCRIPTOR pfd;
        ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
        //Версия с сайта 1:
        /*pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA;
        pfd.iPixelType = 24;
        pfd.cDepthBits = 32;
        pfd.iLayerType = PFD_MAIN_PLANE;*/
        
        //Версия с сатйта 2
        pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
     
        hDc = GetDC(hWnd);
     
        int nPixelFormat = ChoosePixelFormat(hDc, &pfd);
        SetPixelFormat(hDc, nPixelFormat, &pfd);
     
     
        HGLRC hglrc = wglCreateContext(hDc);
        if (!hglrc)
        {
            return GetLastError();
        };
     
        if (!wglMakeCurrent(hDc, hglrc))
        {
            return OGLCONTEXNOTMADECURRENT;
        };
     
        
        return 0;
    };
     
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        int initresult = WinInit(hInstance);
     
        if (initresult != 0)
        {
            return initresult;
        };
     
        initresult = WinOGLInit();
        if (initresult != 0)
        {
            return initresult;
        };
     
        return WinLoop();  
    }


Результат оставляет желать лучшего (обе версии). Во время перерисовок на одной машине (NVidia) окно мограет белым и скорость перерисовок очень низкая, на другой машине (Intel HD) вообще не рисует. Я решил узнать секрет glut. Попробовал прикрутить к проекту glut - но он намертво завязан на glut.dll. Исходный код всех функций вроде как есть, но всё равно требует glut32.lib и glut32.dll. Попробовал пособирать кусочки кода в один файл, чтоб точно скомпилировалось, но через один вечер работы запарился и понял, что что-то я не то делаю. Из ситуации вижу три выхода:

1) Как-то настроить проект так, чтобы он подключал glut/freeglut и компилировал их, при этом не требовал .lib/.dll. И отлаживать программу.
2) Найти или сделать самому файл, который работает так, как описано в пункте 1. Это у меня не получилось, хотя может нужно больше времени.
3) Отладчиком (таким, который показывает ассемблерные коды, не знаю, как это называется) смотреть, какие функции opengl32.dll и winapi вызываются из glut32.dll. Если честно, не хочется это делать.

Просто забросить и использовать glut32.dll не очень хочется. Заранее спасибо.
Я так понимаю, freeglut - хорошая альтернатива glut. В чем тогда проблема? Качаешь исходник freeglut, собираешь либы и подключаешь к своему проекту. В поставке freeglut вроде есть инструкции для всего этого, не?
Мои программные ништякиhttp://majestio.info
k.sovailo, а вот это - что такое ?
ExpandedWrap disabled
           case WM_PAINT:
                glClearColor(0.0, 0.0, 0.0, 1.0);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                glBegin(GL_TRIANGLES);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(0.25, 0.25, 0.0);
                glColor3f(0.0, 1.0, 0.0);
                glVertex3f(0.75, 0.25, 0.0);
                glColor3f(0.0, 0.0, 1.0);
                glVertex3f(0.75, 0.75, 0.0);
                glEnd();
                glFlush();
                SwapBuffers(hDc);
                break;
Подпись была выключена в связи с наложенным заземлением.
Цитата ЫукпШ @

Это рисование самого простого треугольника в ответ на сообщение о необходимости перерисовки окна. Очистка буфера, рисование и замена буфера. Наверное, я не понял вопрос.

Добавлено
JoeUser, хотел уже сказать, что проделывал эти шаги, но проверил ещё раз. Всё точно так же, как и в glut, только freeglut собирается только на х64. В результате я подключаю в проект .lib и .h и получаю "бла-бла-бла нет freeglutd.dll". Если её положить возле экзешника - никаких проблем, но это не то, чего я хочу. На всякий случай:

ExpandedWrap disabled
    #include <glut.h>
     
    void renderScene(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        glBegin(GL_TRIANGLES);
        glVertex3f(-0.5, -0.5, 0.0);
        glVertex3f(0.0, 0.5, 0.0);
        glVertex3f(0.5, -0.5, 0.0);
        glEnd();
     
        glutSwapBuffers();
    }
     
    int main(int argc, char **argv) {
     
        // инициализация
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100, 100);
        glutInitWindowSize(400, 400);
        glutCreateWindow("Урок 1");
     
        // регистрация обратных вызовов
        glutDisplayFunc(renderScene);
     
        // Основной цикл GLUT
        glutMainLoop();
     
        return 0;
    }


В то же время в README.Win32 написано: ...If you are using the DLL version of "freeglut"...
То есть можно как-то использовать не-ДЛЛ-версию? Не могу понять, как.

Добавлено
ЫукпШ, может Вы про то, что каждый раз вызывается glClearColor? Есть косяк. Убрал - всё точно так же.
Цитата k.sovailo @
В то же время в README.Win32 написано: ...If you are using the DLL version of "freeglut"...
То есть можно как-то использовать не-ДЛЛ-версию? Не могу понять, как.


Там есть упоминание о "freeglut_static.lib" - следовательно статик-версия собираться должна...

1) Читай внимательно README.cmake
2) В одном из проектов есть сборочный файл под все версии, просто посмотри что и как там делают:

ExpandedWrap disabled
    # This file is part of MXE. See LICENSE.md for licensing information.
     
    PKG             := freeglut
    $(PKG)_WEBSITE  := https://freeglut.sourceforge.io/
    $(PKG)_IGNORE   :=
    $(PKG)_VERSION  := 3.0.0
    $(PKG)_CHECKSUM := 2a43be8515b01ea82bcfa17d29ae0d40bd128342f0930cd1f375f1ff999f76a2
    $(PKG)_SUBDIR   := freeglut-$($(PKG)_VERSION)
    $(PKG)_FILE     := freeglut-$($(PKG)_VERSION).tar.gz
    $(PKG)_URL      := https://$(SOURCEFORGE_MIRROR)/project/freeglut/freeglut/$($(PKG)_VERSION)/$($(PKG)_FILE)
    $(PKG)_DEPS     := cc
     
    define $(PKG)_UPDATE
        $(WGET) -q -O- 'https://sourceforge.net/projects/freeglut/files/freeglut/' | \
        $(SED) -n 's,.*freeglut-\([0-9][^>]*\)\.tar.*,\1,p' | \
        head -1
    endef
     
    define $(PKG)_BUILD
        cd '$(BUILD_DIR)' && '$(TARGET)-cmake' '$(SOURCE_DIR)' \
            -DFREEGLUT_GLES=OFF \
            -DFREEGLUT_BUILD_DEMOS=OFF \
            -DFREEGLUT_REPLACE_GLUT=ON \
            -DFREEGLUT_BUILD_STATIC_LIBS=$(CMAKE_STATIC_BOOL) \
            -DFREEGLUT_BUILD_SHARED_LIBS=$(CMAKE_SHARED_BOOL)
        $(MAKE) -C '$(BUILD_DIR)' -j '$(JOBS)' VERBOSE=1
        $(MAKE) -C '$(BUILD_DIR)' -j 1 install VERBOSE=1
     
        '$(TARGET)-gcc' \
            -W -Wall -Werror -ansi -pedantic \
            '$(TEST_FILE)' -o '$(PREFIX)/$(TARGET)/bin/test-freeglut.exe' \
            `'$(TARGET)-pkg-config' glut --cflags --libs`
    endef
Мои программные ништякиhttp://majestio.info
Цитата k.sovailo @
Цитата ЫукпШ @

Это рисование самого простого треугольника в ответ на сообщение о необходимости перерисовки окна. Очистка буфера, рисование и замена буфера.

Вот на это я и хотел обратить внимание.
Чтобы с максимальной вероятностью прекратить любые видео-эффекты,
надо отделить операцию рисования от операции вывода.
А у тебя эти операции объединены вместе.
Надо, чтобы из WM_PAINT готовое изображение копировалось в окно.
Тогда такая операция будет производиться максимально быстро.
-----
Ещё рекомендуется обрабатывать сообщение "WM_ERASEBKGND".
Сообщение отредактировано: ЫукпШ -
Подпись была выключена в связи с наложенным заземлением.
Цитата JoeUser @

Действительно, есть упоминание. Всего-то и надо было:
ExpandedWrap disabled
    #define FREEGLUT_STATIC 1
    #include <glut.h>

Теперь буду надеяться, что разберусь, в чём "магия". Тему пока не закрываю.
ЫукпШ, я ковырялся-ковырялся, но так и не смог сделать ещё один буфер. wglCreateContext напрочь отказывается создавать контекст, если ей передают hDc чего-то, кроме формы. Пробовал с HBITMAP, пробовал с Gdiplus::Bitmap и Gdiplus::Graphics, не работает. Не могу применить ваш совет.

Уточнил флаги, которые использует freeglut, лучше не стало. Хотя у меня такое чувство, что это какой-то обманный манёвр. Потому что freeglut сначала создаёт контекст и сразу же высвобождает, а потом создаёт его только где-то в дебрях (отслеживал отладчиком), кода которых у меня нет. Так что придётся либо писать 64-битную программу с freeglut, либо 32-битную с glut и таскать библиотеки, либо ковыряться дальше. В каждом варианте свои минусы.

ExpandedWrap disabled
    #include <windows.h>
    #include <gl/GL.h>
    #define _USE_MATH_DEFINES  
    #include <cmath>
    #pragma comment(lib, "opengl32.lib")
     
    #define CLASSNOTREGISTERED 1
    #define WINDOWNOTCREATED 2
    #define MESSAGENOTGOT 3
    #define OGLCONTEXNOTCREATED 4
    #define OGLCONTEXNOTMADECURRENT 5
    #define PIXELFORMATNOTSET 6
     
    class Application
    {
        public:
            HINSTANCE hInstance;
            HWND hWnd;
            HDC windowDC;
            HGLRC hglrc;
            LPCTSTR classname;
            WNDCLASS wndclass;
    };
     
    Application app;
    float angle = 1.0;
     
     
    void DrawScreen()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glBegin(GL_TRIANGLES);
     
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(0.5*sin(angle), 0.5*cos(angle), 0.0);
     
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f(0.5*sin(angle + 2 * M_PI / 3), 0.5*cos(angle + 2 * M_PI / 3), 0.0);
     
        glColor3f(0.0, 0.0, 1.0);
        glVertex3f(0.5*sin(angle + 4 * M_PI / 3), 0.5*cos(angle + 4 * M_PI / 3), 0.0);
     
        glEnd();
        glFlush();
        SwapBuffers(app.windowDC);
    };
     
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
            case WM_PAINT:
                DrawScreen();
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
     
    int WinLoop()
    {
        MSG msg = { 0 };
        int iGetOk = 0;
        while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
        {
            if (iGetOk == -1) return MESSAGENOTGOT;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        };
        return msg.wParam;
    };
     
    ATOM RegMyWindowClass()
    {
        ZeroMemory(&(app.wndclass), sizeof(WNDCLASS));
     
        app.wndclass.lpfnWndProc = (WNDPROC)WndProc;            // адрес ф-ции обработки сообщений
        app.wndclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// стиль окна
        app.wndclass.hInstance = app.hInstance;                 // дискриптор экземпляра приложения
        app.wndclass.lpszClassName = app.classname;             // название класса
        app.wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);     // загрузка курсора
        app.wndclass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;// загрузка цвета окон
        return RegisterClass(&app.wndclass);                    // регистрация класса
    };
     
    bool SetWindowFormat()
    {
        PIXELFORMATDESCRIPTOR pfd;
        ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
     
        int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
     
        /* Specify which pixel format do we opt for... */
        pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
        pfd.nVersion = 1;
        pfd.dwFlags = flags;
     
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cRedBits = 8;
        pfd.cGreenBits = 8;
        pfd.cBlueBits = 8;
        pfd.cAlphaBits = 0;//(fgState.DisplayMode & GLUT_ALPHA) ? 8 : 0
     
        pfd.cColorBits = 24;
        pfd.cRedShift = 0;
        pfd.cGreenShift = 0;
        pfd.cBlueShift = 0;
        pfd.cAlphaShift = 0;
        pfd.cAccumBits = 0;//(fgState.DisplayMode & GLUT_ACCUM) ? 1 : 0
        pfd.cAccumRedBits = 0;
        pfd.cAccumGreenBits = 0;
        pfd.cAccumBlueBits = 0;
        pfd.cAccumAlphaBits = 0;
     
        /* Hmmm, or 32/0 instead of 24/8? */
        pfd.cDepthBits = 24;
        pfd.cStencilBits = 8;
     
        pfd.cAuxBuffers = 0;//(BYTE)fghNumberOfAuxBuffersRequested()
        pfd.iLayerType = 0;//layer_type
        pfd.bReserved = 0;
        pfd.dwLayerMask = 0;
        pfd.dwVisibleMask = 0;
        pfd.dwDamageMask = 0;
     
        pfd.cColorBits = (BYTE)GetDeviceCaps(app.windowDC, BITSPIXEL);
     
     
        int nPixelFormat = ChoosePixelFormat(app.windowDC, &pfd);
        if (nPixelFormat == 0)
            return false;
     
        SetPixelFormat(app.windowDC, nPixelFormat, &pfd);
     
        return true;
    };
     
    int WinInit()
    {
        app.classname = TEXT("My Window Class!");
     
        if (!RegMyWindowClass())
            return CLASSNOTREGISTERED;
     
        if ((app.hWnd = CreateWindow(app.classname, TEXT("Dialog Window"), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, app.hInstance, NULL)) == 0)
            return WINDOWNOTCREATED;
     
        app.windowDC = GetDC(app.hWnd);
        if (!SetWindowFormat())
            return PIXELFORMATNOTSET;
     
        return 0;
    }
     
    int WinOGLInit()
    {
        app.hglrc = wglCreateContext(app.windowDC);
        if (app.hglrc == 0)
            return GetLastError();
     
        if (!wglMakeCurrent(app.windowDC, app.hglrc))
            return OGLCONTEXNOTMADECURRENT;
     
        return 0;
    };
     
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        app.hInstance = hInstance;
        int initresult;
        
        initresult = WinInit();
        if (initresult != 0)
            return initresult;
     
        initresult = WinOGLInit();
        if (initresult != 0)
            return initresult;
     
        return WinLoop();  
    }
Сообщение отредактировано: k.sovailo -
M
Тема отображена в разделе(ах): Программирование графики
Сообщение на автоудалении
Одни с годами умнеют, другие становятся старше.
Цитата k.sovailo @
ЫукпШ, я ковырялся-ковырялся, но так и не смог сделать ещё один буфер. wglCreateContext напрочь отказывается создавать контекст, если ей передают hDc чего-то, кроме формы.

Вот, я посмотрел.
Ты используешь :
ExpandedWrap disabled
    class Application
    {
        public:
            HINSTANCE hInstance;
            HWND hWnd;
            HDC windowDC;
            HGLRC hglrc;
            LPCTSTR classname;
            WNDCLASS wndclass;
    };

Если в структуру подставить HDC какого-нибудь memdc ?
Созданного на WINAPI.
Всё должно работать.
А потом в WM_PAINT просто выполним "BitBlt" в соответствии с размерами прямоугольника,
передаваемого в Paint - структуре.
Подпись была выключена в связи с наложенным заземлением.
ЫукпШ
ExpandedWrap disabled
    app.windowDC = GetDC(app.hWnd);
    SetOGLPixelFormat(app.windowDC));//pfd и всё остальное - в этой функции
    app.bufferDC = CreateCompatibleDC(app.windowDC);
    app.hBuffer = CreateCompatibleBitmap(app.bufferDC, 800, 600);
    SetOGLPixelFormat(app.bufferDC);
    SelectObject(app.bufferDC, app.hBuffer);//советовали на одном форуме
    wglMakeCurrent(app.bufferDC, NULL);//советовали на другом форуме
    app.hglrc = wglCreateContext(app.bufferDC);//возвращает 0


Не работает. Если создавать битмап в контексте окна, тоже не работает. Я правильно понял?
Сообщение отредактировано: k.sovailo -
Я тут провёл ещё несколько попыток и понял, что лучше доверить эту работу freeglut. Закончилось на том, что я подкорректировал код, добавил getHWND() и написал функцию динамического подключения freeglut.dll. Спасибо за внимание.
Цитата k.sovailo @
Не работает. Если создавать битмап в контексте окна, тоже не работает. Я правильно понял?

Трудно мне без отладки по тексту сказать точно, где ошибка.
я делал так:
ExpandedWrap disabled
    //..
     HDC d_c   = ::CreateDC(_T("DISPLAY"),NULL,NULL,NULL);
     HDC memdc = ::CreateCompatibleDC  (d_c);
     
     RECT rc;  ::GetWindowRect (::GetDesktopWindow(), &rc);
     
    // размер скрина:
     int sizex  = (rc.right   - rc.left) ;
     int sizey  = (rc.bottom  - rc.top)  ;
     
     HBITMAP hbit = ::CreateCompatibleBitmap (d_c, sizex, sizey);  ::SelectObject (memdc, hbit);
     HBRUSH brush = ::CreateSolidBrush  (someColor);               ::SelectObject (memdc, brush);
     
     ::PatBlt(memdc,0,0,sizex,sizey,PATCOPY); // закрасить memdc кистью brush цвета someColor
     
     ::DeleteDC(d_c);
    //...
     
    // в результате получили memdc размером с экран.
    // зачищенный цветом  "someColor".
    // функциями GDI там можно рисовать что угодно. Можно читать/писать посредством "BitBlt" любыми кусками.


Понятно, что лучше все эти объекты обернуть классами, поскольку попытка следить за ними "вручную"
скорее всего закончится утечкой ресурсов. Исходник в таком виде я представил для примера.
-----
Хочу заметить, что всё это имеет конкретное практическое применение.
Например, что делать, если рисование картинки занимает 1 секунду (или больше)?
Если сделать это из оконной процедуры, тогда на это время всё управление приложением
будет парализовано, в том числе перерисовка экрана. При этом сам вывод картинки
на экран (даже самый большой) может составить 1 [мс] или меньше.
Рисовать имиджи можно и в другом потоке.
Поэтому разделение этих 2-х операций весьма перспективное мероприятие.
Сообщение отредактировано: ЫукпШ -
Подпись была выключена в связи с наложенным заземлением.
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,1573 ]   [ 22 queries used ]   [ Generated: 23.09.18, 14:12 GMT ]