Метка «c++» - 3

Понадобилось мне, чтобы каждый класс мог стать субъектом (subject) и оповещать своих наблюдателей (observers) любыми типами данных.

Чтобы вечно не использовать наследование для разных типов данных, я написал универсальный шаблонный класс.

Для начала определим интерфейсы наблюдателя и субъекта.

ASObserver.h

template <class T>

class ASObserver{

public:
    virtual     ~ASObserver(){}
    virtual void onNotify(T *data) = 0;

};

Читать полностью »

В статье рассказывается, как осуществить поддержку мультиоконного режима в операционной системе семейства Windows.

Перед тем, как приступить к работе с множеством мониторов необходимо их перечислить. Для этого можно воспользоваться функцией EnumDisplayMonitors. Эта функция позволит получить описатели ( HMONITOR ) всех мониторов из, которых можно достать необходимую информацию.

BOOL EnumDisplayMonitors(
__in  HDC hdc,
__in  LPCRECT lprcClip,
__in  MONITORENUMPROC lpfnEnum,
__in  LPARAM dwData);

Для перечисления мониторов в системе все параметры, кроме функции обратного вызова, достаточно установить в NULL. Для удобства можно сложить информацию о мониторах в вектор, который будет заполняться по мере вызова CALLBACK- функции.

BOOL CALLBACK EnumMonitorsProc(HMONITOR hMonitor, HDC, LPRECT rect, LPARAM lParam)
{
m_vectAllMonitors.push_back( hMonitor );
return true;
}

Читать полностью »

Данная заметка — попытка вставить свои 5 копеек на тему, затронутую в статье пользователя KumoKairo.

Не далее как год назад я столкнулся с подобной проблемой — необходимо было рассылать события клиентам из WCF-службы, причем один подписчик события не должен страдать от того, что другой подписчик события в момент генерации этого события отвалился.

Как и автор упомянутой заметки, я пошел смотреть, что же такого умного написано на эту тему, и набрел вот на эту публикацию. Пришел к выводу, что строго говоря, задача не решается, то есть мы никак не сможем избежать случайного вызова обработчика событий от того подписчика, который отписался в «неудобный» момент. Но есть неплохой способ избежать последствий такой ситуации.
Читать полностью »

Здравствуйте!

Статья предназначена для тех, кто ведет разработку на Torque3D и умеет компилировать движок в VisualStudio, а не только для тех, кто пользуется WorldEditor и пишет/дописывает torqueScript *.cs скрипты.

В Torque3D 3.5 есть небольшой баг с нормалями на кромках террейна (Terrain). Именно он мешает создавать множество террейнов «без швов» (и не только он). Если запустить какую нибудь демку, например, Empty, открыть в ней WorldEditor, создать 2 террейна, подогнать их друг к другу и попробовать «нарисовать кисточкой высоту» в области «склейки» этих террейнов, то мы увидим неприятный баг. Похожий баг можно увидеть, если мы создадим всего лишь 1 террейн и попробуем отредактировать высоту в областях кромок этого террейна.

Что есть террейн?

Террейн — это регулярная сетка ячеек с высотами ( имеющая размеры 256, 512, 1024 — кратная степени двойки), которая легко преобразуется в поверхность (mesh).
У меша есть не только полигоны и вершины, но также и нормали к вершинам, которые как раз дают нужную освещаемость конкретной вершины.

Дело в том, что в движке Torque3D нормаль в точке x,y рассчитывается исходя из разниц высот:
normal( height(x+1, y) — height (x — 1, y), height(x, y+1) — height(x, y-1), 'какая то постоянная высота' ),
где float height( int x, int y ) — функция взятия высоты по целочисленным координатам регулярной сетки ячеек в террейне.

Да, в Torque3D координата по Z — это высота.

Возникает вопрос: а если x+1 или x-1 или y+1 или y-1 выходят за границу террейна?
Тогда берется точка на противоположенной стороне террейна и возникает артефакт в виде необоснованной повышенной/пониженной освещенности такой «пограничной» вершины. Т.е. если, например, x=0, то x-1 = -1, который превращается в size — 1 (размер террейна минус единичка, например 256 — 1 = 255).

