В.: «что делать если грузятся два экземпляра одного прибора и дерутся между собой, вызывая ошибки в работе панели? И что делать если логика прибора не стартует, пока прибор не будет показан на экране»
О.: Отвязать логику (работы прибора/системы) от представления (от того, что в симе называется gauge). Как это сделать? Сначала экскурс в основы.
Многие начинающие прибористы воспроизводят шаблон, предложенный разработчиками сима в SDK. т.е.
GAUGE_TABLE_BEGIN() GAUGE_TABLE_ENTRY(&gaugehdr_attitude) GAUGE_TABLE_ENTRY(&gaugehdr_control_surfaces) GAUGE_TABLE_ENTRY(&gaugehdr_fuel) GAUGE_TABLE_ENTRY(&gaugehdr_fuel_selector) GAUGE_TABLE_ENTRY(&gaugehdr_temperature) GAUGE_TABLE_ENTRY(&gaugehdr_whiskey) GAUGE_TABLE_ENTRY(&gaugehdr_flightmap) GAUGE_TABLE_END()
и не задумываются, что стоит за этими мудрыми словами, до тех пор пока… пока не начинают делать что-то более сложное, и не сталкиваются с проблемами наподобие вышеописанной. Собственно, данный шаблон предназначен для сокрытия программной машинерии, которая обеспечивает загрузку и отображение приборов симом. Пытаясь остатся в пределах использования этого шаблона, начинаются навороты со статическими переменными, отслеживанием многократной загрузки и тд и тп, что не способствует устойчивости модели вообще. Решение же лежит в другом, и решение это более изящно — а именно — развязывание непосредственно представления (gauges) от логики модели той или иной системы ВС. Но для этого — необходимо прекратить использовать вышеприведеннный шаблон, и начать использовать ту самую внутреннюю машинерию приборного модуля. Так что же скрывает вышеприведенный шаблон? А вот что
//GAUGE_TABLE_BEGIN()
extern GAUGEHDR gauge_header;
void FSAPI module_init(void){} //вот оно!!!
void FSAPI module_deinit(void){} //и это!!!!
BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
GAUGESIMPORT ImportTable =
{
{ 0x0000000F, (PPANELS)NULL },
{ 0x00000000, NULL }
};
/* This is the module's export table. */
GAUGESLINKAGE Linkage =
{
0x00000013,
module_init,
module_deinit,
0,
0,
FS9LINK_VERSION, {
//GAUGE_TABLE_ENTRY(&gaugehdr_attitude)
(&gaugehdr_attitude),
//GAUGE_TABLE_END()
0
}};
Итак, что мы тут видим? А видим, что шаблон скрывает определение трех функций и двух структур. Первую структуру (ImportTable) оставляем без изменений, она обеспечивает доступ к функциям сима наподобие lookup_var(). Вторая структура содержит заголовок приборного модуля, в котором указывается магическое число 0x13 (19 в десятичной системе), обозначающую для сима то, что это приборный модуль, два адреса функций, определенных ранее (module_init, module_deinit), два магических числа, нам не интересных, номер версии сима, для которой предназначен данный приборный модуль, ну а дальше идет список адресов заголовков описаний непосредственно представлений приборов (gauges), завершающееся еще одним магическим числом — 0, поскольку именно его сим ожидает увидить при загрузке списка представлений из приборного модуля, в конце означенного списка представлений.
Более детально нас интересуют именно определенные шаблоном функции. DllMain оставим в стороне, она в приборных модулях дополняется своим кодом в очень редких случаях. Более подробно интересуют две другие функции — module_init и module_deinit. Что они делают? В шаблоне по умолчанию они не делают ничего! Но! функция module_init вызывается один раз при загрузке приборного модуля, и module_deinit вызывается один раз при выгрузке модуля симом. При этом совершенно не важно, был ли отображен прибор на экране, или не был. Т.е. эти две функции выполняются всегда. Вот сюда-то нам и надо поместить инициализацию логики наших систем, загрузку всех требуемых ресурсов, а так же запуск цикла расчетов обновлений логики (в тч и асинхронное, если ваши знания позволяют это реализовать). В представлении же мы оставляем только отображение конкретных значений и прием управляющих воздействий от пользователя (мышеклики). При этом одинаковых представлений может быть любое множество, в каких угодно местах (на 2Д панели, в ВК или на внешнем компьютере). Конкретные способы реализации самой модели я сейчас рассматривать не буду.
Итак, что же надо сделать? конкретно — прекратить использовать шаблон, предложенный SDK, и использовать ту внутреннюю машинерию, которую скрывает этот шаблон. Выполнив это, вы способны внедрить в функции, вызываемые симом при загрузке приборного модуля (не отдельного прибора, события откладываемого до непосредственного отображения прибора, а всего модуля!) и при выгрузке, необходимый вам код инициализации и запуска логики, независимой от представления.
Сообщение отредактировано seric76: 13 July 2012 — 05:17
В исходниках оставлены за кадром некоторые хитрушки для стимуляции головного мозга начинающих писателей
Прикрепленные файлы
gau.ZIP 11.27К
375 Количество загрузок:
Project.ZIP 55.74К
390 Количество загрузок:
А чем рисование через GDI+ решит проблему с рефрешем текстур в вк? Собственно главная проблема в виртуальном кокпите — это несколько более тормознутое обновление текстур — на которых собственно приборы то и рисуются — по сравнению с обновлением подложки 2д панели (ну поставили мы флаг SET_OFF_SCREEN — ну узнал сим что хорошо бы перечитать подложку — ну и когда он по вашему этот сделает? Незамедлительно? Да не факт…). И лечится это вообще-то только одним путем — уменьшением размерности текстур в вк. Чем меньше обновлять — тем быстрее сим это сделает (речь ведем о 2004, фсх вроде в этом плане помягче работает). Ну или рисовать объекты как 3д — но чем больше полигонов в кадре — тем тормознутее собственно работа симулятора.
Ну знаете ли — и из пушки по воробьям (сиречь gdi+ для стрелочников пользовать) — это тоже не вариант 🙂 Ибо рисование через гди — изначально вещь затратная.
Кстати помнится я с подобным сталкивался, уж не помню на каком проекте — так вот, MAKE_NEEDLE имеет какие-то проблемы, а вот спрайт работал плавненько.
А можно задать маленький и глупый вопрос?
Если сделать модель под одну версию FS без использования шаблонов SDK, не приведет ли это к тому, что, при переходе на следующие версии FS придется не просто перекомпилировать исходники с использованием gauges.h из нового SDK, а переписывать куски кода в каждом приборе?
Вряд ли сильно много. Денис просто раскрыл макросы, описывающие «голову» прибора. Если уж прям так напрягает — условную компиляцию никто не отменял.
Спасибо.
У меня два вопроса.
1. В любой гау баблиотеке должен быть хотя бы один прибор с именем, которое, в свою очередь, нужно прописать в Panel.cfg, для того, чтобы сим мог подцепить библиотеку. Сам же прибор требует наличия макроса GAUGE_HEADER_FS700, который в свою очередь, требует обязательного списка элементов. Вот и приходится в прибор логики добавлять такой список, хотя бы с одним элементом, к примеру, MAKE_STATIC, содержащий в качестве параметров нули. В принципе, ничего особо страшного в этом нет, но может есть способ обойтись без таких заглушек?
2. Необходимо написать программный модуль обработки ввода пользователя. Ввод пользователя осуществляется через клавиатуру, джойстик, мышь. С джойстиком понятно — пишем с использованием DirectInput, отключаем в симе джойстик и получаем нечто похожее на ПТ. Мышь. Мышиные события и так обрабатываются в пользовательском коде. Остается клавиатура. И тут мне известны два возможных варианта: DirectInput и SetWindowsHookEx. Собственно клавиатурный хук пока вполне справляется с задачей, то есть клавиатурное событие прехватывается перед симулятором, и в коде определяется что с ним делать: а) обработать самостоятельно и «погасить»; б) обработать самостоятельно и передать симу; в) просто передать симу без обработки.
Собственно вопрос: нужно ли смотреть в сторону DirectInput (с которым я никогда не работал применительно к клавиатуре)?
Можно. Способ для FS9 называется «модуль». Собственно гау есть частный случай обычного модуля, несколько более специфицированный. Для FSX нужно работать через SimConnect.
Как сделать модуль FS9? да точно так же как и gau. С одним отличием — в Linkage первый параметр («магическое число 0x00000013) заменяется либо на 0, либо на любое не занятое симовскими модулями (ага, они имеют такую же структуру, те же ImportTable и Linkage символы) число. Впрочем, отличное от нуля число необходимо только тогда, когда предполагается загрузка вашего модуля другими компонентами сима (ну например — вашими приборами) посредством штатных механизмов ФС. Ну и дальше в Linkage, где у вас идут списки приборов, будет стоять простой сакраментальный 0, обозначающий пустой список функций. Такой модуль надобно будет положить в папочку modules, сим при запуске его загрузит. Что с этим делать дальше и как взаимодействовать с симом? нууу, это большой и сложный вопрос, который уходит в сторону «грязных» хаков и использования штатных, но немножко недокументированных функций
Можно и не смотреть, достаточно клавиатурного хука. Дальше — смотрите сами. там опять начинается грязный хакинг и пошлая недокументарщина. В плане FSX все куда проще — возможность маппить свои события на клавиатуру и перехватывать штатные, с «гашением» любых симовских событий — заложена в SimConnect по дефолту.
можно я добавлю? такие модули будут висеть постоянно в памяти, в отличии от гауги, которая грузится только при загрузки крафта и выгружается при его выгрузки (ну например смене самолёта, который данную гаугу не использует). я не знаю, важно это знать или нет.
С помощью тех самых недокументированных функций можно реализовать и модуль с загрузкой по запросу. В FS9 ессесно. в FSX SimConnect нивелирует все различия.
Ребята, кто подскажет в чем может быть проблема, если после компиляции стандартных файлов из SDK (папка /sample), то файл .gau не создается вообще…?
Компилятор не ругается только с параметром /I. (nmake MVC++2008 EE).
а файл .dll есть? на что ругается без /I?
В том то и проблема, что не создается никаких папок и файлов вообще, а компилер ошибок не выдает.
Без /I пишет «fatal error U1077».
А с указанным параметром «link…» и т.д. — т. е. вроде все Ок.
??? Не понятно.
Прикрепленные изображения
Я прописал нахождение cl и rc …
можно make файл в студию.
и ещё один вопрос — а почему собсно из консоли компиляем? чем живая студия плоха?
и ещё, если работаешь из консоли, vcvars32 запускал?
Сообщение отредактировано icebear: 10 March 2009 — 14:00
# Copyright © 2000 Microsoft Corporation. All rights reserved.
INCDIR = ..inc
DESTDIR = ..inc
INCS = -I$(INCDIR)
LIBS = user32.lib gdi32.lib kernel32.lib
!IFDEF DEBUG
C_FLAGS = /Z7
L_FLAGS = /DEBUG
!ELSE
C_FLAGS =
L_FLAGS =
!ENDIF
goal: SDK.gau
SDK.obj: $(INCDIR)gauges.h
SDK.c
SDK.h
SDK.Attitude.c
SDK.Control_Surfaces.c
SDK.Fuel.c
SDK.Fuel_Selector.c
SDK.Temperature.c
SDK.Wiskey.c
SDK.FlightMap.c
cl $(C_FLAGS) -c $(INCS) SDK.c
SDK.res: SDK.rc
SDK.h
resSDK.Attitude.bg.BMP
resSDK.Attitude.card1.BMP
resSDK.Attitude.mask1.BMP
resSDK.Attitude.card2.BMP
resSDK.Attitude.mask2.BMP
resSDK.Control_Surfaces.bg.bmp
resSDK.Control_Surfaces.Ailerons.bmp
resSDK.Control_Surfaces.Elevator.bmp
resSDK.Control_Surfaces.Rudder.bmp
resSDK.Control_Surfaces.Trim.bmp
resSDK.Fuel.bg.bmp
resSDK.Fuel.needle.bmp
resSDK.Fuel_Selector.Off.BMP
resSDK.Fuel_Selector.Left.BMP
resSDK.Fuel_Selector.Right.BMP
resSDK.Fuel_Selector.Both.BMP
resSDK.Temperature.bg.bmp
resSDK.Temperature.F.bmp
resSDK.Temperature.C.bmp
resSDK.Whiskey.bg.BMP
resSDK.Whiskey.card.BMP
resSDK.Whiskey.mask.BMP
resSDK.FlightMap.BMP
rc -r $(INCS) SDK.rc
SDK.gau: SDK.obj
SDK.res
link $(L_FLAGS) /dll /out:$(DESTDIR)SDK.gau SDK.obj SDK.res $(LIBS)
clean:
del $(DESTDIR)*.exp
del $(DESTDIR)*.gau
del $(DESTDIR)*.lib
del *.obj
del *.res
///////////////////////////////////////////////
В студии я не компилирую потому, что не компилировал никогда при помощи <makefile> — файлов (работал в СиБилдере и Делфи, и всегда использовал встроенный компилер). К тому же руководствовался только SDK.
vcvars32 запускал — все по-прежнему..
goal:SDK.gau
после вызовов cl и перед вызовом link. хотя не думаю, что это что-то даст. cl не переваривает какой-то файл. попробуй сначала от руки компильнуть, без линковки и посмотри, что скажет cl
дык если из студии компилируешь — makefile вообще не нужен, она же сама всё делает. или я что-то не понял?
Написал прибор для кнопки нажигационных огней. Огни переключаются а битмап самой кнопки не появляется и не переключается. Битмап заднего фона виден.
У кого есть идеи?
Код: SDK.h
Код SDK.c
... #include "gauges.h" #include "SDK.h" UINT32 nav_light = 0; ///////////////////////////////////////////////////////////////////////////// // Attitude ///////////////////////////////////////////////////////////////////////////// #define GAUGE_NAME "gear_lock_key" #define GAUGEHDR_VAR_NAME gaugehdr_gear_lock_key #define GAUGE_W 100 // Set up gauge header char gear_lock_key_gauge_name[] = GAUGE_NAME; extern PELEMENT_HEADER gear_lock_key_list; extern MOUSERECT gear_lock_key_mouse_rect[]; GAUGE_HEADER_FS700(GAUGE_W, gear_lock_key_gauge_name, &gear_lock_key_list, gear_lock_key_mouse_rect, 0, 0, 0, 0); ///////////////////////////////////////////////////////////////////////////// FLOAT64 FSAPI gear_lock_key_icon_cb( PELEMENT_ICON pelement ) { return nav_light; } MAKE_ICON ( gear_lock_key_icon, BMP_KEY_DOWN, NULL, NULL, IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY, 0, 0,0, MODULE_VAR_NONE, gear_lock_key_icon_cb, ICON_SWITCH_TYPE_SET_CUR_ICON, 2, 0, 0 ) PELEMENT_HEADER gear_lock_key_icon_list[] = { &gear_lock_key_icon.header, NULL }; ///////////////////////////////////////////////////////////////////////////// MAKE_STATIC ( gear_lock_key_background, BMP_BG, NULL, NULL, IMAGE_USE_TRANSPARENCY, 0, 0,0 ) PELEMENT_HEADER gear_lock_key_list= &gear_lock_key_background.header; ///////////////////////////////////////////////////////////////////////////// MODULE_VAR gear_lock_key_mouse_var = {NAV_LIGHTS}; BOOL FSAPI gear_lock_key_mouse_cb( PPIXPOINT relative_point, FLAGS32 mouse_flags ) { lookup_var( &gear_lock_key_mouse_var); switch (nav_light) { case 0: trigger_key_event( KEY_TOGGLE_NAV_LIGHTS, 0 ); nav_light = 1; break; case 1: trigger_key_event( KEY_TOGGLE_NAV_LIGHTS, 0 ); nav_light = 0; break; //default: // trigger_key_event( KEY_TOGGLE_NAV_LIGHTS, 0 ); // break; } return TRUE; } MOUSE_BEGIN( gear_lock_key_mouse_rect, HELP_NONE, 0, 0 ) MOUSE_CHILD_FUNCT( 100,100,60,60, CURSOR_HAND, MOUSE_LEFTSINGLE, gear_lock_key_mouse_cb ) MOUSE_END ///////////////////////////////////////////////////////////////////////////// #undef GAUGE_NAME #undef GAUGEHDR_VAR_NAME #undef GAUGE_W GAUGE_TABLE_BEGIN() GAUGE_TABLE_ENTRY(&gaugehdr_gear_lock_key) GAUGE_TABLE_END()Сообщение отредактировано anton_il: 11 April 2009 — 16:02
третий параметр NULLевой. Попробуй указать &gear_lock_key_icon_list
ИМХо подобные вопросы лучше задавать в отдельной теме(-ах) — тут всё-таки вроде как Tips & Hints
Сообщение отредактировано Lavrik: 11 April 2009 — 20:21
Спасибо помогло
там еще симпотный баг был,
Ну и за одно открою топик для вопросов по строительству приборов на С
Сообщение отредактировано Drum27: 10 March 2010 — 01:10
В общем, алгоритм
1. заводится L: переменная (просто выбирается для нее имя, сим сам создаст ее при первом упоминании где угодно)
2. в modeldef.xml пишется описание новой кастомной анимации (за описаниями смотри тот же файл) где и прописываются алгоритмы и зависимости
3. объект моделируется в 3Д и ему назначается в качестве анимации тэг этой новой вашей кастомки
4. если надо — пишется поддерживающая часть (на XML или C, не суть) на стороне приборки
5. все это собирается, проверяется, если не работает — возвращаемся на п.2 и делаем итерацию снова
Собсно,подскажите, на что ругается компилятор VS++2008. С расширением файла чёт не то, или настройки?
Сообщение отредактировано Virpil: 02 June 2010 — 09:10