Сейчас на форуме: (+5 невидимых)

 eXeL@B —› Дневники и блоги —› ARCHANGEL's blog
. 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 . 9 . 10 . >>
Посл.ответ Сообщение


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 13 июля 2012 18:28
· Личное сообщение · #1

Добрый день, уважаемые форумчане. Ни для кого не секрет, что решил я с недавних пор пойти учиться программированию. Поэтому стали меня интересовать практические аспекты кодинга, иногда весьма далёкие от вопросов реверсинга. Поэтому чтоб не засорять форум, решил создать этот блог. Стоит сказать, что вопросы, которые планируется тут разбирать, не такие уж и бесполезные. Они часто могут возникать при написании тех же кейгенов или тулз для реверсинга, так что, надеюсь, каждый сможет найти здесь что-нибудь интересное. Как некоторые уже догадались, вопросы Common Controls, простым числам, и сегодняшний вопрос по OpenGL как раз из серии учебных. Теперь о самом вопросе.

На днях выполнял задание про отрисовку простых фигур: треугольника, квадрата и т.д. Решено было выполнять рисование средствами OpenGL. Литературы по этому делу много, поэтому я разобрался, что и как. Т.е. в литературе советовали использовать бибилиотеку glut.dll, которая сама не относится к стандартному OpenGL, но её применение, как я понял, упрощает использование OpenGL в своих проектах. Далее я решил создать базовый класс для отрисовки треугольника, а от него создать производные классы для отрисовки других геометрических фигур. Но на практике получилась вот такая сложность. Дело в том, что glut, по сути, инкапсулирует функции Windows и OpenGL, что упрощает операции с ними. Но от базовых вещей же никуда не деться. Т.е. если процедура обработки оконных сообщений (CALLBACK WindowProc) должна присутствовать, то в классе она должна быть статической. Так и здесь:
Code:
  1. glutDisplayFunc(Draw); //где Draw - колбэк, а значит не может быть простым методом класса


Но вот проблема - мне нужно передать внутрь Draw несколько параметров. Являясь статическим методом, Draw не имеет указателя this, а значит не видит обычных полей. Статические поля он видит, но при попытке в конструкторе присвоить значения этим полям появляется ошибка линковки. Понятное дело, что по-хорошему, можно обойтись совсем без классов, но это превратит код в кашу - большое количество глобальных переменных, почти одинаковые функции со схожим функционалом принесут путаницу раньше, чем будут отрисованы несколько фигур. Кто посоветует, как быть в такой ситуации и как решить проблему со статическими функциями-членами?

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 13 июля 2012 18:49 · Поправил: neomant
· Личное сообщение · #2

На самом деле проблемы никакой нет. Ошибка при линковке может быть потому, что статические члены в классе объявлены, но их экземпляры не созданы. То есть их нужно объявить в .h в теле класса и создать(можно сразу и проинициализировать) в .cpp Для отрисовки фигуры лучше создать базовый класс Shape c виртуальной функцией Draw. В производных классах фигур определять свой метод Draw. Профит - полиморфизм в действии.

-----
Следуй за белым кроликом


| Сообщение посчитали полезным: ARCHANGEL


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 13 июля 2012 20:18
· Личное сообщение · #3

neomant
Да, помогло. Теперь другой бок появился - вот никогда такого не было, а тут вылезло, и как же так получилось? В общем, есть у меня 4 radiobutton, но прикол в том, что можно сделать один из них checked при том, что другой тоже останется checked. Как я так умудрился-то? И как это убрать?

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 13 июля 2012 21:48
· Личное сообщение · #4

Не точно, на вскидку. Попробуй создать окошко со ститем BS_GROUPBOX и его уже в качестве родителя давать BS_RADIOBUTTON кнопкам при создании. Естественно сама рамка BS_GROUPBOX в свою очередь может крепиться к чему угодно.

-----
Следуй за белым кроликом





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 13 июля 2012 22:05
· Личное сообщение · #5

