"продвинутое рисование на форме"

Средства разработки, технические вопросы, отвечает (по мере сил) Отдел Разработок
apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

"продвинутое рисование на форме"

Сообщение apachik » Ср апр 12, 2006 03:48

дано:
VS 2005 NET CF

нужно:
каждую секунду рисовать много-много всего на экране и так, чтобы не моргало.

идея:
если просток каждую секунду перерисоваывать, будут тормоза и моргания экрана. а ведь можно и так: каждую секунду начинаем рисовать, но не по форме, а по какому нибудь битмапу (пусть на это уйдет даже 0.1с) потом мгновенно меняем изображение на экране на наш битмап и получаем то что хотели (нет моргания)

вопрос: как это сделать?

ВадимП
Нобелевский лауреат (7 lvl)
Сообщения: 6385
Зарегистрирован: Ср июн 04, 2003 15:03

Сообщение ВадимП » Ср апр 12, 2006 04:10

плохая идея

apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

Сообщение apachik » Ср апр 12, 2006 17:17

ну предложи другую тогда. мне не так важно, чтобы изображение мгновенно прорисовывалось, нужно чтобы оно быстро менялось и не было мерцания экрана.

нужно типа двойная буферизация вывода на экран. как это делается?

Ginger
Кандидат (3 lvl)
Сообщения: 151
Зарегистрирован: Вс июл 20, 2003 11:03

Сообщение Ginger » Ср апр 12, 2006 17:22

ВадимП писал(а):плохая идея
Акуеннограмматный ответ! Жаль, что я так не могу! =)
В который раз уже убеждаюсь, что от этого товарисча не бывает толковых ответов - умен больно, блин, не для нашего уровня!

А по твоему вопросу, я бы хотел добавить, что под .Net ничего нельзя писать критичного по времени - уж больно много у нее прослоек (сюда же входит и без нее не быстрый GDI), пока до железа дойдет - пройдет столько времени, что даже человеку заметно.

Для организации backbuffer я бы посоветовал GAPI или на худой конец BITMAP из GDI, хотя полседний так же очень медленный, что бы через него рисовать быстро на экране.

ВадимП
Нобелевский лауреат (7 lvl)
Сообщения: 6385
Зарегистрирован: Ср июн 04, 2003 15:03

Сообщение ВадимП » Ср апр 12, 2006 19:17

apachik писал(а):нужно типа двойная буферизация вывода на экран. как это делается?
Вот именно - нужна именно двойная буферизация. Могу рассказать как это делается для Linux-КПК и сильно сомневаюсь, что ее нет на winmobile.

sshd
Нобелевский лауреат (7 lvl)
Сообщения: 2159
Зарегистрирован: Вс мар 19, 2006 15:55

Сообщение sshd » Ср апр 12, 2006 22:06

а почему ты тогда сказал "плохая идея"? :)
он вроде и описал двойную буферизацию:
"рисовать на битмапе, а потом выводить на экран"
Samsung GT-S8500 + MicroSD 8Gb

apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

Сообщение apachik » Чт апр 13, 2006 00:27

Ginger писал(а): А по твоему вопросу, я бы хотел добавить, что под .Net ничего нельзя писать критичного по времени - уж больно много у нее прослоек (сюда же входит и без нее не быстрый GDI), пока до железа дойдет - пройдет столько времени, что даже человеку заметно.

Для организации backbuffer я бы посоветовал GAPI или на худой конец BITMAP из GDI, хотя полседний так же очень медленный, что бы через него рисовать быстро на экране.
про тормознутость я знаю, но она меня вполне устраивает.
ну и пусть медленно рисует, мне нужно чтобы быстро меняло.
времени изучать GAPI совсем нету (я пробежался и понял, что там много всего всего).
с битмапом вроде попроще работать будет?
только вот мне на нем не отдельные пиксели ставить, а фигуры рисовать с заливкой, писать самому эти функции понятное дело подходит.

много кода нужно для реализации двойной буферизации?
научите пожалуйста! я в программировании под КПК совсем новичек, справку VS, MSDN читать на англ. не напрягает, но вот разбираться с новой технологией времени вообще нет.

ВадимП
Нобелевский лауреат (7 lvl)
Сообщения: 6385
Зарегистрирован: Ср июн 04, 2003 15:03

Сообщение ВадимП » Чт апр 13, 2006 01:40

