Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.125.2] |
|
Сообщ.
#1
,
|
|
|
Когда я писал простые графические вещи - такие как рисование в окне, то функции рисования я размещал в обработчике сообщения WM_PAINT. Все прекрасно работало. Однако, возникла необходимость написания 3D графики. Выбрал OpenGL.
Во многих примерах рисование происходит в главном окне программы, а у меня - в дочернем окне. Это возможно не повлияет на дальнейшее решение проблемы, но информация к сведению. Теперь в чем проблема : в описанных примерах запускается бесконечный цикл while, который шурует постоянное рисование и тем самым перегревая процессор. Так как графика у меня статическая и должна изменяться первое - по действию пользователя (например нажал на кнопку графический объет повернулся на угол и т.д) и второе - при перекрытии окон и изменении их размеров. Поэтому крутить бесконечный цикл - как-то не рационально. void ThreedviewCreateDlg(HWND hwnd, HINSTANCE hinstance) { // ... // здесь создается диалоговое дочернее окно, в котором будет выводиться 3D графика //... //while(!e::threedviewdone) // Loop That Runs While threedviewdone=FALSE //{ DrawGLScene(); SwapBuffers(e::threedviewhdc); //} } BOOL DrawGLScene() { glClearColor(1.0f, 1.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(-1.5f,0.0f,-6.0f); glRotatef(e::threedviewrtri, 0.0f, 1.0f, 0.0f); GLUquadricObj *q; q = gluNewQuadric(); glColor3f(0.0f, 0.0f, 1.0f); gluCylinder(q, 1.0f, 1.0f, 3.0f, 32, 32); return TRUE; } LRESULT CALLBACK WndProcThreedview(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { // ... switch (message) { //case WM_PAINT: // DrawGLScene(); // SwapBuffers(e::threedviewhdc); // return 0; return DefWindowProc(hwnd, message, wparam, lparam); } Вопрос : Как определить, когда нужно перерисовать окно, какие обрабатывать сообщения ? |
Сообщ.
#2
,
|
|
|
Перерисовка по событию таймера решает проблему лишней перегрузки процессора.
Вопрос решен. |
Сообщ.
#3
,
|
|
|
Цитата Mr.Brooks @ Как определить, когда нужно перерисовать окно, какие обрабатывать сообщения ? Цитата Mr.Brooks @ например нажал на кнопку графический объет повернулся на угол и т.д Ты сам же ответил на свой вопрос. И таймер здесь не нужен |
Сообщ.
#4
,
|
|
|
Цитата Ты сам же ответил на свой вопрос. И таймер здесь не нужен Когда мое приложение имеет фокус то таймер действительно не за чем, обрабатываются: 1. WM_SIZE 2. WM_MOVE - потому как не изменяя размеры можно вынести окно за границы desktop и вернуть затертое окно 3. WM_KEYDOWN - это действия пользователя клавиатурой (типа поворот, приближение) 4. WM_LBUTTONDOWN - это действия пользователя мышью (типа поворот, приближение) но при потере фокуса если переключиться на другое приложение и носить его над моим окном произойдет затирание, вот здесь я и включаю таймер case WM_ACTIVATEAPP: if (wparam) { ThreedviewRefresh(); KillTimer(hwnd, 1); } else { SetTimer(hwnd, 1, 10, 0); } return 0; case WM_TIMER: if (wparam == 1) { ThreedviewRefresh(); } return 0; Использование таймера для перерисовки позволяет отказаться от цикла while (картинка статическая fps-ы не нужны) и заметно уменьшить загрузку процессора. |
Сообщ.
#5
,
|
|
|
А это нормально вообще - рисовать (переделывать=пересчитывать=...) сцену много раз в секунду, ежели на ней ничего не меняется? Ненужный же напряг граф. проц-а! Или как?..
|
Сообщ.
#6
,
|
|
|
Цитата А это нормально вообще - рисовать (переделывать=пересчитывать=...) сцену много раз в секунду, ежели на ней ничего не меняется Мне тоже это не нравится. Хорошо, тогда вопрос, а как запомнить то, что было нарисовано в окне и как это потом отрисовать, если окно было перекрыто другим? |
Сообщ.
#7
,
|
|
|
В OpenGL всё (по умолчанию) рисуется в буфер, кой потом быстро кидается граф. проц-ром в память/на экран. Если вы озаботитесь, чтобы у вас в обоих буферах нарисована была одна и та же сцена, то нужно лишь будет "менять" активность буферов (wglSwapBuffers и т.п.), что сделает почти мгновенным переброс=перерисовку картинки на экране. Для эксперимента, попробуйте:
1.Нарисовать сцену. 2.Поменять буферы. 3.Нарисовать её же. 4.При всяком переносе/перекрытии окна просто меняйте буферы. П.С. в идеале бы, конечно, как-то сказать на шаге №3, чтобы перекинуть готовое в текущий буфер, но как сделать сие (и можно ли?) не знаю. |
Сообщ.
#8
,
|
|
|
Попробовал
вместо case WM_ACTIVATEAPP: if (wparam) { ThreedviewRefresh(); KillTimer(hwnd, 1); } else { SetTimer(hwnd, 1, 10, 0); } return 0; case WM_TIMER: if (wparam == 1) { ThreedviewRefresh(); // где рисование + копирование с буфера } return 0; сделал case WM_ACTIVATEAPP: if (wparam) { ThreedviewRefresh(); KillTimer(hwnd, 1); } else { SetTimer(hwnd, 1, 10, 0); } return 0; case WM_TIMER: if (wparam == 1) { SwapBuffers(e::threedviewhdc); // где только копирование с буфера } return 0; разницы не заметил Возможно, потому что у меня нарисован только один цилиндр и разница наверное будет видна когда на сцене будет пару сотен фигур. Идею с таймером оставлю, она мне нравится, во-первых не надо заморочиваться что делает пользователь, (если бы было такое сообщение WM_ОКНО_ПЕРЕКРЫТО_ДРУГИМ_ОКНОМ то обработал бы его, а так как узнать что окно перекрыто, хуки ставить - закопаюсь...), во-вторых ситуация когда пользователь работает с одним приложением и временно переключается на другое - ни есть основной способ работы. Это так сказать временно - или музыку включил или калькулятором воспользовался и потом вернулся. Но за совет спасибо. |
Сообщ.
#9
,
|
|
|
1.Наверное заметнее=правильнее будет, если не просто пара сотен, а пара сотен тысяч!
2.Все перекрытия (освобождения открытых кусков областей) обработаются WM_PAINT'ом. Я давно хотел написать прожку, чтобы она в фоновом режиме поверх всех окон таскала (аки шарик пинг-понга) своё маленькое окошко (для отладки отрисовки/перерисовки других окон=приложений), но так руки и не дошли (да и чего-то ГОСТ'овского хотелось... ). |
Сообщ.
#10
,
|
|
|
Цитата Mr.Brooks @ Использование таймера для перерисовки позволяет отказаться от цикла while (картинка статическая fps-ы не нужны) и заметно уменьшить загрузку процессора. Тем более неправильный подход. Я бы даже сказал -- костыль. Потому что правильно это делается двойной буферизацией. То, что озвучил выше Славян. Только он не довёл идею до самого главного, отрисовку со вторичного кадрового буфера следует производить в обработчике WM_PAINT. |
Сообщ.
#11
,
|
|
|
Да, B.V., у меня как-то так и было:
void __fastcall WMMyPaint(Messages::TWMPaint &message) { if( !message.DC ) // HDC==0 ? { PAINTSTRUCT PS; // фикция какая-то HWND hwnd; ::BeginPaint( hwnd=Handle, &PS); ::EndPaint( hwnd, &PS); } message.Result = 0; // мы - самые быстрые } virtual void __fastcall Dispatch(void *message) // 2009-01-23 { if( ((PMessage)message)->Msg==WM_ERASEBKGND && traek.v ) WMEraseBkgnd( (Messages::TWMEraseBkgnd *)message ); else if( ((PMessage)message)->Msg==WM_PAINT ) { WMMyPaint( *((Messages::TWMPaint *)message) ); if( ... ) if( ghDC && ghRC ) wglSwapBuffers( ghDC ); }else TComponent::Dispatch( message ); } |
Сообщ.
#12
,
|
|
|
А почему нельзя просто использовать обсервер? Подписываешься на значение рендером, значение изменяется - картинка перерисовывается. А ещё лучше обсервером с троттлингом в несколько мс, таким образом ререндер будет происходить не чаще чем раз в X мс. Т.е. кумулятивные изменения не будут заставлять несколько раз перерисовывать всё.
Добавлено По этим приниципам живёт фронтенд. А некоторые либы просто делают дифф состояний и на основе этого строят виртуальное дерево перерисовки, понимая что и где надо перерисовать. |
Сообщ.
#13
,
|
|
|
Цитата А почему нельзя просто использовать обсервер Что это и как это сделать? Где можно посмотреть примеры? |
Сообщ.
#15
,
|
|
|
Так, с этим разобрался. А как получить имя процесса, которому принадлежит окно, если нам известен только дескриптор окна?
|