На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела "Программирование графики"
1) Данный раздел предназначен для обсуждения проблем, возникающих при программировании задач, связанных с чтением, сохранением, обработкой, созданием, отрисовкой графической информации (в том числе - 3D [OpenGL, Direct3D] и анимации [в т.ч. VFW, DirectShow, OpenDML]).
Флэш обсуждают здесь!.

2) Если вы хотите получить совет для конкретной платформы/языка программирования, обязательно укажите их в вопросе.

3) Уважаемые новички! Мы приветствуем Ваше желание научить всех посетителей раздела правильному программированию. Но огромная просьба, перед тем, как писать поучения в старых (последний ответ - "старее" месяца, а особенно, если вопрошавший не появляется на форуме уже не первый месяц, в чем можно убедиться в его профиле) темах, хорошо подумать, будет ли кому-нибудь, кроме Вас cамих, это интересно.



Ваше мнение о модераторах: user posted imageBarazuk, user posted imageOpenGL, user posted imageMikle
Модераторы: OpenGL, Mikle
  
> Не работает функция glReadPixels
    Пытаюсь заскриншотить экран, нашел функцию glReadPixels. Если кому интересно, вот ее прототип:
    ExpandedWrap disabled
      void glReadPixels(GLint  x,  GLint  y,  GLsizei  width,  GLsizei  height,  GLenum  format,  GLenum  type,  GLvoid *  data);

    Согласно описанию, функция возвращает указатель на данные в GLvoid *data, однако мне кажется, что нулевой указатель не похож на смысл ее существования. Я сначала думал, что какая-то ошибка, попробовал вызвать glGetError
    ExpandedWrap disabled
      #include <GL/gl.h>
       
      using namespace std;
       
      int main()
      {
        GLvoid *data;
        glReadPixels(0,0,1920,1080,GL_BGR,GL_UNSIGNED_BYTE,data);
        cout << glGetError() << endl << data << endl;
      }
    Результат: ошибки нет, указатель данных равен нулю. Я малость в ступоре, даже не знаю куда копать. Лично меня осенили только три идеи: либо это что-то типа хэндла -- но в документации ничего такого не упоминается; либо он должен записать в созданный мной заранее буфер -- пробовал: массив типа GLvoid нельзя создать, однако для пробы я создал массив другого типа, инициализованный заранее мне известными значениями. Компилятор ругаться не стал. И вызов функции совершенно никак на них не повлиял. Наконец третий вариант -- это какой-то странный баг.

    ОС:Ubuntu
    Компилятор:gcc
    Сообщение отредактировано: just-a-guest -
      Здрасьте-приехали. У тебя есть фреймбуфер, из которого она что-то вменяемое могла бы вернуть?
        Извиняюсь, в ОпенГЛ я новичок :) Намек понял, прочел туториал про фреймбуфера. Добавил glGenFramebuffers и glBindFramebuffer. Чем дальше в лес, тем больше дров: кол-во мистики зашкалило -- можно теперь, опубликоваться в местные газеты. Я нашел, что вышеупомянутые функции упоминаются в glext.h и gl_mangle.h и добавил их. Однако компилятор все равно отказывается находить их декларацию. Не зная, что еще придумать, я просто вручную вписал их прототипы в код -- все равно с библиотекой слинкуются, должны работать. Однако линкер моего мнения не разделил и вежливо, без мата, отказался линковать. Как-то так:
        ExpandedWrap disabled
          constantine@constantine-N61Ja:~/Projects/OCVTut/bin/Debug$ g++ test1.cpp -lGL -g
          /tmp/ccMKpXsk.o: In function `main':
          /home/constantine/Projects/OCVTut/bin/Debug/test1.cpp:13: undefined reference to `glGenFramebuffers(int, unsigned int*)'
          /home/constantine/Projects/OCVTut/bin/Debug/test1.cpp:14: undefined reference to `glBindFramebuffer(int, unsigned int*)'
          collect2: ошибка: выполнение ld завершилось с кодом возврата 1
        С библиотекой я не ошибся:
        ExpandedWrap disabled
          constantine@constantine-N61Ja:~/Projects/OCVTut/bin/Debug$ nm -D /usr/lib/x86_64-linux-gnu/libGL.so|grep glGenFramebuffers
          000000000004a3e0 T glGenFramebuffers
          000000000004a3e0 T glGenFramebuffersEXT

        Я вообще думал, что может с кодировкой какие-то проблемы -- я сначала код функции просто скопировал с браузера. Но нет, я уже и вручную переписал и даже копировал с терминала, то, что выше привел, тщетно. В-общем код сейчас выглядит так:
        ExpandedWrap disabled
          #include <GL/gl.h>
          #include <GL/glext.h>
          #include <iostream>
          //#include <GL/gl_mangle.h>
           
          using namespace std;
           
          void glBindFramebuffer(GLsizei n, GLuint  *framebuffers);
          void glGenFramebuffers(GLsizei n, GLuint *ids);
           
          int main()
          {
            GLuint* ids=0;
            glGenFramebuffers(1,ids);
            glBindFramebuffer( GL_READ_FRAMEBUFFER, ids );
            glReadPixels(0,0,1920,1080,GL_BGR,GL_UNSIGNED_BYTE,ids);
            if(!ids)cout << "No buffer" << endl;
          }
        Обратите внимание на закомментированный хедер. Совершенно непонятно, почему, но если его оставить в коде, то ошибка меняется на такую:
        ExpandedWrap disabled
          constantine@constantine-N61Ja:~/Projects/OCVTut/bin/Debug$ g++ test1.cpp -lGL -g
          test1.cpp: В функции «int main()»:
          test1.cpp:16:57: ошибка: нет декларации «mglReadPixels» в этой области видимости

        Добавляет к именам OpenGL функций букву m и радостно сообщает, что таких не существует.
        Сообщение отредактировано: just-a-guest -
          Мощно :D gl-функции к скриншоту экрана не имеют никакого отношения. Делайте через GetDC, CreateCompatibleBitmap, SelectObject и GetDIBits.
          Если не получится, позже набросаю пример.
            Просто я выбрал OpenGL, чтобы можно было потом приложение перекомпилировать под винду. И здесь, у меня на Убунте оно тоже работало. GetDC исключительно виндовая функция, и, наверное, у иксов есть свой аналог -- но это уже кроссплатформенным, увы, не будет.
            Хотя, если решения не найду, придется пользоваться ими.
              А, точно, убунту не заметил :D
              В любом случае OpenGL в данном случае нужен не более, чем функции работы с сетью, например. Из готовых кроссплатформенных решений есть, например, Qt (QDesktopWidget + grabWindow).
              Но если скриншот это одна (или одна из немногих) некроссплатформенных фич, то проще ее написать самому, используя платформозависимые функции.
                В-общем попробовал написать на QT: самый минимум кода, и он умудряется все равно валиться
                ExpandedWrap disabled
                  #include <QtCore>
                  #include <QtGui>
                  #include <iostream>
                   
                  int main(int argc, char* argv[])
                  {
                    std::cout << (int)QApplication::desktop()->winId();
                  }
                ExpandedWrap disabled
                  QWidget: Must construct a QApplication before a QPaintDevice
                  Аварийный останов (сделан дамп памяти)

                Гугл сказал что такие проблемы обычно бывают при запуске дебаг версии, я перекомпилировал в релиз -- ничего не изменилось.
                Пока вынужден оставить свои скитания по пустыне проб и ошибок, чуть попозже продолжу)
                  Цитата
                  самый минимум кода,

                  Вы откуда это взяли?

                  Цитата
                  и он умудряется все равно валиться

                  а с чего-бы оно должно работать?

                  читаем доку:
                  QApplication::QApplication

                  А вообще, вам ошибка говорит, что делать ;)
                  Сообщение отредактировано: maxim84_ -
                    Цитата OpenGL @
                    Но если скриншот это одна (или одна из немногих) некроссплатформенных фич, то проще ее написать самому, используя платформозависимые функции.
                    +1. К тому же ваш, just-a-guest, особый ОС-вариант займёт в пределе 30 Кб, а с Qt выльется в 30 Мб. И нафига?
                      Прошу прощения, за столь долгий перерыв; итак, по результатам голосования среди меня и меня, самым бесполезным хидером объявляется glext.h, поприветствуем победителя. Именно благодаря ему, у меня возникала ошибка, и именно он обладатель функций, объявления которых все равно пришлось переписывать.
                      Собственно проблема крылась в манглинге имен функций. Честно говоря до сих пор знал об этом весьма абстрактно. С++ по тех. причинам переименовывает функции на стадии препроцессинга, причем способ меняется от компилятора к компилятору. И, для линковки с внешней библиотекой конкретной функции, нужно запретить ее переименование с помощью extern "C"{}.
                      Удивительно: эта директива в glext.h есть, но, почему то не работает. Видимо какой-то баг препроцессора gcc.

                      Я решил продолжить с OpenGL, дабы не изобретать велосипед и теперь вернулся к самому началу темы, код
                      ExpandedWrap disabled
                        #include <GL/gl.h>
                        #include <iostream>
                         
                        using namespace std;
                         
                        extern "C"{
                        void glBindFramebuffer(GLsizei n, GLuint  *framebuffers);
                        void glGenFramebuffers(GLsizei n, GLuint *ids);
                        }
                         
                        int main()
                        {
                          GLuint* ids=0;
                          glGenFramebuffers(1,ids);
                          glBindFramebuffer( GL_READ_FRAMEBUFFER, ids );
                          glReadPixels(0,0,1280,800,GL_BGR,GL_UNSIGNED_BYTE,ids);
                          if(!ids)cout << "No buffer!" << endl;
                        }
                      не работает, или, приводя небезызвестную, надеюсь цитату: "No buffer!". glReadPixels, увы, ничего в ids не возвращает.
                      Что я неправильно делаю?

                      UPD: ну, т.е, насколько я теперь уже понял, glReadPixels должен писать в заранее созданный мной массив, размером WIDTHxHEIGHTx3. Я конечно его не создавал, но, в любом случае программа должна вылетать при попытке записи по нулевому указателю *ids; посколько этого не происходит, glReadPixels не работает.
                      Сообщение отредактировано: just-a-guest -
                        :wacko:
                        Во-первых, сказано же уже, что к скриншоту экрана glReadPixels не имеет никакого отношения. Во-вторых, даже если вам нужен скрин окна opengl - вы не сможете получить от gl-функций ничего до его создания. Ну и в-третьих glBindFramebuffer это из совсем другой оперы.

                        Добавлено
                        Цитата Славян @
                        +1. К тому же ваш, just-a-guest, особый ОС-вариант займёт в пределе 30 Кб, а с Qt выльется в 30 Мб. И нафига?

                        Под убунтой обычно qt линкуется динамически (а библиотеки часто уже есть в системе), поэтому на размер исполняемого файла не влияет. А если учесть, что qt это кроссплатформенные окна и куча полезных классов, то оно вполне можжет быть оправданным.
                          OpenGL, спасибо, я понял... Просто google выдает множество ссылок по вопросу OpenGL screenshot, это меня ввело в заблуждение. Насколько я понимаю glReadPixels может сделать снимок только созданного лично мной окна. Помечаю вопрос решенным.
                            Цитата OpenGL @
                            Под убунтой обычно qt линкуется динамически (а библиотеки часто уже есть в системе), поэтому на размер исполняемого файла не влияет. А если учесть, что qt это кроссплатформенные окна и куча полезных классов, то оно вполне можжет быть оправданным.
                            Спасибо. Не знал.
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0380 ]   [ 15 queries used ]   [ Generated: 25.04.24, 20:46 GMT ]