sshd писал(а):а почему ты тогда сказал "плохая идея"? :)
он вроде и описал двойную буферизацию:
"рисовать на битмапе, а потом выводить на экран"
Насколько я понял первоначальное предложение, речь шла о формировании изображения в некотором буфере в системной памяти, которое затем обычной memcpy() копируется в кадровый буфер видеокарты (который у большинства КПК также находится в системной памяти).
Этот процесс, синхронизированный по времени с сигналом вертикального обратного хода луча (луча, правда, в LCD-мониторах давно нет, но сигнал остался), тоже иногда называли раньше двойной буферизацией.
Но сейчас этот термин всё-таки больше закрепился за тем, что в стародавние времена обзывали "page flipping":
Double Buffering means that there are two display buffers. This means that the next image can be drawn in the page of the display buffer, which is initially invisible. This image is displayed once it is ready and the next image is prepared in the other page of the buffer. Animation's and games can be made to look more realistic with this technique than in simple single buffer mode.
И я не вижу абсолютно никаких преимуществ в первом предложенном варианте - напротив, только недостатки в частности за счет дополнительных потерь времени на копирование.
Переключать буфера на мой взгляд гораздо удобнее и проще.
(никаких проблем с созданием необходимого числа буферов и свободным переключением между ними, по крайней мере, на Linux-КПК нет - начало отображаемой части видеопамяти определяется указателем screen_base, который используется низкоуровневым драйвером кадрового буфера).

Ginger
Кандидат (3 lvl)
Сообщения: 151
Зарегистрирован: Вс июл 20, 2003 11:03

Сообщение Ginger » Чт апр 13, 2006 10:14

Про CF не скажу так ли это делается или нет, но для GDI выглядит все просто:

Код: Выделить всё

    HDC memDC = CreateCompatibleDC ( hDC );
    HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
    SelectObject ( memDC, memBM );
hDC - как понимаешь, тот DC в котором должен быть виден конечный результат пользователю.
Все теперь можешь рисовать на memDC, а результат будет храниться в memBM.
Когда заканчиваешь рисовать, то BitBlt копируешь memDC на тот DC который у тебя на экране. все.

apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

Сообщение apachik » Чт апр 13, 2006 10:58

мне на другом форуме подсказали:
artko писал(а):2 *apachik*:
ну вы даете. а доки читали?
class my_control : Control
{
....
protected override OnPaint(PaintEventArgs e)
{
Bitmap bmp_buffer = new Bitmap(this.Width, this.Height);
Graphics gr_buffer = Graphics.FromImage(bmp_buffer);
... рисуем по gr_buffer....
e.Graphics.DrawImage(bmp_buffer, 0, 0);
}
}
работает :D . только вот DrawImage тормозит. можно побыстрее сделать?

sshd
Нобелевский лауреат (7 lvl)
Сообщения: 2159
Зарегистрирован: Вс мар 19, 2006 15:55

Сообщение sshd » Чт апр 13, 2006 13:20

ВадимП писал(а):И я не вижу абсолютно никаких преимуществ в первом предложенном варианте - напротив, только недостатки в частности за счет дополнительных потерь времени на копирование.
Переключать буфера на мой взгляд гораздо удобнее и проще.
(никаких проблем с созданием необходимого числа буферов и свободным переключением между ними, по крайней мере, на Linux-КПК нет - начало отображаемой части видеопамяти определяется указателем screen_base, который используется низкоуровневым драйвером кадрового буфера).
тоесть ты предлагаешь перерисовывать _весь_ экран????
во-первых на покете это вроде бы нельзя делать, во-вторых я так понял, что нужно рисовать в окошке.
page flipping вообще какая-то древняя технология. на спектруме была.
Samsung GT-S8500 + MicroSD 8Gb

sshd
Нобелевский лауреат (7 lvl)
Сообщения: 2159
Зарегистрирован: Вс мар 19, 2006 15:55

Сообщение sshd » Чт апр 13, 2006 13:22

apachik писал(а):работает :D . только вот DrawImage тормозит. можно побыстрее сделать?
можно.
использовать native code.
Samsung GT-S8500 + MicroSD 8Gb

ВадимП
Нобелевский лауреат (7 lvl)
Сообщения: 6385
Зарегистрирован: Ср июн 04, 2003 15:03

Сообщение ВадимП » Чт апр 13, 2006 17:31

sshd писал(а): во-вторых я так понял, что нужно рисовать в окошке.
page flipping вообще какая-то древняя технология. на спектруме была.