Почему так превращается? Потому что вот функция, возвращающая высоту в точке x, y:

inline U16 TerrainFile::getHeight( U32 x, U32 y ) const
{
x %= mSize;
y %= mSize;
return mHeightMap[ x + ( y * mSize ) ];
}

где mSize — это размер террейна, например 256, а оператор % берет остаток от деления. Тип U32 — это беззнаковый тип, а вызывается эта функция из функции TerrainBlock::getSmoothNormal(...) вот здесь:

F32 h1 = fixedToFloat( mFile->getHeight( x+1, y ) );
F32 h2 = fixedToFloat( mFile->getHeight( x, y+1 ) );
F32 h3 = fixedToFloat( mFile->getHeight( x-1, y ) );
F32 h4 = fixedToFloat( mFile->getHeight( x, y-1 ) );

а x и y они типа S32, что означает знаковый тип. Если приходит -1 на вход этой функции, то значение автоматически преобразуется к беззнаковому, причем к предельному (максимальному) для 32 битных чисел. Это будет 2^32 — 1 = 4 294 967 295 и остаток от деления на 256 будет 255.
4 294 967 295 % 256 = 255.

Я подумал, что нам такого не надо и решил немного подкорректировать исходный код Torque, попутно запилив некий функционал.

Функционал заключается в следующем:
если x-1 < 0 или x+1 > mSize — 1 или y-1<0 или y+1> mSize — 1, то значение высоты в данной точке брать не с текущего террейна, а с тех террейнов, которые мы указали соответствующими соседями.

Для этого поменялся инспектор в редакторе мира для террейна, теперь там есть вкладка «Attached terrains» и поля «ForwardId», «BackwardId», «LeftId» и «RightId», куда пользователь ручками вбивает id'шники соседних террейнов (которые он сочтет нужными, хаха).

Для того, чтобы поменять инспектор, был вставлен код в функцию void TerrainBlock::initPersistFields():

addGroup( "Media" );

addProtectedField( "terrainFile", TypeStringFilename, Offset( mTerrFileName, TerrainBlock ), &TerrainBlock::_setTerrainFile, &defaultProtectedGetFn,"The source terrain data file." );

endGroup( "Media" );

// Вкладка в инспекторе WorldEditor'а для "соседей" террейна
addGroup( "Attached terrains" );
addField( "ForwardId", TypeS32, Offset( m_Forward, TerrainBlock ), "Id of forward attached terrain" );
addField( "BackwardId", TypeS32, Offset( m_Backward, TerrainBlock ), "Id of backward attached terrain" );
addField( "LeftId", TypeS32, Offset( m_Left, TerrainBlock ), "Id of left attached terrain" );
addField( "RightId", TypeS32, Offset( m_Right, TerrainBlock ), "Id of right attached terrain" );
endGroup( "Attached terrains" );
// end of Вкладка

addGroup( "Misc" );
...

В прототип класса class TerrainBlock : public SceneObject были вставлены поля:
S32 m_Forward;
S32 m_Backward;
S32 m_Left;
S32 m_Right;

То есть у меня выглядит вот так:
...
///
FileName mTerrFileName;

/// Attached terrains Соседи террейна
S32 m_Forward;
S32 m_Backward;
S32 m_Left;
S32 m_Right;

/// The maximum detail distance found in the material list.
F32 mMaxDet

Для того, чтобы эти поля сериализовались, надо вставить код в функции TerrainBlock::packUpdate и TerrainBlock::unpackUpdate.

В TerrainBlock::packUpdate вставляется:

// для соседей террейна
if( stream->writeFlag( mask & NextFreeMask ) )
{
stream->write( m_Forward );
stream->write( m_Backward );
stream->write( m_Left );
stream->write( m_Right );
}
//
После строчек:
if ( stream->writeFlag( mask & FileMask ) )
{
stream->write( mTerrFileName );
stream->write( mCRC );
}

В TerrainBlock::unpackUpdate нужно вставить:

// Соседи террейна
if ( stream->readFlag() )
{
stream->read( &m_Forward );
stream->read( &m_Backward );
stream->read( &m_Left );
stream->read( &m_Right );
}
// end of Соседи террейна

После строчек:

if ( stream->readFlag() ) // FileMask
{
FileName terrFile;
stream->read( &terrFile );
stream->read( &mCRC );

if ( isProperlyAdded() )
setFile( terrFile );
else
mTerrFileName = terrFile;
}

Внимание! Код в этих двух функциях должен быть в определенном порядке, а не абы где. Именно там, где я указал, идет работа со stream'ом (наподобии STLвского стрима).

Теперь дошла очередь и до самой функции TerrainBlock::getSmoothNormal(...).

Изменения в terrData.cpp.

Сначала перед самой функцией TerrainBlock::getSmoothNormal(...) надо объявить:

namespace Sim
{
// Defined in simManager.cpp
extern SimIdDictionary *gIdDictionary;
}

Это объявит неймспейс локально прямо в этом файле реализации и продекларирует, что есть такая переменная SimIdDictionary *gIdDictionary.
Прошу заметить, это не создание новой глобальной переменной Sim::gIdDictionary, а лишь указание компилятору (впоследствии линковщику), что такая переменная уже есть в какой то другой единице трансляции — в другом *.cpp файле (а следовательно — в другом *.obj файле, после того как компилятор скушает *.cpp)

По этому указателю расположено глобальное хранилище всех Id для Sim объектов со своим интерфейсом (все объекты видимые в редакторе мира игры — террейны, мешы, солнце, плейны, точки респауна, инфо о левеле, и т.д. — являются потомками SimObject и имеют свой SimId).

В функции TerrainBlock::getSmoothNormal(...) после строчек

const TerrainSquare *sq = mFile->findSquare( 0, x, y );
if ( skipEmpty && sq->flags & TerrainSquare::Empty )
return false;

Вставляю следующий код:

Resource File1, File2, File3, File4;
File1 = File2 = File3 = File4 = mFile;

S32 x1 = x + 1;
S32 x2 = x — 1;
S32 y1 = y + 1;
S32 y2 = y — 1;

if( x1 > mFile->mSize — 1 )
{
x1 = mFile->mSize — 1;
TerrainBlock *rBlk = dynamic_cast<TerrainBlock*>( Sim::gIdDictionary->find( m_Right ) );
if( rBlk )
{
x1 = 1;
File1 = rBlk->mFile;
}
}

if( y1 > mFile->mSize — 1 )
{
y1 = mFile->mSize — 1;
TerrainBlock *fBlk = dynamic_cast<TerrainBlock*>( Sim::gIdDictionary->find( m_Forward ) );
if( fBlk )
{
y1 = 1;
File2 = fBlk->mFile;
}
}

if( x2 < 0 )
{
x2 = 0;
TerrainBlock *lBlk = dynamic_cast<TerrainBlock*>( Sim::gIdDictionary->find( m_Left ) );
if( lBlk )
{
x2 = lBlk->mFile->mSize — 2;
File3 = lBlk->mFile;
}
}

if( y2 < 0 )
{
y2 = 0;
TerrainBlock *bBlk = dynamic_cast<TerrainBlock*>( Sim::gIdDictionary->find( m_Backward ) );
if( bBlk )
{
y2 = bBlk->mFile->mSize - 2;
File4 = bBlk->mFile;
}
}

А строчки:

F32 h1 = fixedToFloat( mFile->getHeight( x+1, y ) );
F32 h2 = fixedToFloat( mFile->getHeight( x, y+1 ) );
F32 h3 = fixedToFloat( mFile->getHeight( x-1, y ) );
F32 h4 = fixedToFloat( mFile->getHeight( x, y-1 ) );

Заменить строчками:

F32 h1 = fixedToFloat( File1->getHeight( x1, y ) );
F32 h2 = fixedToFloat( File2->getHeight( x, y1 ) );
F32 h3 = fixedToFloat( File3->getHeight( x2, y ) );
F32 h4 = fixedToFloat( File4->getHeight( x, y2 ) );