Исправил бок с radiobutton'ами. Похоже, что тут важна очерёдность создания. Т.е. если вначале создаётся GROUPBOX, потом RadioButton, потом опять GROUPBOX, и опять RadioButton, то ониотносятся к разным групбоксам, и, став checked, не влияют друг на друга, т.е. uncheck не происходит. Выходом было создание всех GROUPBOX, а потом - всех RadioButton.

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 16 июля 2012 22:39
· Личное сообщение · #6

Сейчас стоит задача построения лабиринта в в иде матрицы, в которой элемент равен нулю, если данный участок непроходим, и равен 1 если проходим. Нужно строить лабиринт случайным образом. Т.е. заранее известны только длина и ширина матрицы (всего лабиринта). Лабиринт, конечно, не должен быть слишком простым, т.е. это не должно выглядеть, как прямая линия к выходу, обрамлённая непроходимыми участками, ведь это, всё-таки, лабиринт. Но и не должен быть испещрён ходами, т.е. перемещаться по нему должно быть трудно, выражаясь яснее, человек должен в нём блуждать, и выйти из него должно быть непросто. Теперь, выражаясь языком математики, у нас должен быть связный неориентированный граф, не являющийся деревом. Как в таком случае определить оптимальное число ребёр в графе, чтоб добиться описанного выше эффекта труднопроходимости лабиринта? Ну, или есть какие-то эффективные общеизвестные методы построения лабиринтов? В гугле находил ссылки на алгоритмы, но опасаюсь, что это необоснованный самопал.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 17 июля 2012 01:36
· Личное сообщение · #7

ARCHANGEL
Тут приводится алгоритм построения лабиринта на основе эйлеровых графов Intuit
По поводу сложности решения поиска выхода, то все упирается в размер лабиринта и количество тупиков, в общем бери то что тебе удобнее использовать ибо супер алгоритма нет.

| Сообщение посчитали полезным: ARCHANGEL


Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 17 июля 2012 20:30
· Личное сообщение · #8

библиотека Clp помоему решает такие задачи




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 18 июля 2012 14:56
· Личное сообщение · #9

reversecode
Ну, тут не тот случай - тут надо самому додуматься.

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 340.0 (мудрец), 22thx
Активность: 0.120
Статус: Участник
THETA

Создано: 22 июля 2012 14:09
· Личное сообщение · #10

ARCHANGEL, для твоей задачи. Если еще актуально.

1) Есть конкретная реализация на C++: поиск по кратчайшему пути в лабиринте от пункта A в пункт B, сам же лабиринт условно задается в виде матрицы и сгенерирован рандомно, - --> Link <--

2) Классическая книга "Роберт Седжвик. Фундаментальные алгоритмы на C++". Там есть отдельный раздел по теории графов, с примерами на С++, можно найти почти любой алгоритм, и доработать под свои нужды.

3) Хороший учебник "Максим Динман. C++. Освой на примерах". Книга хоть и ориентирована на людей, которые только начинают изучение C++, однако очень интересны и нетривиальны примеры, демонстрируемые читателям: множество алгоритмов шифрования, и почти половина книги - алгоритмы, построенные на графах, с минимально необходимой для понимания теорией. Очень много исходного кода, с большим числом комментариев. Возможно, окажется полезной.

-----
Программист SkyNet


| Сообщение посчитали полезным: ARCHANGEL


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 24 июля 2012 22:50
· Личное сообщение · #11

FrenFolio
Ещё актуально. Правда, в гугле поиском нашлась книга Мозгового "Занимательное программирование", где всё вполне доступно изложено. Конечно, теория не идеальна, например, не рассказывается, почему адаптированный алгоритм Прима для построения минимального остова следует применять для построения лабиринта, и как, с математической точки зрения, так получается, что алгоритм Крускала подходит для этой цели лучше. Поиск пути тут можно выполнять методом волновой трассировки. Седжвика читаю потихоньку, но до графов пока не дошёл. За линк спасибо, кстати, по этому линку лабиринты получаются с коридорами!

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 30 июля 2012 21:57
· Личное сообщение · #12