Да-да, совсем древняя... Вся трехмерная графика (во всяком случае OpenGL) именно на ней и построена - Вы же пишете при инициализации окна glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
а потом по мере надобности glutSwapBuffers();
(для краткости привожу примеры с использованием библиотеки GLUT, но идея от этого не меняется - могу переписать то же самое на чистом GLX. Только длиннее будет)
Создаём область видеопамяти с двойной буферизацией:

Код: Выделить всё

  Display *dpy;
  Screen *scr;
  int scrnum;
  int attrib[] = { GLX_RGBA,
                   GLX_RED_SIZE, 1,
                   GLX_GREEN_SIZE, 1,
                   GLX_BLUE_SIZE, 1,
                   GLX_DOUBLEBUFFER,
                   GLX_DEPTH_SIZE, 1,
                   None };
    XVisualInfo *visinfo;

   scrnum = XScreenNumberOfScreen(scr);
   root   = XRootWindow(dpy, scrnum);
   visinfo = glXChooseVisual( dpy, scrnum, attrib );
прим: для краткости я не стал записывать API создающие окно на базе этого visual.
А потом, после окончания формирования изображения на экране, пишем glXSwapBuffers(dpy, win);
Кстати, независимо от того, перерисовываем ли мы весь экран или небольшой его кусочек - для этого существуют такие инструменты как ножницы (scissors) и трафаретный буфер (stencil buffer).
(трехмерные игры-то спокойно запускаются в окне и двойная буферизация в видеопамяти этому не мешает)
Я конечно понимаю, что исходный вопрос не имел никакого отношения к трехмерной графике и что видеоподсистемы КПК не обеспечивают, увы, необходимой аппаратной поддержки для реализации подобных средств (хотя последнее-то как раз и не имеет особого значения - библиотеки при необходимости эмулируют недостающие возможности программно). Я просто хотел поддержать уважаемого sshd в том, что подобная техника - это несомненно самый что ни на есть каменный век и всяким там doom'ам 3 и quake'ам 4 если и осталось место, то именно на Spectrum'ах! ;)

apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

Сообщение apachik » Чт апр 13, 2006 17:43

sshd писал(а):тоесть ты предлагаешь перерисовывать _весь_ экран????
во-первых на покете это вроде бы нельзя делать, во-вторых я так понял, что нужно рисовать в окошке.
page flipping вообще какая-то древняя технология. на спектруме была.
мне нужно перерисовывать почти весь экран - кроме нижней строки с меню и верхней информационной строки (там всякие лэйблы). строка с заголовком окна убрана нах.

apachik
Студент (1 lvl)
Сообщения: 25
Зарегистрирован: Сб фев 18, 2006 20:57

Сообщение apachik » Чт апр 13, 2006 18:06

вот что я нашел
http://www.codeproject.com/bitmap/drawi ... licker.asp
Explanation of Double Buffering
If you have to draw repeatedly to the screen in a short period of time, then when you keep drawing step by step to the DC, it updates the Window again and again which makes the screen flicker.

To avoid this, we first draw to a DC in memory (see the CDC MemDC and CBitmap MemBitmap declarations), and we store the resultant drawing in a memory bitmap. After all the drawing has been completed, we move the bitmap from the memory to the screen in a fast single bitblt call. Thus, we only need to draw once to the screen which avoids flickering totally. This principle is called Double Buffering.

Example code
This example assumes that you are going to draw filled rectangles onto the screen. It generates random shades of green to fill that rectangle.

Use this code in your view class's OnDraw() function if you are using Doc/View architecture or if you are using a dialog based application, then you can add this code in the OnPaint Function.

Код: Выделить всё

    CRect rcClient;		
    GetClientRect(rcClient);	// See Note 1

    CDC MemDC,*pDC;
    CBitmap MemBitmap;

    pDC = this->GetDC()         // Get Current DC
    MemDC.CreateCompatibleDC(pDC);
    MemBitmap.CreateCompatibleBitmap(pDC,rcClient.right,rcClient.bottom);

    CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap);
    CBrush bkBrush(HS_FDIAGONAL,RGB(0,rand()%255,0));	// See Note 2
    MemDC.FillRect(rcClient,&bkBrush);

    pDC->BitBlt(0,0,rcClient.right,rcClient.bottom,&MemDC,0,0,SRCCOPY);	//See Note 3
    MemDC.SelectObject(pOldBitmap);
Note 1 : Gets the coordinates of the bounding rectangle.
Note 2 : Creates a brush with random shades of green. The rand()%255 generates a value between 0 and 255 randomly.
Note 3 : Copies the bitmap from the memory dc to the pdc using a fast bitblt function call.

но это все для С++

Закрыто

Вернуться в «Программирование для КПК»