Вроде бы все! Перекомпилировать — и ПРОФИТ! Ура!

Кстати, можно оптимизировать по скорости, то есть указатель на соседний террейн не искать в функции TerrainBlock::getSmoothNormal(...), как здесь: например:

TerrainBlock *rBlk = dynamic_cast<TerrainBlock*>( Sim::gIdDictionary->find( m_Right ) );

Ибо функция сглаживания нормали вызывается очень много раз( mSize*mSize раз ) для каждой вершины террейна, если террейн поднимается/опускается/сглаживается.

Тогда нужно создать 4 соответствующих указателя как поля класса и, скорее всего, инициализировать их там, где происходит «сериализация» (скорее всего ф-ции TerrainBlock::packUpdate или TerrainBlock::unpackUpdate).

Если бы была возможность вставить сюда измененные файлы исходников — с удовольствием вставил бы!

ТоркEnginesourceterrainterrData.cpp
и
ТоркEnginesourceterrainterrData.h

Для того, чтобы увидеть результат — заменить файл, перекомпилировать, запустить, создать до фига террейнов с монотонной текстурой, назначить соответствующих соседей в инспекторе, сохранить сцену и можно либо перезапустить, либо подредактировать высоты террейнов для запуска процедуры пересчета его нормалей.

Пока фиксит только нормали. Для сглаживания текстур — отдельная история.

Кстати, если соседей не назначить, то нормали будут пересчитываться все равно более адекватно — высоты с противоположенных сторон браться не будут — не будет ужасных непонятных артефактов, будет браться высота текущей точки, для которой и рассчитывается нормаль.

Выглядеть будет офигенчиком как здесь, использована монотонная текстура.
imageЧитать полностью »

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

Очередной CI светофор. На этот раз attiny2313 и Node.js

Под катом светофор из цветомузыки и пластиковых бутылок, USB модуль управления светофором на attiny2313 за доллар, а так же софт для опроса Jenkins и управления USB модулем на Node.js.
Читать полностью »

в 10:59, , рубрики: linux, thrift, метки: , ,

Приветствую, уважаемый читатель.

Начну с небольшой предыстории. В данный момент я работаю над довольно комплексным продуктом, который состоит из серверной части (включает в себя несколько сервисов) и клиентского SDK, портированного на определенные платформы. Весь этот зоопарк нам надо каким-то образом тестировать совместно.

Были сделаны клиентские приложения (своего рода драйверы), которые используют соответствующие SDK и умеют получать команды от тестирующего сервиса вида «сходи на сервер, сделай то», или «дай мне такой-то результат для проверки». Команды клиент получает, используя Thrift(wiki). И все было хорошо, пока мы не добрались до портирования SDK на Си и не обнаружили, что толкового мануала для Си у Apache'а нету. Нашли тикет на создание оного мануала и скудный пример там же. После успешного применения Thrift'а в Си, было решено написать небольшой ликбез на эту тему.

Цели, которые мы поставили:
— Клиент должен получать команды от тестирующего сервиса, используя Thrift;
— Команды это отлично, но нужно еще и с сервером общаться;
— Клиент должен работать в одном потоке.
Читать полностью »

Вместо начала.

Недавно пришлось заняться написанием приложения по работе. Раньше работал исключительно с PHP и web-мордами, однако быо требование сделать полноценное windows-приложение с авторизацией, использованием forms и прочей «петрушки». Эту статью я пишу на отвлеченном абстрактном примере с целью сделать ман доступным и простым. Собственно, здесь важен сам ход действий, нежели само приложение.

Задача была без веб-интерфейса работать с табличными данными, получаемыми с сервера. Доступные инструменты: web-сервер Apache + PHP + MySQL и C#-приложение на стороне клиента.

Профессионалам вряд ли будет интересно. А вот новичкам, мне кажется, может пригодиться. Очень надеюсь, что я не перемудрил с воплощением идеи.
Кому интересна реализация связки — прошу под кат.
Читать полностью »

Hello, Habr!

Решил рассказать о своем опыте работы с AutoCAD. Может быть, кому-то это поможет – ну или хотя бы интересным покажется.