Сейчас делаю программу "Электронные часы". Суть простая - нужно в стиле электронных часов отрисовать текущее время, при этом обновлять его каждую секунду. Циферки в фотошопе уже сделаны, в общем, и программа вся уже накатана, но есть одна (впрочем, весьма небольшая) проблемка... она НЕ РАБОТАЕТ! Идея состоит в том, чтоб в ответ на сообщение WM_PAINT получать клиентскую область окна и в ней черз BitBlt рисовать времечко. И время действительно рисуется - один раз. Но при WM_INITDIALOG создаётся поток, который шлёт в очередь сообщений заветное WM_PAINT, но картинка почему-то не перерисовывается, несмотря на то, что сообщение доходит до адресата, и, в общем-то, корректно обрабатывается. Что за нах? Или для решения такой задачи действовать надо как-то по-другому? Код в виде проекта студии прилагаю.

7acb_30.07.2012_EXELAB.rU.tgz - Forum WatchShow.rar

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 30 июля 2012 22:29
· Личное сообщение · #13

ARCHANGEL
Как то так:
Code:
  1.          case WM_PAINT:     
  2.                  PaintDev = BeginPaint(hwndDlg,&ps);
  3.                  LPSTR tempTime = GetTimeInStringFormat();
  4.                  ForwardTheWatch(PaintDev,GetModuleHandleA(NULL),hwndDlg,tempTime);
  5.                  delete[] tempTime;
  6.                  InvalidateRect(hwndDlg, NULL, NULL);
  7.                  EndPaint(hwndDlg,&ps);
  8.                  result = TRUE;
  9.                  break;


| Сообщение посчитали полезным: ARCHANGEL


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 30 июля 2012 22:51
· Личное сообщение · #14

F_a_u_s_t
Блин, а я был так близко. И ведь искал же по MSDN что-то подобное, правда, искал InvalidateRectangle, а полученный результат меня сбил с толку - думал, что не туда куда-то меня повело. В общем, добавил, заработало. Спасибо.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 30 июля 2012 22:55
· Личное сообщение · #15

ARCHANGEL
Да фигня.




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 30 июля 2012 23:08
· Личное сообщение · #16

Для отправки собщения WM_PAINT не нужно заводить поток, достаточно обычного таймера.
Чистый WIN32 - это брутально, но можно хотя бы CString или std::string попользовать чтобы не заморачиваться с выделением/возвращением памяти.
Класс используется не рационально, постоянно выполняются лишние действия по подгрузке картинок.
Не совсем красиво написано условие окончания цикла по выводу времени.

-----
Следуй за белым кроликом





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 31 июля 2012 00:04
· Личное сообщение · #17

neomant пишет:
Для отправки собщения WM_PAINT не нужно заводить поток, достаточно обычного таймера.

Вот с таймером я крутил всякие заманухи, и так, и эдак. Взял SetTimer, добавил обработчик WM_TIMER, но тут или я что-то не понимаю, или делать надо как-то не так, но если я буду внтри обработчика WM_TIMER юзать SendMessageA(...,WM_PAINT,...), то т.к. обработка SendMessageA синхронна, то оно так и будет висеть, ничего не отрисовывая. Хотя в МСДН написано, что напрямую слать окну WM_PAINT нельзя. Значит, видимо, есть способ какой-то.

Чистый WIN32 - это брутально, но можно хотя бы CString или std::string попользовать чтобы не заморачиваться с выделением/возвращением памяти.

Возможно.

Класс используется не рационально, постоянно выполняются лишние действия по подгрузке картинок.

Есть такое дело. Но т.к. не тормозит, то подумал - пусть будет так. Хоть по быстродействию и не оптимально, зато как-то гармонично.

Не совсем красиво написано условие окончания цикла по выводу времени.

А вот этого не понял. А как красиво надо?

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 31 июля 2012 00:20 · Поправил: neomant
· Личное сообщение · #18

ARCHANGEL пишет:
Хотя в МСДН написано, что напрямую слать окну WM_PAINT нельзя. Значит, видимо, есть способ какой-то.


UpdateWindow, RedrawWindow. Проблем с отсылкой сообщения SendMessge так же быть не должно. Можно ещё PostMessage.

ARCHANGEL пишет:
А вот этого не понял. А как красиво надо?


Code:
  1. for (= 0; i < _tcslen(TheTime); ++i)

И соответственно break для выхода из цикла тоже не нужен.

Ещё несколько замечаний. Код правильнее писать в cpp-файлах, в заголовках - прототипы функций, константы.
inline лучше делать ОЧЕНЬ маленькие функции. Конструктор и деструктор реализованы при описании класса - автоматом считаются инлайн.

-----
Следуй за белым кроликом




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 31 июля 2012 01:50
· Личное сообщение · #19

neomant пишет:
Конструктор и деструктор реализованы при описании класса - автоматом считаются инлайн.

inline или public (access control)? .
Рисовать лучше таки в другом потоке, а таймер это костыль, по поводу разбиения класса на *.h и *.cpp тоже спорно, зависит от потребностей и размера самого класса, если класс в 1,5 строки и в будущем не планируется расширять можно и в один всунуть, а есчо есть amalgamation header, например так SQLite идет.
Использование winapi, тут на вкус и цвет, хотя сам бы не стал извращаться с ним.




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 31 июля 2012 10:18
· Личное сообщение · #20

F_a_u_s_t пишет:
inline или public (access control)?

Нет, inline не контроль доступа. При генерации кода вместо вызова функции будет подставлено само её тело.

-----
Следуй за белым кроликом




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 31 июля 2012 12:34
· Личное сообщение · #21

neomant
Но тогда что бы автоматом считалось inline это должно быть в стандарте, что то там я этого не видел, да и gcc подсказывает что не всегда это так.




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 31 июля 2012 12:52
· Личное сообщение · #22

F_a_u_s_t пишет:
Но тогда что бы автоматом считалось inline это должно быть в стандарте


Разное. Спецификатор inline. Действительно компилятор не должен инлайнить функцию даже после объявления её таковой. Всего лишь предложение компилятору.
А вот в VC есть ещё и принудительное требование __forceinline.

-----
Следуй за белым кроликом




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 31 июля 2012 13:13
· Личное сообщение · #23

neomant
В стандарте подробнее расписано.

Code:
  1. 2 A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function . The inline
  2. specifier indicates to the implementation that inline substitution of the function body at the point of call
  3. is to be preferred to the usual function call mechanism. An implementation is not required to perform this
  4. inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules
  5. for inline functions defined by 7.1.2 shall still be respected.
  6. 3 A function defined within a class definition is an inline function. The inline specifier shall not appear on
  7. a block scope function declaration.
  8. 91
  9. If the inline specifier is used in a friend declaration, that declaration
  10. shall be a definition or the function shall have previously been declared inline.
  11. 4 An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly
  12. the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its
  13. definition appears in the translation unit. —end note ] If the definition of a function appears in a translation
  14. unit before its first declaration as inline, the program is ill-formed. If a function with external linkage is
  15. declared inline in one translation unit, it shall be declared inline in all translation units in which it appears;
  16. no diagnostic is required. An inline function with external linkage shall have the same address in all
  17. translation units. A static local variable in an extern inline function always refers to the same object.
  18. A string literal in the body of an extern inline function is the same object in different translation units.
  19. [ Note: A string literal appearing in a default argument is not in the body of an inline function merely
  20. because the expression is used in a function call from that inline function. —end note ] A type defined
  21. within the body of an extern inline function is the same type in every translation unit.
  22. 5 The virtual specifier shall be used only in the initial declaration of a non-static class member function;
  23. see 10.3.
  24. 6 The explicit specifier shall be used only in the declaration of a constructor or conversion function within
  25. its class definition; see 12.3.1 and 12.3.2.





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 01 августа 2012 15:04
· Личное сообщение · #24