public static string disclaimer = "Автор не является профессиональным разработчиком и не обладает глубокими знаниями AutoCAD. Этот пост – просто небольшой рассказ о начальном этапе создания плагина.";

Предыстория

Началось все достаточно просто: в очередной раз почувствовав острую нехватку денег, я решил, что пора бы уже начать их где-нибудь разыскивать. И вот после пары недель поиска на «Фрилансим» обнаружилась вакансия разработчика для создания программы, взаимодействующей с AutoCAD.

Скажу сразу: до того дня общаться с AutoCAD мне не доводилось. Однако объявление содержало в себе фразу «Опыт работы не требуется», которая наполнила мою душу надеждой. Я связался с разместившим вакансию человеком и получил тестовое задание.

Для пробы предлагалось создать на чертеже пару объектов, а также вывести текст. Несколько дней я искал информацию об API и пытался подружиться с непривычной программой. В конце концов фигуры были нарисованы, текст выведен, а тестовое задание отправлено на проверку. И через несколько дней я неожиданно узнал, что принят! Чудеса, да и только.

В следующих абзацах – мои впечатления, синяки и шишки, мысли и советы (возможно, вредные). Разработка велась под AutoCAD 2010, в качестве IDE использовалась верная Visual Studio 2013 Express. Язык разработки – C#.
Читать полностью »

image

Аннотация

В статье описывается фреймворк, позволяющий создавать графические кроссплатформенные приложения, написанные на языке Java, но при этом абсолютно не зависящие ни от Oracle JRE, ни от OpenJDK. Основная идеология фреймворка — по возможности снять с разработчика заботы об обеспечении «родного» look and feel для приложения под каждой операционной системой.

Фактически, на выходе вы получите исполняемый файл, опирающийся только на системные API, на котором нигде не будет клейма «написано на Java».

Все компоненты фреймворка имеют либеральные лицензии (BSD либо Apache), что позволяет использовать их в любых (в том числе, коммерческих) разработках.

Фреймворк находится в стадии публичной alpha-версии, что означает некоторую его работоспособность, но непроверенность. Использование поощряется (я постараюсь прислушаться к жалобам на проблемы и помогу их решить), но работоспособность не гарантируется.

Готовая, собранная версия приложений, демонстрирующих работу фреймворка под всеми платформами, находится здесь.

Всех интересующихся подробностями милости прошу под кат.
Читать полностью »

image

В этом обзоре мы поговорим про бесплатные курсы виртуальной академии Microsoft MVA, которые будут полезны как профессиональным разработчикам программного обеспечения, так и новичкам. Обратите внимание, что видео-плеер на сайте для ряда курсов, которые созданы на английском языке, содержит возможность включить русские субтитры.

Хит! Новичкам! Знакомство с игровыми подсистемами для Windows 8

Данный курс посвящен всем аспектам разработки игр для Windows 8, от определения целевой аудитории до получения прибыли от продукта. Вы узнаете об игровых подсистемах, упрощающих разработку, таких как Construct 2 от Scirra, GameMaker от YoYo Games и Unity. Данный курс предназначен для начинающих разработчиков игр и содержит демонстрации и многочисленные рекомендации, помогающие добиться успеха.

Сертификация! Приступаем к созданию веб-приложений ASP.NET MVC 4

Разработчикам для платформы Microsoft: прослушайте этот курс, если вы хотите начать создавать корпоративные веб-приложения или же просто требуется применить новые функции MVC либо обновить свою сертификацию Майкрософт. В рамках этого насыщенного курса вы узнаете все необходимые сведения. Он является продолжением курса Начинаем разработку на языке HTML5 с использованием JavaScript и CSS3. С его помощью также можно подготовиться к экзамену 70-486.

Хит! Новичкам! Английский. Windows Phone 8.1 Development for Absolute Beginners

Отличный и глубокий курс из 30 модулей посвященый всем аспектам разработки под мобильную платформу Windows Phone с учетом новинок самой свежей версии WP8.1. Курс на английском языке, но нагляден и вполне понятен и доступен.
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js