Теперь новый трабл. Создаю окно, на клиентской области которой и будет отображаться долгожданный лабиринт. Вот код:
Code:
  1. HWND __stdcall CreatePlotArea(int X,int Y,HWND Parent,Maze* Mm)
  2. {
  3.          HWND result = NULL;
  4.          WNDCLASSEXA wnd = {0};
  5.          RECT desk;
  6.  
  7.          wnd.cbSize = sizeof(WNDCLASSEXA);
  8.          wnd.style = CS_HREDRAW | CS_VREDRAW;
  9.          wnd.hInstance = (HINSTANCE) GetModuleHandleA(NULL);
  10.          wnd.lpszClassName = "MAZE";
  11.          wnd.lpfnWndProc = &WindowProc;
  12.          wnd.hIconSm = wnd.hIcon = LoadIconA(NULL,(LPSTR) IDI_INFORMATION);
  13.          wnd.hCursor = LoadCursorA(NULL,(LPSTR) IDC_ARROW);
  14.          wnd.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  15.          if (RegisterClassExA(&wnd))
  16.          {
  17.                  GetWindowRect(GetDesktopWindow(),&desk); //располагаем окно игры по центру экрана
  18.                  result = CreateWindowExA(NULL,"MAZE","MAZE",WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
  19.                         desk.left + (desk.right-desk.left-Y)/2,desk.top + (desk.bottom-desk.top-X)/2,Y,X,
  20.                         Parent,NULL,(HINSTANCE) GetModuleHandleA(NULL),Mm);
  21.          }
  22.          return result;
  23. }


Но проблема в том, что как только я закрываю это окно - всё приложение завершает работу. На самом же деле это окно создаётся после нажатия кнопки на главном диалоговом окне. Т.е. программа-часы имеет кнопку "Играть", я давлю на эту кнопку, а в ответ должен появиться лабиринт. И он появляется, но стоит мне закрыть окно лабиринта, как программа тут же завершается. Что это? Может, какие-то стили окна отвечают за это? В мсдн ничего не нашёл, знать бы, где искать.

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 01 августа 2012 15:38
· Личное сообщение · #25

Не увидел WindowProc. Могу предположить, что используется общаяя с часами, которая и посылает PostQuitMessage потоку.

-----
Следуй за белым кроликом


| Сообщение посчитали полезным: ARCHANGEL


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 01 августа 2012 15:47
· Личное сообщение · #26

neomant
Не общая, но получается, что PostQuitMessage действительно посылается тому же потоку, который и создавал диалоговое окно с часами. Спасибо, что я делал бы без neomant`a и F_a_u_s_t`a? Будем исправлять...

Да, кстати, в часах вместо SendMessageA поставил UpdateWindow. Работает, ещё и баг один исправился - раньше стоило переключиться на другое окно, а потом обратно на "часы" - и кнопки пропадали, пока не переместишь окно. А теперь без всяких манипуляций появляются.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 01 августа 2012 17:17
· Личное сообщение · #27

ARCHANGEL
Хз из за чего, причин много может быть, если что выкладывай прожект.
Кстати у тебя получение времени страшное какое то, не проще так:
Code:
  1.  
  2. char buff[MAX_PATH];
  3. SYSTEMTIME* systime;
  4. GetSystemTime(systime);
  5. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT, systime, "hh':'mm':'ss tt", buff, sizeof(buff));

Писал в браузере, но не думаю что бы в 5-и строчках накосячил.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 01 августа 2012 17:44
· Личное сообщение · #28

F_a_u_s_t

А, может, так:

Code:
  1. SYSTEMTIME systime;
  2. GetSystemTime(&systime);


?

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 01 августа 2012 18:26 · Поправил: F_a_u_s_t
· Личное сообщение · #29

[Тут было стыдно]

Что то забегался и не заметил что: GetSystemTime а не GetLocalTime и есчо и думаю чтто это время у меня левое.




Ранг: 164.6 (ветеран), 65thx
Активность: 0.120
Статус: Участник
Волшебник

Создано: 01 августа 2012 19:18
· Личное сообщение · #30

ARCHANGEL пишет:
А, может, так:


Как раз только так и нужно, так как функе нужно передать указатель на структуру, а не непроинициализированный указатель. Но лучше пользоваться уже готовыми библиотечными
обёртками:
Code:
  1. CTime time = CTime::GetCurrentTime();
  2. CString s = time.Format( "%A, %B %d, %Y" );


-----
Следуй за белым кроликом



. 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 . 9 . 10 . >>
 eXeL@B —› Дневники и блоги —› ARCHANGEL's blog
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати