Автоматизированное редактирование частиц в компьютерной графике

Введение



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

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

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

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

Многие эффекты в трехмерной графике создаются при помощи частиц. Это и брызги воды, и искры бенгальского огня, и разлетающиеся обломки взорвавшегося автомобиля. При помощи систем частиц одновременно создается большое количество одинаковых объектов, поведением которых можно легко управлять. Для создания, редактирования и интеграции в конечное приложение эффектов частиц используются специальные программы – редакторы частиц. В отличие от профессиональных пакетов для работы с 3D, они обычно содержат заранее просчитанные алгоритмы поведения частиц. Этим объясняется их быстродействие (обычно такие программы работают в режиме реального времени).

Разработанное в рамках данной работы программное средство “Easy Particles” является несложным вариантом редактора частиц, позволяющее оперировать рядом физических сил при программировании эффектов частиц. К основным его достоинствам можно отнести:

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

- в отличие от профессиональных пакетов работы с частицами, научиться работать с данным редактором можно буквально за несколько минут;

- при этом доступно создание сложных, многоступенчатых эффектов, с использованием интуитивно-понятной многоступенчатой схемы;

- использование графического конвейера OpenGL позволило максимально ускорить процесс расчётов, так что вывод графики в режиме реального времени возможен при очень больших количествах полигонов;

- низкие требования, стабильность и простота настройки и работы;

- удобный графический пользовательский интерфейс;

В данной пояснительной записке представлено подробное описание разработанного редактора частиц.

Отчёт состоит из шести разделов.

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

В разделе “Проектирование и реализация задачи” приводится список классов с их описанием, рассматривается физическая и логическая организация данных, дается описание концептуального прототипа, а также приводятся функции и элементы управления, которыми оперирует программа.

В разделе “Тестирование” проводится анализ надёжности программы, примеры тестовых результатов, реакция программы на исключительные ситуации, анализ полученных результатов.

В разделе “Применение программы” приводится назначение программы с областью применения, описывается аппаратно-программный комплекс для нормального функционирования программы, система помощи, разбирается инсталляция программы, диалог с пользователем.

В разделах “Оптимизация зрительного взаимодействия оператора со средствами отображения информации па основе ЭЛТ”, “Обоснование экономической целесообразности разработки ПС “Easy Particles” ” представлены сведения, заданные для каждого раздела соответственно.




1. Постановка задачи



1.1 Требования к разрабатываемому программному средству



Разрабатываемое программное средство должно осуществлять следующие основные функции:

- управление динамическим набором эмиттеров (систем частиц);

- управление частицами каждого эмиттера;

- управление общими параметрами рисования;

- ввод и вывод данных на внешние носители;

- вывод справочных данных о разработчике, способах использования программного средства;

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

Входными данными приложения являются параметры эмиттеров, задаваемые пользователем, параметры режима рисования.

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




1.2 Обоснование актуальности темы ДП



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

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



1.3 Обзор существующих решений



На сегодняшний день существует множество приложений для работы с системами частиц. Вот некоторые наиболее популярные из них:

a) ParticleIllusion;

б) Trapcode Particular;

в) Magic Particles;

Продукт компании Wondertouch [10] ParticleIllusion на сегодняшний день является, пожалуй, наиболее всеохватывающим средством создания эффектов частиц. Изначально включает довольно большую библиотеку бесплатных эффектов, обновляемую каждый месяц. Обладает высокой расширяемостью (подключение дополнительных эмиттеров, к примеру).

Trapcode Particular – встраиваемый (необязательный) модуль для пакета программ Adobe After Effects, предназначенный для редактирования частиц, разработанный компанией Trapcode [11]. Немного менее широкий по возможностям, нежели ParticleIllusion, к тому же требующий для работы предустановленного Adobe After Effects.

Magic Particles – российский генератор частиц компании Астралакс [12]. Позволяет быстро и наглядно создавать визуальные спецэффекты на основе систем частиц. Основное достоинство Magic Particles – мгновенное отображение всех изменений без длительного процесса визуализации. Хотя то же можно сказать и о ParticleIllusion. Аналогично, в состав Magic Particles входит около сотни готовых образцов, которые можно использовать как есть или изменять по своим потребностям. Хотя по многим аспектам функциональности данный продукт уступает ParticleIllusion, к нему постоянно выходят обновления с исправлениями и дополнениями.

Все, за исключением последнего, перечисленные редакторы частиц распространяются платно.



1.4 Цели и задачи проекта



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

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

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

Другой важной задачей является разработка приложения с возможностями последующего расширения. Нужно отметить, что разрабатываемое в рамках дипломного проектирования программное средство является прототипом, реализующим лишь основные функциональные возможности программ данного класса. Поэтому необходимо позаботиться о будущих модификациях основной функциональности, возможностях лёгкого добавления новых параметров, а также поддержке многоплатформенности (поддержка Mac OS X). При этом очень важным остаётся вопрос разработки такого пользовательского графического интерфейса, чтобы в него можно было легко и без ущерба для удобства работы дизайнера интегрировать новые элементы, связанные с описанными выше новыми возможностями. Это очень важная задача, поэтому именно проработке графического пользовательского интерфейса следует уделить максимум времени при разработке программного средства. Более подробно о будущих планируемых расширениях редактора будет сказано ниже.

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



1.5 Описание программно-алгоритмического обеспечения решения поставленной задачи



	1.5.1 Среда для проектирования и разработки программных продуктов Microsoft Visual Studio 2005

Microsoft Visual Studio — линейка продуктов компании Microsoft, включающих интегрированную среду разработки программного обеспечения и ряд других инструментальных средств. В их число входят редакторы и компиляторы языков Visual Basic.NET, Visual C++, Visual C# и некоторые другие. Также, что весьма важно, Visual Studio предлагает подробную информацию о библиотеках и языках, включённых в пакет, в MSDN – информационной библиотеке по продуктам Microsoft, с возможностью получения недостающей информации из Интернета. Любой программист, создающий приложения для Windows, весьма быстро убеждается в абсолютной необходимости данного средства при разработке. Также нужно отметить, что Microsoft Visual Studio построена в архитектуре, поддерживающей возможность использования дополнений от сторонних разработчиков, что позволяет расширять возможности среды разработки. Более подробную информацию о данном пакете можно получить на официальном сайте производителя [13] и в Интернете.

Среда разработки MS Visual Studio 2005 была выбрана мною, так как создаваемое программное средство ориентировано для использования в ОС Windows. В ходе кодирования приложения, его тестирования и отладки и даже проектирования были использованы различные компоненты среды: компилятор C++, сборщик объектных C++ файлов, отладчик, средства обратного проектирования, позволяющие создавать диаграммы классов для проекта по исходному коду его компилируемых единиц, на основе средства MS Visio 2003.



1.5.2 Язык программирования C++

C++ — компилируемый строго типизированный язык программирования общего назначения. Поддерживает разные парадигмы программирования: процедурную, обобщённую, функциональную; наибольшее внимание уделено поддержке объектно-ориентированного программирования. В 1990-х годах язык стал одним из наиболее широко применяемых языков программирования общего назначения. Более полную информацию можно получить, например, прочитав книгу создателя языка Бьёрна Страуструпа [1].

Язык С++ был выбран мною по причине его высочайшей гибкости и, конечно же, высокой проработанности парадигмы объектно-ориентированного программирования. С применением именно этой парадигмы осуществлена реализация приложения. Приложение полностью построено на объектах C++ классов (в качестве исключения имеется несколько используемых C-функций), при этом широко используются концепции наследования, инкапсуляции и полиморфизма, mutable-члены данных, шаблонные классы и функции. Достаточно широко применяются шаблоны контейнеров из стандартной библиотеки шаблонов (STL), входящей в библиотеку C++. В то же время, ввиду достаточно высокой проработанности используемых в качестве базовых для приложения библиотек среды wxWidgets, отпала необходимость в создании сложных разветвлённых структур отношений родитель-потомок (наследования) на уровне кода разрабатываемого приложения. В основном, наследование свелось к созданию потомков для достаточно большого упорядоченного множества используемых стандартных компонентов wxWidgets.




1.5.3 wxWidgets

wxWidgets представляет собой набор библиотек для создания легко переносимых приложений для платформ Win32, Mac OS X, GTK+ и других (X11, Motif, WinCE). Он предоставляет в распоряжение разработчика единый, простой в использовании API. wxWidgets можно использовать с С++, Python, Perl, C#. В отличие от некоторых других межплатформенных средств разработки, wxWidgets позволяет создавать естественно-выглядящие на любой из перечисленных платформ приложения, так как использует собственные графические элементы платформы, вместо их эмуляции. wxWidgets – хорошо продуманный, бесплатный, расширяемый продукт с открытым исходным кодом, что делает его весьма полезным при разработке приложений. Более подробная информация доступна на официальном сайте [14], а также в прочих источниках Интернета.

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



1.5.4 FreeImage

Бесплатная библиотека с открытым исходным кодом, FreeImage используется для работы с данными изображений. FreeImage предоставляет разработчику удобные средства для загрузки изображений различных форматов и унифицирует работу с ними. Это библиотека с открытым исходным кодом, поддерживающая работу с такими популярными сегодня графическими форматами, как PNG, BMP, JPEG, TIFF и другими. Для реализации отдельных аспектов (оговоренных в последующих главах) приложения возникла необходимость использования подобного рода средств. FreeImage была выбрана мною, так как библиотека довольно проста в использовании, быстра, поддерживает многопоточное использование, совместима с всеми 32-х разрядными версиями Windiws, кроме того, поддерживает межплатформенную разработку (для Linux и Mac OS X). FreeImage может использоваться с С, С++, VB, C#, Delphi, Java, а также в скриптах на Perl, Python, PHP и других. За более полной информацией можно обратиться к официальному сайту проекта [15].



1.5.5 TinyXML

TinyXML – простой, небольшой, бесплатный С++ анализатор XML. TinyXML – одно из многих средств, используемых для анализа XML документов, обладает удобным и компактным внешним интерфейсом, не требует специальных знаний и длительного обучения для использования. Использовано в реализации некоторых функций приложения для работы с файловой системой. Официальный сайт проекта содержит дополнительную информацию [16].



1.5.6 Microsoft Office Visio 2003

Microsoft Office Visio 2003 — редактор диаграмм и блок-схем для Windows. Использует векторную графику для создания диаграмм.

Корпорация Visio была создана в 1990 г., и она довольно быстро стала известна на рынке благодаря одноименному программному продукту. По данным корпорации, в 2000 г. его применяли около четырех млн. пользователей в 60 странах мира.

Microsoft Visio 2000, сменивший предыдущую версию Visio 5.0, - первый продукт, вышедший под совместной торговой маркой Microsoft и Visio. В технологическом и организационном плане Visio Corporation стала работать в составе группы Microsoft по приложениям делового назначения.

Пользовательский интерфейс Microsoft Visio 2003 выполнен в традиционном стиле продуктов Microsoft Office.

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

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

Отметим также, что кроме файлов Visio (.vsd) можно использовать достаточно широкий спектр других файлов, в том числе графических и .html.

Конечно, это далеко не все возможности стандартного пакета Microsoft Visio 2003. Отметим только, что кроме различных диаграмм и графиков он позволяет, например, работать с простейшими географическими картами.

Для специалистов информационных отделов и разработчиков ПО особый интерес представляют функции пакета Microsoft Visio Professional, такие как построение схем компьютерных сетей, диаграмм баз данных, структурной схемы программ и карт Web-сайтов. При моделировании баз данных разработчик может формировать описание непосредственно в среде пакета или импортировать данные из существующих БД.

Microsoft Visio 2003 представляет большой набор средств для визуального моделирования программ – здесь можно использовать практически все распространенные типы диаграмм, описываемые с помощью Unified Modeling Language (UML) версии 1.2. При этом поддерживаются языки программирования C++, Visual Basic и Java.

После установки Microsoft Visio 2003 на компьютер в средствах разработки, в частности в Microsoft Visual Studio 2005, автоматически прописываются ссылки на пакет. С помощью команды Reverse Engineer UML Model можно автоматически сформировать описание текущего приложения, которое отображается в виде иерархического дерева в окне UML Navigator. Надо сказать, что в данном случае мы получаем детальную информацию о программе (включая описания внутренних переменных процедуры).

Это весьма краткий обзор функций Microsoft Visio 2003. Для получения более полной информации можно воспользоваться ресурсами из официального источника [13].




2. Проектирование и реализация задачи



2.1 Выбор формальных моделей



Любой проект – это уникальный процесс, в ходе выполнения которого получают уникальный продукт. Таким образом, для разработки продукта в проекте, скорее всего, должен применяться уникальный процесс. Оптимальным же решением при этом является использование одной из обобщенных, проверенных на практике методик, адаптировав ее для конкретного проекта. Как правило, всегда есть возможность выбора среди нескольких начальных жизненных циклов.

На протяжении десятилетий теоретических исследований и практических разработок было разработано множество различных моделей жизненных циклов ПО. Можно выделить наиболее известные из них: каскадная модель, V-образная модель, модель быстрого прототипирования, модель быстрой разработки приложений (RAD), инкрементная модель. Каждая из них хорошо подходит для проектов определённого типа, однако применение её в иных случаях может привести к неудаче (большим затратам ресурсов), поэтому к выбору необходимо отнестись очень внимательно.

Для разработки редактора “Easy Particles” за основу модели жизненного цикла была взята модель быстрого прототипирования. В отличие от каскадной модели, в основе неё лежит не последовательная линейная структура, а цикловая, поэтому обратная связь между фазами (в целях исправления какой-либо проблемы или недостатка, например) не приводит к значительному увеличению затрат и сбою в графике. Использование V-образной модели не имело смысла, так как она применяется при разработке программного продукта командой разработчиков, и особо ориентирована на верификацию и аттестацию продукта. Обособленному разработчику было бы весьма непросто справиться с параллельными событиями, возникающими при её использовании. К тому же, как и в каскадной модели, в ней не учтены итерации между фазами. Что касается инкрементной модели жизненного цикла, она не могла быть использована, так как определение полной функциональной системы в ней должно осуществляться в начале жизненного цикла, а также, поскольку в данной модели создание одних модулей завершается значительно раньше других, необходимости в четко определенных (также в начале жизненного цикла) интерфейсах. Это недопустимые условия для разработки редактора, требования к функциональности, поддерживаемым платформам, пользовательскому интерфейсу были изменены несколько раз в процессе разработки.

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

- полные требования не известны заранее и не постоянны;

- существует потребность в разработке достаточно сложных пользовательских интерфейсов;

- осуществляются временные демонстрации;

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

- разработчики не уверены в том, какую оптимальную архитектуру или алгоритмы следует применять;

- системные интерфейсы усложнены;

Создание модели быстрого прототипирования было бы невозможным без работ выдающегося Фреда Брукса (“The Mythical Man-Month”, "No Silver Bullet, the Essence and Accidents of Programming"). Его идеи, изложенные в данных книгах, сегодня столь же актуальны, как и в 1975 году. Технологии радикально изменили мир, но многие недостатки менеджмента программных проектов по-прежнему те же. Десятки лет тому назад Брукс сказал:

"В большинстве проектов первая построенная система едва ли пригодна к употреблению. Она может быть слишком медленной, слишком объемной, неудобной в использовании или обладать всеми тремя перечисленными недостатками. Нет другого выбора, кроме как начать с самого начала, приложив все усилия, и построить модернизированную версию, в которой решались бы все три проблемы...

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

Эти слова замечательно передают сущность рассматриваемой модели, её основную идею – построение экспериментальных моделей реального приложения, иными словами – прототипирование.

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

Таким образом, прототип — это эквивалент экспериментальной модели или "макета" в мире аппаратного обеспечения.

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

Схему метода можно изобразить следующим образом:


Рисунок 2.1 – Метод быстрого прототипирования



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

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

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

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

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

Использование данной модели не раз оправдало себя в течение разработки. В целом, оно позволило решить следующие проблемы:

- исходя из реакции заказчиков на демонстрации разрабатываемого продукта, разработчиком были получены сведения об аспектах необходимого поведения системы, благодаря чему количество неточностей в требованиях свелось минимуму;

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

- при разработке образовывались постоянные, видимые признаки прогресса в выполнении проекта, благодаря чему заказчики чувствовали себя уверенно;

- благодаря меньшему объему доработок были уменьшены затраты на разработку;

- благодаря тому, что проблемы, как правило, выявлялись до привлечения дополнительных ресурсов, сократились общие затраты;

- было обеспечено управление рисками;



2.2 Структурная модель приложения



Приложение состоит из двух основных сущностей:

а) очередь эмиттеров;

б) оконно-интерфейсная часть;

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

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

Отдельно взятый набор частиц представлен внутренними структурами данных эмиттера. Здесь хранятся все параметры эмиттера и каждой его частицы:

а) для эмиттера:

1) координаты в двумерной декартовой системе;

2) скорость;

3) размеры;

4) значения разброса частиц;

5) стартовая задержка и длительность генерации;

б) для частицы:

1) текстура;

2) время жизни;

3) скорость по осям;

4) гравитация по осям;

5) значения начальных и конечных растяжений;

6) значения начального и конечного цветов по каналам;

Для реализации интерфейсной части были использованы графические объекты вышеописанного межплатформенного движка wxWidgets.

Корневым элементом интерфейсной части является основной фрейм. Основной фрейм служит для расположения фрейма ввода данных, фрейма управления очередью эмиттеров, фрейма вывода. Также основному фрейму принадлежат системное меню, панели инструментов и статуса.

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

Фрейм управления очередью эмиттеров представляет собой панель со схематическим отображением отдельных эмиттеров в виде пиктограмм. К функциям фрейма относятся добавление и удаление эмиттеров, копирование эмиттера со всеми его параметрами, изменение текущего эмиттера, а также порядка прорисовки эмиттеров. Для копирования и удаления эмиттеров при активном фрейме управления очередью можно использовать горячие клавиши (Ctrl+V, Ctrl+X, соответственно).

Фрейм вывода объединяет в себе всю функциональность вывода графических данных приложения. Для максимально быстрого вывода используется низкоуровневая работа с аппаратным обеспечением видеосистемы, осуществляемая посредством драйвера OpenGL. Доступ к платформенно-независимому конвейеру OpenGL осуществляется, в свою очередь, через интерфейс wxWidgets. Именно на уровне фрейма вывода осуществлено связывание оконной системы и функциональности рисования очереди эмиттеров, не зависящей от конкретного окна и работающая с буферами OpenGL. Средства wxWidgets используют для этого те или иные системные библиотеки, в зависимости от целевой платформы. Для Windows это WGL, для Mac OS X – AGL, а также стандартные Carbon (для С++) и Cocoa (Objective С).

Дополнительно фрейм вывода позволяет при помощи мыши перемещать эмиттеры, изменять их размеры. Также поддерживается перенос рабочей (текущей отображаемой) области рисования. Для этого необходимо, во-первых, активировать режим переноса, использовав клавишу Space. Затем, используя мышь, осуществить перенос области в нужном направлении и на необходимое расстояние. Для выхода из режима переноса рабочей области необходимо повторно нажать клавишу Space. Необходимо отметить, что в режиме переноса рабочей области возможности переноса эмиттеров и изменения их размеров отключаются.

Системное меню имеет следующую структуру:

- меню “Файл”, отвечающее за общий сброс, сохранение и загрузку, выход из приложения;

- меню “Очередь”, отвечающее за установку режима отображения эмиттеров (Playback, Loop playback, Static), добавление и удаление текущего эмиттера, копирование эмиттера и набора его параметров, сброс всех эмиттеров;

- меню “Информация”, позволяющее получить информацию о способах использования редактора, а также о разработчике;

Панель инструментов содержит следующие компоненты:

а) функции установки режима отображения эмиттеров:

1) Playback;

2) Loop playback;

2) Static;

б) функции сохранения и загрузки:

1) Save;

2) Load;

в) функции настройки отображения:

1) Back color;

2) Back image;

3) режим смешивания;

Панель статуса имеет два поля: количество отображённых за секунду кадров, число частиц, число примитивов, быстрая подсказка (по ситуации).

Получить информацию о внутренней структуре приложения можно, обратившись к диаграмме классов (Приложение Г).



2.3 Функциональная модель приложения



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

Настройка очереди эмиттеров, в свою очередь, состоит из на набора функций по управлению очередью (добавление эмиттеров, удаление эмиттеров, копирование эмиттеров с переносом их параметров) и набора функций по установке параметров текущего эмиттера и его частиц.

Функция отображения реализует вывод на экран создаваемых эффектов.

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

Функции настройки отображения состоят в установке дополнительных параметров отображения (перечисленных в предыдущем подразделе).

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



2.4 Информационная модель приложения



Информационная модель приложения отражает потоки информации, проходящие между его модулями и внешними сущностями.

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

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

За непосредственный приём данных эмиттеров от пользователя отвечает инструментарий фрейма ввода. Библиотеки операционной системы предоставляют для этого всё необходимое, а использование предкомпиляторных “фильтров” wxWidgets позволяет и вовсе забыть о платформе.

После ввода данные направляются в первую основную сущность приложения – очередь эмиттеров. Там они хранятся, используясь при выводе (некоторые поля модифицируются при этом).

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

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

Обобщая вышесказанное, к основным потокам данных приложения можно отнести:

а) ввод пользователем в систему параметров эмиттеров:

1) координаты в двумерной декартовой системе;

2) скорость;

3) размеры эмиттера;

4) значения разброса частиц;

5) стартовая задержка и длительность генерации;

б) ввод пользователем в систему параметров частиц эмиттера:

1) текстура;

2) время жизни;

3) скорость по осям;

4) гравитация по осям;

5) значения начальных и конечных растяжений;

6) значения начального и конечного цветов (32bit), по каналам;

в) вывод графической информации системы эмиттеров в буфер изображения;

Графически информационная модель приложения представлена в Приложении В, на диаграмме потоков данных.



2.5 Объектная модель приложения



Так как приложение было разработано с использованием возможностей объектно-ориентированного языка С++, следует раскрыть его объектную структуру. Подробно объектная структура программного средства описана в Приложении Г, здесь же можно привести общий обзор системы классов.

а) класс MyApp, отвечает за инициализацию приложения, создаётся и управляется полностью из среды wxWidgets. Это корневой класс всей проектируемой части приложения.

б) модуль очереди эмиттеров. Включает в себя:

1) класс ParticleSystemChain, то есть непосредственно саму очередь; в системе существует singleton-объект данного класса;

2) содержащиеся в очереди эмиттеры – объекты класса ParticleSystem;

3) для формирования и использования корректных OpenGL текстур на основании битовых изображений используются объекты класса MyTexture.

в) класс MainFrame – корневой класс оконного пользовательского интерфейса; в системе существует singleton-объект данного класса;

г) класс PSChainFrame представляет собой окно управления очередью систем;

д) объекты PSLabel применяются в PSChainFrame для представления эмиттеров, представляют собой пиктограммы;

е) PSInputFrame используется для ввода пользовательских данных активной системы;

ж) объекты классов MySpinCtrld и MySpinEditCtrld – пользовательские элементы управления, используемые для ввода чисел с плавающей точкой из указанного диапазона, применяются в PSInputFrame;

з) PSOutputFrame используется для отображения результатов работы приложения (вывода вычисленных графических примитивов – частиц); объект MyCanvas – предоставляется OpenGL в качестве контекста визуализации;

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


2.6 Требования к программным, аппаратным ресурсам и ОС



Для сборки приложения необходимо наличие набора встраиваемых (статических) библиотек среды wxWidgets, установленных в системный каталог (или в один из каталогов поиска статических библиотек, указанных в настройках среды разработки Microsoft Visual Studio 2005 и в свойствах проекта). Для корректной работы приложения необходимо наличие в системе динамической библиотеки OpenGL (любой версии, по умолчанию с OS Windows поставляется версия 1.0). Драйвер OpenGL используется для растеризации графических данных, генерируемых редактором.

Приложение требует не более 30 MB оперативной памяти, 20 MB – виртуальной, 40 MB дискового пространства.

Минимальное разрешения дисплея монитора, требуемое для корректной работы приложения, составляет 1024x768 точек.

Приложение работает под управлением любой OС Windows (версии не ниже Windows XP SP2).

Кроме того, для корректной работы приложения, собранного в Microsoft Visual Studio 2005, необходимо наличие в системе установленных специальным образом библиотек (так называемых манифестов), иначе приложение не запустится. В качестве альтернативы можно собрать приложение с использованием Microsoft Visual Studio 2003, однако при этом будет использован графический пользовательский интерфейс старого образца.




3. Тестирование



3.1 Анализ надежности



	Испытания проводятся с целью выявления отклонений в работе программы и результатах её функционирования, оценки причин таких отклонений. Отклонения полученных результатов от эталонов используются для оценки качества программы.

	Основным методом обнаружения ошибок при проведении испытаний программы являлось тестирование, в котором целесообразно выделить три стадии:

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

	- тестирование для диагностики обнаруженных искажений результатов, с целью обнаружения инструкций и данных, явившихся причиной отклонения результатов от эталонных при тестировании для обнаружения ошибок;

	- тестирование для контроля выполненных корректировок программы и данных, где подтверждалась правильность выполненной корректировки.

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

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

	


3.2 Тестовые примеры



При тестировании был проведен ряд тестов различной направленности:

- тест корректности вводимых пользовательских данных, в рамках которого была проверена система ввода всех видов данных, используемых приложением, с попытками ввода некорректных данных;

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

- тест корректности работы приложения на ПК с различными конфигурациями (драйверами графического ускорителя); приложения, использующие низкоуровневую функциональность драйвера (или близкую к ней), необходимо дополнительно тестировать на совместимость с различными разновидностями драйверов данного типа. В случае с разрабатываем приложением, необходимо выполнить проверку на корректность его работы с различными драйверами видеосистемы, так как приложение использует низкоуровневые возможности OpenGL в качестве своей осевой функциональности.



3.3 Реакция программы на тесты



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

После успешной компиляции и сборки приложения, непосредственно в процессе тестирования, были обнаружены и устранены ошибки времени исполнения. Из наиболее трудно-устранимых можно отметить ошибку приведения данных типов с плавающей запятой при пользовательском вводе (что приводило к их неявному искажению), а также ошибки проектирования пользовательского интерфейса, в связи с чем последний был целиком переработан несколько раз. При тестировании приложения с графическим ускорителем от фирмы ATI были выявлены ошибки инициализации текстурных данных, из-за чего нарушался их вывод. Из ошибок работы приложения при установленных граничных значениях параметров можно выделить ошибку генерации частиц при заданной ширине и/или высоте эмиттера, равной нулю. При этом для частиц генерировались координаты, сильно выходящие за пределы границ эмиттера. Эту ошибку можно назвать логической ошибкой программы.

При устранении найденных ошибок отладка программы осуществлялась встроенным отладчиком MS Visual Studio 2005.



3.4 Вывод по результатам тестирования



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

В результате испытаний на контрольных примерах было доказано, что данная программа работает согласно заданному алгоритму. Все ошибочные ситуации были рассмотрены, ошибки – устранены.




4. Применение программы



4.1 Назначение программы



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

- управление динамическим набором эмиттеров (систем частиц);

- управление частицами каждого эмиттера;

- управление общими параметрами рисования;

- ввод и вывод данных на внешние носители;



4.2 Инсталляция программы



Разработанное программное средство не нуждается в инсталляции. Однако следует заметить, что для работы приложения необходимо наличие в системе динамической библиотеки OpenGL любой версии (с MS Windows по умолчанию поставляется версия 1.0).

Кроме того, для корректной работы приложения, собранного в Microsoft Visual Studio 2005, необходимо наличие в системе установленных специальным образом библиотек (так называемых манифестов), иначе приложение не запустится. В качестве альтернативы можно собрать приложение с использованием Microsoft Visual Studio 2003, однако при этом будет использован графический пользовательский интерфейс старого образца. Более подробно о манифестах, их типах и назначениях, можно прочитать на официальном сайте корпорации Microsoft [13].




4.3 Структура входных данных



Входными данными приложения служат параметры эмиттеров, задаваемые пользователем, а также параметры отображения. Более подробно со структурой входных данных можно ознакомиться в подразделе 1.1, или на диаграмме потоков данных (Приложение В).



4.4 Диалог с пользователем



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

При попытке выхода из приложения с несохранёнными данными проекта осуществляется запрос пользователя о необходимости выполнить сохранение данных.

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

В остальном, с учётом типа и назначения приложения, используемого в нём интуитивно понятного, продуманного графического пользовательского интерфейса, необходимость в дополнительной обратной связи с пользователем отпадает.



4.5 Форма представления выходных данных



Выходные данные формируются, как уже было отмечено выше, в нескольких формах. Можно просматривать выходную информацию в графическом виде непосредственно на экране редактора. Также разработчик приложения, использующий редактор (предоставляемый разработчику исходный код для вывода эффектов частиц), может выводить данные в окно своего приложения (предварительно связав его с OpenGL средствами ОС). Наконец, можно просматривать выгруженные на диск выходные данные с помощью любого текстового (XML) редактора.




5. Оптимизация зрительного взаимодействия оператора со средствами отображения информации па основе ЭЛТ



5.1 Особенности зрительного восприятия информации и формирование утомления зрительного анализатора оператора



Зрительное восприятие — совокупность процессов построения зрительного образа окружающего мира. Из этих процессов более простые обеспечивают восприятие цвета, которое может сводиться к оценке светлоты, или видимой яркости, цветового тона, или собственно цвета, и насыщенности как показателя отличия цвета от серого равной с ним светлоты. При этом основные механизмы цветового восприятия имеют врожденный характер и реализуются за счет структур, локализованных на уровне подкорковых образований мозга. Более филогенетически поздними являются механизмы зрительного восприятия пространства, в которых происходит интеграция соответствующей информации о пространстве, полученной также от слуховой, вестибулярной, кожно–мышечной сенсорных систем. В пространственном зрении выделяют два основных класса перцептивных операций, обеспечивающих константное восприятие. Одни позволяют оценивать удаленность предметов на основе бинокулярного и монокулярного параллакса движения. Другие позволяют оценить направление. В основном пространственное восприятие обеспечивается врожденными операции, но их окончательное оформление происходит в приобретаемом в течение жизни опыте практических действий с предметами. Пространственное восприятие является основой восприятия движения, которое также осуществляется за счет врожденных механизмов, обеспечивающих детекцию движения. Более сложными операциями зрительного восприятия является операции восприятия формы, которые и в филогенезе, и онтогенезе формируются достаточно поздно. Основой выступает восприятие пространственных группировок как объединение однотипных элементов, расположенных в достаточно узком зрительном поле.

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

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

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

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

Специалистами-медиками и гигиенистами разработано большое количество разнообразных упражнений, направленных на восстановление и защиту от перегрузок органов зрения упражнений. Они широко представлены, например, в источнике [8].

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

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

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




5.2 Инженерно-психологические требования к средствам отображения информации (СОИ) и их расположению в рабочем пространстве



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

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

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

Все эргономические требования изложены в соответствующих ГОСТах (ГОСТ 21829- 76, ГОСТ 21480-76, ГОСТ 21837-76, ГОСТ 22902-78).

Остановимся на основных требованиях к мониторам и характеристиках изображения на экране.

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

Основные нормируемые визуальные характеристики мониторов и соответствующие допустимые значения этих характеристик представлены в таблице 5.1.



Таблица 5.1 – Некоторые нормируемые визуальные параметры мониторов [9]

Параметры

Допустимые значения

Яркость знака или фона (измеряется в темноте)

35-120 кд/м2

Контраст

От 3:1 до 1,5:1

Временная нестабильность изображения (мерцания)

Не должна быть зафиксирована более90% наблюдателей

Угловой размер знака

16-60

Отношение ширины знака к высоте

0,5-1,0

Отражательная способность экрана (блики)

не более 1%

Неравномерность яркости элементов знаков

не более (25%)

Неравномерность яркости рабочего поля экрана

не более (20%)

Формат матрицы знака

не менее 7 * 9 элементов изображения

Размер минимального элемента отображения (пикселя) для монохромного монитора, мм.

0,3

Допустимое вертикальное смещение однотипных знаков, % от высоты матрицы

не более 5

Допустимая пространственная нестабильность изображения (дрожание по амплитуде изображения) при частоте колебаний в диапазоне от 0,5 до 30 Гц, мм

не более 2L*10-4 (L-расстояние наблюдения, мм.)

Кроме того, компьютеры и мониторы, а также организация рабочих мест операторов должны соответствовать принятым на территории Республики Беларусь санитарным правилам и нормам [7], касающимся охраны зрения пользователей персональных компьютеров:

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

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

Экран видеомонитора должен находиться от глаз пользователя на оптимальном расстоянии 600-700 мм, но не ближе 500 мм с учетом размеров алфавитно-цифровых знаков и символов.

Рабочее место с монитором и ПК должно быть оснащено легко перемещаемым пюпитром для документов.

Уровень глаз при вертикально расположенном экране монитора должен приходиться на центр или 2/3 высоты экрана. Линия взора должна быть перпендикулярна центру экрана и оптимальное ее отклонение от перпендикуляра, проходящего через центр экрана в вертикальной плоскости, не должно превышать 5°, допустимое - 10°.




5.3 Требования к организации, качественным и количественным характеристикам освещения рабочего места оператора и их реализация. Оптимизация режима труда и отдыха оператора



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

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

Нормами для данных работ установлена необходимая освещенность рабочего места Ен=300лк (средняя точность работы по различению деталей размером от 1 до 10 мм).

Для освещения рабочего места оператора обычно используются люминесцентные лампы – они имеют ряд преимуществ перед лампами накаливания: их спектр ближе к естественному, они имеют большую экономичность (больше светоотдача) и срок службы (в 10-12 раз). Наряду с этим имеются и недостатки: их работа иногда сопровождается шумом, они хуже работают при низких температурах, имеют малую инерционность.

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

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

Что касается естественного освещения, лучше всего, если окна в комнате выходят на север или северо-восток. Как уже было сказано, в поле зрения пользователя не должно быть резких перепадов яркости, поэтому окна желательно закрывать шторами либо жалюзи. Уровень естественного освещения нормируется коэффициентом естественной освещенности (КЕО) - это отношение естественной освещенности внутри помещения Евн к одновременному значению наружной горизонтальной освещенности Ен. Освещенность Е измеряется в люксах (Лк). Фактическая освещенность должна быть больше или равна нормируемой. При эксплуатации зданий необходимо поддерживать светоотдачу и светопропускаемость окон, т. е. производить их своевременную чистку. При незначительном выделении пыли – 4 раза в год.

Искусственное освещение может быть общим и комбинированным, внутренним и наружным. Искусственное освещение обеспечивается электролампами различной мощности, заключенными в специальную арматуру (светильники, различных типов и исполнений).

Искусственное освещение рабочего места оператора должно быть общим и равномерным, использование одних только настольных ламп недопустимо.

Одним из главных способов повлиять на процессы утомления оператора является установление соответствующих режимов труда.

При распределении работ в течение недели следует учитывать, что работоспособность увеличивается в первые дни недели, достигает наивысшего уровня на третий-четвертый день, а затем снижается.

Распределение работ в течение смены должно учитывать, что период вырабатывания у операторов ПК составляет от 10 до 40 минут (в послеобеденное время период вырабатывания сокращается). Период устойчивой работоспособности продолжается около двух часов; период наступления утомления и спада работоспособности наступает после 1,5-2,0 часов устойчивой работоспособности (во второй половине рабочего дня период утомления более выражен).

Режимы труда и отдыха при работе с ПК в течение смены должны организовываться в зависимости от вида и категории трудовой деятельности.

Виды трудовой деятельности разделяются на 3 группы: 

а) группа А — работа по считыванию информации с экрана ПК с предварительным запросом;

б) группа Б — работа по вводу информации;

в) группа В — творческая работа в режиме диалога. 

При выполнении в течение рабочей смены работ, относящихся к разным видам трудовой деятельности, за основную работу с ПК следует принимать такую, которая занимает не менее 50% времени в течение рабочей смены или рабочего дня.

Для видов трудовой деятельности устанавливается 3 категории тяжести и напряженности работы с ПК, которые определяются:

а) для группы А — по суммарному числу считываемых знаков за рабочую смену, но не более 60 000 знаков за смену;

б) для группы Б — по суммарному числу считываемых или вводимых знаков за рабочую смену, но не более 40 000 знаков за смену;

в) для группы В — по суммарно времени непосредственной работы с ПК за рабочую смену, но не более 6 часов за смену.

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



Таблица 5.2 – Время регламентированных перерывов в зависимости от продолжительности рабочей смены, вида и категории трудовой деятельности с ПК

Категория работы с ПК

Уровень нагрузки за рабочую смену при видах работ с ПК

Суммарное время регламентированных перерывов, мин.



группа А, кол-во знаков

группа Б, кол-во знаков

группа В, час.

при 8-часовой смене

при 12-часовой смене

I

до 20000

до 15000

до 2,0

30

70

II

до 40000

до 30000

до 4,0

50

90

III

до 60000

до 40000

до 6,0

70

120



Время перерывов дано при соблюдении оптимальных режимов труда, в противном случае время регламентированных перерывов следует увеличить на 30%.

При работе с графическими элементами менее 0,5 мм, длительность сосредоточенного наблюдения должна быть не более 50% времени смены. 

Продолжительность непрерывной работы с ПК без регламентированного перерыва не должна превышать 2 часов.

При многосменной работе, что актуально для диспетчеров, да и взаимоотношения с Internet часто вынуждают к такому режиму, физиологически рациональное время начала и окончания работы смены находится в следующих интервалах: 6 - 8 часов, 14 - 16 часов, 0 - 4 часа.

При работе с ПК в ночную смену (с 22 до 6 часов), независимо от категории и вида трудовой деятельности, продолжительность регламентированных перерывов должна увеличиваться на 60 минут. При 8-часовой рабочей смене и работе на ПК регламентированные перерывы следует устанавливать: 

а) I категория работ - через 2 часа от начала рабочей смены и через 2 часа после обеденного перерыва продолжительностью 15 минут каждый; 

б) II категория работ - через 2 часа от начала рабочей смены и через 1,5 - 2 часа после обеденного перерыва продолжительностью 15 минут каждый или продолжительностью 10 минут через каждый час работы;

в) III категория работ - через 1,5 - 2 часа от начала рабочей смены и через 1,5 - 2 часа после обеденного перерыва продолжительностью 20 минут каждый или продолжительность 15 минут через каждый час работы.

При 12-часовой рабочей смене регламентированные перерывы должны устанавливаться в первые 8 часов работы аналогично перерывам при 8-часой рабочей смене, а в течение последних 4 часов работы, независимо от категории и вида работ, каждый час продолжительностью 15 минут.

При несоблюдении принятых санитарных норм СанПиН 9-131 РБ 2000, а также требований, которых необходимо придерживаться во избежание ошибок, которые может допустить в процессе работы оператор, приводит к психофизиологическим перегрузкам оператора.




6. Обоснование экономической целесообразности разработки ПС “Easy Particles”



6.1 Общая характеристика разрабатываемого ПС ВТ



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

Разработка проектов программных средств требует затрат разнообразных и, не редко значительных объемов, ресурсов (трудовых, материальных, финансовых). В связи с этим, разработка и реализация каждого проекта должна быть обоснована, как технически, так и экономически.

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

Программное средство функционального назначения “Easy Particles” – графический редактор, разработан на C++ с использованием MS Visual Studio 2005 и ряда специализированных библиотек, является ПС 1 группы сложности.

Разрабатываемое программное средство относится к 1-й группе сложности. По степени новизны программный продукт относится к группе “В” с коэффициентом 0,7.



6.2 Расчет цены и прибыли на ПС



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

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

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

- снижения трудоемкости расчетов и алгоритмизации программирования и отладки программ за счет использования ПС в процессе разработки автоматизированных систем обработки данных;

- сокращения расходов на оплату машинного времени и других ресурсов на отладку программ;

- снижения расходов на материалы (магнитные ленты, магнитные диски и прочие материалы);

- ускорение ввода в эксплуатацию новых систем;

- улучшения показателей основной деятельности в результате использования ПС.

Стоимостная оценка ПС у разработчиков предполагает определение размеров затрат, что включает следующие статьи:

- заработная плата исполнителей - основная и дополнительная;

- отчисления в фонд социальной защиты населения;

- отчисления по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний;

- расходы на материалы и комплектующие;

- расходы на спецоборудование;

- расходы на оплату машинного времени;

- прочие прямые затраты;

- накладные расходы.

На основании затрат рассчитывается себестоимость и отпускная цена ПС.



6.2.1 Исходные данные



Таблица 6.1 – Исходные данные для расчётов

Наименование показателя

Единица измерения

Условные обозначения

Норматив

Коэффициент изменения скорости обработки информации

ед.

Кск

0,7

Численность разработчиков

чел.

Чр

1

Тарифная ставка 1-го разряда в организации

руб.

Сзм1

77000

Тарифный коэффициент

ед.

Кт

2,84

Фонд рабочего времени

ч

ФРВ

169.3

Коэффициент естественных потерь рабочего времени

ед.

Кп

1,4

Коэффициент премирования

ед.

Кпр

1

Норматив дополнительной заработной платы

%

Ндз

10%

Ставка отчислений в Фонд социальной защиты населения

%

Нфсзн

34%

Ставка отчислений по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний

%

Нбгс

1%

Цена одного машино-часа

руб.

Цм

2200

Норматив прочих затрат

%

Нпз

12%

Норматив накладных расходов

%

Ннр

120%

Норматив расходов на сопровождение и адаптацию

%

Нрса

10%

Уровень рентабельности

%

Урн

24%

Ставка отчислений по единому нормативу в целевые бюджетные фонды из выручки от реализации

%

Нцбф

1%

Ставка НДС

%

Нндс

18%

Норматив расходов на освоение ПС

%

Нос

1%

Норматив расходов на пополнение оборотных средств в связи с использованием нового ПС

%

Ноб

1%

Ставка налога на прибыль

%

Нnр

24%

Ставка местных налогов и сборов

%

Нмс

3%

Норматив приведения разновременных затрат

ед.

Ен

0,11



6.2.2 Определение объема ПС

Объем ПС определяется путем подбора аналогов на основании классификации типов ПС, каталога функции ПС и аналогов ПС в разрезе функций.



Таблица 6.2 – Содержание и объем функций на разрабатываемое ПС ВТ

Функция

Объем, условных машинных команд

Работа с файлами характеристик систем частиц, файлами изображений

1100

Организация ввода характеристик систем частиц пользователем

1020

Организация ввода управляющих сигналов от пользователя

700

Организация вывода графической информации в режиме реального времени

1150

Прочие расчёты, сервисные функции

700

Справка и обучение

520

Итого

5190

На основании информации о функциях разрабатываемого ПС по каталогу функций определяется объем функций. Общий объем ПС рассчитывается по формуле:



	, 	(6.1)

	

где Vо – общий объем ПС, условных машино-команд;

Vi – объем функций ПС, условных машино-команд;

	n – общее число функций.

	= 5190 условных машинных команд

	С учетом изменения скорости обработки информации рассчитывается скорректированный объем функций:

	

	Vo/ = Vo · Кск , 									(6.2)

	

где  – скорректированный объем ПС, условных машинных команд;

 – общий объем ПС, условных машинных команд;

	Кск – коэффициент изменения скорости обработки информации.

Vo/ = 5190*0,7 = 3633 условных машинных команд



6.2.3 Расчет трудоемкости выполняемой работы



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

Общая трудоемкость ПС рассчитывается по формуле:

	 , 	(6.3)



где То – общая трудоемкость ПС, человеко-дней;

Тн – нормативная трудоемкость ПС, человеко-дней;

Ксл – дополнительный коэффициент сложности ПС, ед.

Уровень сложности = 1, КСЛ = 0,18, норма времени Тн = 112. Получаем:

То= 112 * 0,7 *0,18 = 14 человеко-дней



6.2.4 Расчет основной заработной платы

Нормативная трудоемкость служит базой для расчета основной заработной платы.

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

Месячная тарифная ставка каждого исполнителя определяется путем умножения действующей месячной тарифной ставки 1-го разряда на тарифный коэффициент, соответствующий установленному тарифному разряду:



Сзм = Сзм1 . Кт ,									(6.4)



где Сзм – тарифная ставка за месяц, руб.;

Сзм1 – тарифная ставка 1-го разряда за месяц, руб.;

Кт – тарифный коэффициент, ед.



Сзм = 77000*2,84 = 218680 руб.


Основная заработная плата исполнителей на конкретное ПС рассчитывается по формуле:

							(6.5)



где Соз– основная заработная плата, руб.;

Сзд – тарифная ставка за день, руб.;

То – общая трудоемкость ПС, человеко-дней;

Кп – коэффициент естественных потерь рабочего времени, ед.;

Кпр – коэффициент премирования, ед.



Соз = (218680 / 21,25)*14*1,4*1 = 201700 руб.



6.2.5 Расчет дополнительной заработной платы

Дополнительная заработная плата на конкретное ПС включает выплаты, предусмотренные законодательством о труде (оплата отпусков, льготных часов, времени выполнения государственных обязанностей и других выплат, не связанных с основной деятельностью исполнителей), и определяется по нормативу в процентах к основной заработной плате:



, 									(6.6)



где Сдз – дополнительная заработная плата на конкретное ПС, руб.;

Ндз – норматив дополнительной заработной платы, %.



Cдз = 201700 * 0,1 = 20170 руб.




6.2.6 Расчет отчислений в Фонд социальной защиты населения

Отчисления в фонд социальной защиты населения определяются в соответствии с действующими законодательными актами по нормативу в процентном отношении к фонду основной и дополнительной зарплаты исполнителей, определенной по нормативу, установленному в целом по организации:

, 								(6.7)



где Сфсзн – сумма отчислений в Фонд социальной защиты населения, руб.;

Нфсзн – норматив отчислений в Фонд социальной защиты населения, %.



Cфсзн = (201700 + 20170) * 0,34 = 75436 руб.



6.2.7 Расчет отчислений по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний

Отчисления по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний рассчитываются по формуле:



,								(6.8)



где Сбгс – сумма отчислений по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний, руб.;

Нбгс – норматив отчислений по обязательному страхованию от несчастных случаев на производстве и профессиональных заболеваний, %.



Сбгс = (201700 + 20170)*0,01 = 2219 руб.


6.2.8 Расчет расходов на материалы и комплектующие

По статье “Материалы” отражаются расходы на магнитные носители, бумагу, красящие ленты и другие материалы, необходимые для разработки ПС. Нормы расхода материалов в суммарном выражении определяются в расчете на 100 строк исходного кода. Сумма затрат материалов рассчитывается по формуле:



,									(6.9)



где См – сумма расходов на материалы, руб.;

Нм – норма расхода материалов в расчете на 100 строк исходного кода ПС, руб.



См = 380*0,7*3633/100 = 9664 руб.



6.2.9 Расчет расходов на оплату машинного времени

Расходы по статье “Машинное время” включают оплату машинного времени, необходимого для разработки и отладки ПС, которое определяется по нормативам (в машино-часах) на 100 строк исходного кода машинного времени в зависимости от характера решаемых задач и типа ПК:



 ,								(6.10)



где Смв – сумма расходов на оплату машинного времени, руб.;

Цм – цена одного машино-часа, руб.;

Нмв – норматив расхода машинного времени на отладку 100 строк исходного кода, машино-часов.

Смв = 2200*3633/100*12*0,6 = 575467 руб.



6.2.10 Расчет прочих прямых затрат

Расходы на конкретное ПС включают затраты на приобретение и подготовку специальной научно-технической информации и специальной литературы. Определяются по нормативу в процентах к основной заработной плате:



 ,									(6.11)



где Спз – сумма прочих затрат, руб.;

Нпз – норматив прочих затрат в целом по организации, %.



Спз = 201700*12/100 = 24204 руб.



6.2.11 Расчет накладных расходов

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



 ,									(6.12)



где Снр – сумма накладных расходов, руб.;

Ннр – норматив накладных расходов в целом по организации, %.




6.2.12 Расчет суммы расходов на разработку ПС ВТ

Общая сумма расходов на ПС рассчитывается по формуле:



,			(6.13)



где Ср – сумма расходов на разработку ПС ВТ, руб.;



Ср = 201700 + 20170 + 75436 + 2219 + 9664 + 0 + 575467 + 24204 + 242040 = 1150900 руб.



6.2.13 Расчет расходов на сопровождение и адаптацию

Кроме того, организация-разработчик осуществляет затраты на сопровождение и адаптацию ПС, которые определяются по нормативу:



,									(6.14)



где Срса – сумма расходов на сопровождение и адаптацию ПС ВТ, руб.;

Нрса – норматив расходов на сопровождение и адаптацию, %.



Срса = 1150900 * 10/100 = 115090 руб.



6.2.14 Расчет полной себестоимости разработки ПС ВТ

Общая сумма расходов на разработку (с затратами на сопровождение и адаптацию) – полная себестоимость ПС – определяется по формуле:



,(6.15)

Сп = 1150900 + 115090 = 1265990 руб.




6.2.15 Определение отпускной цены на ПС ВТ

Отпускная цена определяется на основании цены разработчика, которая формируется на основе показателя рентабельности продукции. Рентабельность и прибыль по создаваемому ПС определяются исходя из результатов анализа рыночных условий, переговоров с заказчиком (потребителем) и согласования с ним отпускной цены, включающей дополнительно налог на добавленную стоимость и отчисления в целевые бюджетные фонды из выручки от реализации продукции.

Прибыль рассчитывается по формуле:



 ,									(6.16)



где Ппс – прибыль от реализации ПС, руб.;

Урп – уровень рентабельности ПС, %;



Ппс = 1265990 * 24/100 = 303838 руб.



Прогнозируемая цена разработчика ПС без налогов:



Цп = Сп + Ппс,									(6.17)



где Цп – прогнозируемая цена разработчика ПС, руб.;



Цп = 1265990 + 303838 = 1569828 руб.



Сумма отчислений в целевые бюджетные фонды из выручки от реализации продукции единым платежом:




 ,								(6.18)



где Сцбф – сумма отчислений в целевые бюджетные фонды из выручки от реализации продукции единым платежом, руб.;

Нцбф – ставка отчислений в целевые бюджетные фонды из выручки от реализации продукции единым платежом, %.



Сцбф = 1569828 * 1/(100-1) = 15857 руб.



Сумма налога на добавленную стоимость:



 ,							(6.19)



где НДС – сумма налога на добавленную стоимость, руб.;

Нндс – ставка НДС, %.



НДС = (1569828 + 15857) * 18/100 = 285423 руб.



Прогнозируемая отпускная цена:



,								(6.20)



где Цо – прогнозируемая отпускная цена, руб.



Цо = 1569828 + 15857 + 285423 = 1871108 руб.




6.3 Расчет экономического эффекта от применения ПС у пользователя



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

В результате применения нового ПС пользователь может понести значительные капитальные затраты на приобретение и освоение ПС, доукомплектования ЭВМ новыми техническими средствами и пополнение оборотных средств. Однако, если приобретенное ПС будет в достаточной степени эффективнее базового, то дополнительные капитальные затраты быстро окупятся. Эффект может быть достигнут за счет сокращения объема ПС (уменьшения количества машинных команд, количества строк и т.д.), снижение трудоемкости подготовки данных, обработки информации, анализа результатов, уменьшения расходов машинного времени и материалов.

Для определения экономического эффекта от использования нового ПС у потребителя необходимо сравнить расходы по всем основным статьям затрат на эксплуатацию нового ПС (расходы на заработную плату с начислениями, материалы, машинное время) с расходами по соответствующим статьям базового варианта. При этом за базовый вариант следует принимать аналогичное программное средство, используемое в действующей автоматизированной системе. При сравнении базового и нового вариантов ПС в качестве экономического эффекта будет выступать общая экономия всех видов ресурсов относительно базового варианта. При этом создание нового ПС окажется экономически целесообразным лишь в том случае, если все капитальные затраты окупятся за счет получаемой экономии в ближайшие 1–2 года.




6.3.1 Исходные данные



Таблица 6.3 – Исходные данные для сравнения вариантов

Наименование показателей

Обозначения

Единицы измерения

Значение показателя

Наименование источника информации







в базовом варианте

в новом варианте



Средняя трудоемкость работ в расчете на 100 строк кода

Тс1

Тс2

человеко-дней с на 100 строк кода

0,96

0,92

По данным пользователя

Средний расход машинного времени в расчете на 100 строк кода

Нмв1

Нмв2

машино-час на 100 строк кода

7,7

7,2

По данным пользователя

Средний расход материалов в расчете на

100 строк кода

См1

См2

руб. на 100 строк кода

341

266

По данным пользователя



Объем работ в зависимости от функциональной группы и назначения ПС определяется по формуле:



А = Vо' ∙ Кпс ,									(6.21)



где Vо' – скорректированный объем ПС, условных машино-команд;

Кпс – коэффициент применения ПС, ед.

Таким образом, A = 3633 * 0,7 = 2543 условных машинных команд



6.3.2 Расчет капитальных затрат заказчика ПС

Общие капитальные вложения заказчика (потребителя), связанные с приобретением, внедрением и использованием ПС, рассчитываются по формуле:



Ко = Кпр + Кос + Коб,								(6.22)




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

Кос – затраты пользователя на освоение ПС, руб.;

Коб – затраты на пополнение оборотных средств в связи с использованием нового ПС, руб.

Затраты на освоение ПС и на пополнение оборотных средств рекомендуется рассчитывать по формулам:



Кос = Кпр ∙ Нос ,									(6.23)

Коб = Кпр ∙ Ноб ,									(6.24)

Кпр = Цо = 1871108

Кос = 1871108 * 0,01 = 18711 руб.

Коб = 1871108 * 0,01 = 18711 руб.

Ко = 1871108 + 18711 + 18711 = 1908530 руб.



6.3.3 Расчет экономии основных видов ресурсов в связи с использованием нового ПС



Экономия затрат на заработную плату при использовании нового ПС в расчете на объем выполненных работ:



Эоз = Эоз' ∙ А,									(6.25)



где Эоз – экономия затрат на заработную плату при решении задач с использованием нового ПС, руб.;

Эоз' – экономия затрат на заработную плату при решении задач с использованием нового ПС в расчете на 100 КБ, руб.;

А – объем выполненных работ с использованием нового ПС, 100 КБ.

Экономия затрат на заработную плату в расчете на 100 КБ:

,								(6.26)



где Сзм – среднемесячная заработная плата одного программиста, руб.;

Тс1, Тс2 – трудоемкость работ в расчете на 100 строк кода при базовом и новом варианте соответственно, человеко-часов;

Тч – количество часов работы в день, ч;

ФРВ – фонд рабочего времени за месяц, ч.



Тс2 = 0,3*112*100/3633 = 0,92 человеко-дней

Эоз’ = 218680 * 0,04 / 169,3 = 52 руб.

Эоз = 52 * 2543 = 131389 руб.



При определении трудоемкости, связанной с использованием программы рекомендуется ориентироваться на показатель равный 30-50% от трудоемкости разработки в часах.

Экономия начислений на заработную плату при использовании нового ПС в расчете на объем выполненных работ:



Энач = Эоз ∙ Кнач ,									(6.27)



где Энач – экономия начислений на заработную плату при решении задач с использованием нового ПС, руб.;

Кнач – коэффициент начислений на заработную плату, ед.



,								(6.28)

Кнач = (34 + 1)/100 = 0,35 ед.

Энач = 131389 * 0,35 = 45986 руб.

Экономия затрат на оплату машинного времени в расчете на выполненный объем работ в результате применения нового ПС:



,										(6.29)



где Эмв – экономия затрат на оплату машинного времени при решении задач с использованием нового ПС, руб.;

 – экономия затрат на оплату машинного времени при решении задач с использованием нового ПС в расчете на 100 КБ, руб.

Экономия затрат на оплату машинного времени в расчете на 100 КБ:



,								(6.30)



где Нмв1, Нмв2 – средний расход машинного времени в расчете на 100 КБ при применении базового и нового варианта ПС соответственно, машино-часов.



Эмв’ = 2200 * 0,5 = 1100 руб.

Эмв = 1100 * 2543 = 2797300 руб.



Экономия затрат на материалы при использовании нового ПС в расчете на объем выполненных работ:



,										(6.31)



где Эм – экономия затрат на материалы при использовании нового ПС, руб.;

Эм' – экономия затрат на материалы в расчете на 100 КБ при использовании нового ПС, руб.:

,									(6.32)



где См1, См2 – средний расход материалов у пользователя в расчете на 100 КБ при использовании базового и нового варианта ПС соответственно, руб.



Эм’ = 341-266=75 руб.

Эм =75*2543 = 190725 руб.



Общая годовая экономия текущих затрат, связанных с использованием нового ПС:



,								(6.33)

Эо = 131389 + 45986 + 2797300 + 190725 = 3165400 руб.



6.3.4 Расчёт экономического эффекта

Внедрение нового ПС позволит пользователю сэкономить на текущих затратах, т.е. практически получить на эту сумму дополнительную прибыль. Для пользователя в качестве экономического эффекта выступает лишь чистая прибыль – дополнительная прибыль, остающаяся в его распоряжении (ΔПч), которая определяются по формуле:



,								(6.34)



где ∆Пч – прирост чистой прибыли, руб.;

Нмс – ставка местных налогов и сборов, %.



,									(6.35)

где ∆П – прирост прибыли, руб.;

Нп – ставка налога на прибыль, %.



= 3165400 – 3165400 * 24/100 = 2405704 руб.

= 2405704 – 2405704 * 3/100 = 2333533 руб.



В процессе использования нового ПС чистая прибыль в конечном итоге возмещает капитальные затраты. Однако, полученные при этом суммы результатов (прибыли) и затрат (капитальных вложений) по годам приводят к единому времени – расчетному году (за расчетный год принят 2008 год) путем умножения результатов и затрат за каждый год на коэффициент привидения (ALFAt), который рассчитывается по формуле:



, 								(6.36)



где Ен – норматив привидения разновременных затрат и результатов;

tp – расчетный год, tp = 1;

t – номер года, результаты и затраты которого приводятся к расчетному (2008-1, 2009-2, 2010-3, 2011-4).

Норматив приведения разновременных затрат и результатов (Ен) для программных средств ВТ в существующей практике принимается равным 0,12. При таком нормативе коэффициентам приведения (ALFAt) по годам будут соответствовать следующие значения:



ALPHA 1 = (1+0,15) 1-1 = 1

ALPHA 2 = (1+0,15) 1-2 = 0,870

ALPHA 3 = (1+0,15) 1-3 = 0,756

ALPHA 4 = (1+0,15) 1-4 = 0,658


Данные расчета экономического эффекта сведем в таблицу:



Таблица 6.4 - Расчет экономического эффекта от использования нового ПС

Показатели

Ед.

измерения

Методика расчета

2008

2009

2010

2011

Результаты:













Прирост прибыли за счет экономии затрат

руб.

∆ Пч

2333533

2333533

2333533

2333533

Сумма прибыли с учетом фактора времени

руб.

∆ Пч ∙ ALFAt

2333533

2030174

1764151

1535465

Затраты:













Затраты на приобретение ПС

руб.

Кпр

1871108

-

-

-

Затраты на освоение ПС

руб.

Кос

18711

-

-

-

Затраты на доукомплектование ВТ техническими средствами

руб.

Ктс

-

-

-

-

Затраты на пополнение оборотных средств

руб.

Коб

18711

18711

18711

18711

Сумма затрат

руб.

Ко

1908530

18711

18711

18711

Сумма затрат с учетом фактора времени

руб.

Ко ∙ ALFAt

1908530

16279

14146

12312

Экономический эффект

руб.

∆ Пч ∙ ALFAt -Ко ∙ ALFAt



425003



2013895

1750005

1523153

Экономический эффект с нарастающим итогом

руб.





425003

2438898

4188903

5712056

Коэффициент приведения

ед.

ALFAt

1

0,870

0,756

0,658



6.4 Результаты оценки экономической целесообразности



В данном разделе была рассчитана отпускная цена программного средства, которая составила 1871108 руб. Затраты потребителя, связанные с приобретением, освоением программного средства, а также пополнением оборотных средств – 1951267 руб. Прирост прибыли за счёт экономии начислений на заработную плату, оплаты машинного времени и материалов в каждый из расчётных лет составил соответственно 2333533 руб., 2030174 руб., 1764151 руб. и 1535465 руб. Затраты потребителя окупились уже в первый год, при этом получился положительный экономический эффект в размере 425003 руб. Экономический эффект за 4 года использования ПС составит 5712056 руб. Всё это даёт возможность говорить о том, что создание и внедрение ПС целесообразно.




Заключение



	В представленном дипломном проекте разработан графический редактор эффектов частиц “Easy Particles”.

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

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

	В ходе выполнения поставленной задачи реализованы все основные функции программного средства. Все предъявляемые к программе требования были выполнены. Отладка и тестирование программы проведены успешно.

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

	Цель, поставленная перед автором работы, была выполнена в полной мере. Проект выполнен в соответствие с ГОСТами и требованиями, предъявляемыми к технической документации.

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

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

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

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

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

	Некоторые изменения претерпит и оконная система приложения. В ней будут преобладать перетаскиваемые присоединяемые панели. Станет возможным изменение размеров окна вывода, а также использование полноэкранного режима при просмотре эффектов.

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

Перечисленные изменения должны повысить интерес к программному средству и его полезность для разных групп пользователей.




Список использованных источников



1) Бьёрн Страуструп Дизайн и эволюция языка C++ – М.: ДМК пресс, 2006. – 448с.

2) Ефремова О.С. Требования охраны труда при работе на персональных электронно-вычислительных машинах (ПК) – М.: Альфа-пресс, 2005. – 150с.

4) Санитарные нормы для образовательных учреждений . – 5-е изд., доп. – М.: Образование в документах, 2002. – 200с.

5) Замбржицкий О.Н. Гигиеническая оценка естественного и искусственного освещения помещений. – Мн.: БГМУ, 2005. – 18 с.

6) СанПиН N 9-131 РБ 2000 Гигиенические требования к видеодисплейным терминалам (ВДТ), электронно-вычислительным машинам (ЭВМ) и организации работы

7) Косилина Н.И., Колтановского А.П. Производственная гимнастика для работников умственного труда – М.: Физкультура и спорт, 1983.

8) Кляуззе В.П. Безопасность & компьютер. – Мн.: В.П.Кляуззе, 2001. – 155с.




Приложение А

(обязательное)



Текст программного модуля обработки частиц



//ParticleSystemChain.cpp (очередь эмиттеров)

#include "ParticleSystemChain.h"

#include "PSOutputFrame.h"//just for using canvas to get current reflecting mode ang zoom



#define BLEND_SRC "blend_src"

#define BLEND_DST "blend_dst"

#define ITEM_SELECTED "item_selected"

#define PSBOUND_SELECTED_COLOR wxColour(200, 200, 200, 255)

#define PSBOUNS_CHOOSED_COLOR wxColour(70, 70, 70, 255)

#define PSBOUND_COLOR wxColour(50, 50, 50, 255)



#define MIN_RUN_PSCHAIN_ITEM_DIMENSION 20



ParticleSystemChain *ParticleSystemChain::singletonChain = NULL;



ParticleSystemChain* ParticleSystemChain::Master()

{

if(!singletonChain)

singletonChain = new ParticleSystemChain();

return singletonChain;

}



void ParticleSystemChain::CleanSingleton()

{

if(singletonChain)

{

delete singletonChain;

singletonChain = NULL;

}

}



int ParticleSystemChain::AddSystem()

{

ParticleSystem* ps = new ParticleSystem();

 all_ps.push_back(ps);

if(workMode != ParticleSystemChainWorkMode_STATIC)

 ps->start();

int new_ps_layer = (int)all_ps.size() - 1;

if(selectedSystemLayer < 0)

selectedSystemLayer = new_ps_layer;

return new_ps_layer;

}



bool ParticleSystemChain::RemoveSystemAtLayer(int layer)

{

if( (layer < 0) || (layer >= (int)all_ps.size()) )

return false;



delete all_ps.at(layer);

all_ps.erase(all_ps.begin() + layer);

if(layer == choosedSystemLayer)

choosedSystemLayer = -1;

if(all_ps.size() == 0)

selectedSystemLayer = -1;

else

 if(selectedSystemLayer >= layer && selectedSystemLayer > 0)

 selectedSystemLayer--;

return true;

}



void ParticleSystemChain::RemoveAll()

{

vector<ParticleSystem*>::iterator iter = all_ps.begin();

while(iter != all_ps.end())

{

delete((ParticleSystem*)*iter);

++iter;

}

all_ps.clear();

selectedSystemLayer = choosedSystemLayer = -1;

}



void ParticleSystemChain::MoveSystem(int from, int to)

{

int numof_systems = (int)all_ps.size();

if( (from == to) || (from < 0) || (from >= numof_systems) || (to < 0) || (to >= numof_systems) )

return;



ParticleSystem *tmp_ps_ptr = all_ps.at(from);

all_ps.erase(all_ps.begin() + from);

all_ps.insert(all_ps.begin() + to, tmp_ps_ptr);

}



void ParticleSystemChain::CopySystemsData(int layer_from, int layer_to)

{

int numof_systems = (int)all_ps.size();

if(layer_from == layer_to || layer_from < 0 || layer_from >= numof_systems || layer_to < 0 || layer_to >= numof_systems )

return;



all_ps.at(layer_to)->copyDataFromParticleSystem(all_ps.at(layer_from));

}



bool ParticleSystemChain::Save(TiXmlElement* root) const

{

TiXmlElement tmp("BLENDING");

TiXmlElement *caption = (TiXmlElement*)root->InsertEndChild(tmp);

if(!caption)

return false;



caption->SetAttribute(BLEND_SRC, blendModeSrc);

caption->SetAttribute(BLEND_DST, blendModeDst);

return saveSystems(root);

}



bool ParticleSystemChain::Load(TiXmlElement *root)

{

TiXmlElement *blending_attrs_ptr = (TiXmlElement*)root->FirstChild("BLENDING");

if(!blending_attrs_ptr)//old version file (1.0), just set defaults

{

blendModeSrc = GL_ONE;

blendModeDst = GL_ONE_MINUS_SRC_ALPHA;

}

else

{

blending_attrs_ptr->Attribute(BLEND_SRC, &blendModeSrc);

blending_attrs_ptr->Attribute(BLEND_DST, &blendModeDst);

}

return loadSystems(root);

}



ParticleSystemOutputCoordCharacter ParticleSystemChain::AnalyseOutputCoords(MYPoint2D point) const

{

ParticleSystemOutputCoordCharacter res;

res.psLayer = -1;

res.isLeft = res.isRight = res.isTop = res.isBottom = false;



//first find selecting system layer

vector<ParticleSystem*>::const_iterator iter = all_ps.end();

vector<ParticleSystem*>::const_iterator begin_iter = all_ps.begin();

size_t i = all_ps.size();

wxRect system_rect, tmp_rect;

bool chain_is_run = (workMode != ParticleSystemChainWorkMode_STATIC);

while(iter != begin_iter)

{

--iter, --i;

wxRect tmp_rect;

MYPoint2D appear_box_position = MYPoint2DMake((*iter)->getX(), (*iter)->getY());

MYSize2D appear_box_size = (*iter)->getAppearBoxSize();

if(chain_is_run)

{

tmp_rect = wxRect(appear_box_position.x, appear_box_position.y, appear_box_size.width, appear_box_size.height);

if(tmp_rect.GetWidth() < MIN_RUN_PSCHAIN_ITEM_DIMENSION)

{

int diff = MIN_RUN_PSCHAIN_ITEM_DIMENSION - tmp_rect.GetWidth();

tmp_rect.SetX(tmp_rect.GetX() - diff / 2);

tmp_rect.SetWidth(MIN_RUN_PSCHAIN_ITEM_DIMENSION);

}

if(tmp_rect.GetHeight() < MIN_RUN_PSCHAIN_ITEM_DIMENSION)

{

int diff = MIN_RUN_PSCHAIN_ITEM_DIMENSION - tmp_rect.GetHeight();

tmp_rect.SetY(tmp_rect.GetY() - diff / 2);

tmp_rect.SetHeight(MIN_RUN_PSCHAIN_ITEM_DIMENSION);

}

}

else

tmp_rect = wxRect(appear_box_position.x - BOUND_DIMENSION, appear_box_position.y - BOUND_DIMENSION, 

 appear_box_size.width + BOUND_DIMENSION * 2, appear_box_size.height + BOUND_DIMENSION * 2);



 if(point.x >= tmp_rect.x && point.x < (tmp_rect.x + tmp_rect.width) &&

 point.y >= tmp_rect.y && point.y < (tmp_rect.y + tmp_rect.height) )

{

res.psLayer = (int)i;

system_rect = tmp_rect;

break;

}

}

if( res.psLayer == -1/*no selected ps*/ || chain_is_run )

return res;



//selecting system has been finded, and <!chainIsRun> - maybe we touched on some ps's bottom(-s)

 if( (point.x >= system_rect.x) && (point.x < system_rect.x + BOUND_DIMENSION) )

res.isLeft = true;

if( (point.x < system_rect.x + system_rect.width) && (point.x >= system_rect.x + system_rect.width - BOUND_DIMENSION) )

res.isRight = true;

if( (point.y >= system_rect.y) && (point.y < system_rect.y + BOUND_DIMENSION) )

res.isTop = true;

if( (point.y < system_rect.y + system_rect.height) && (point.y >= system_rect.y + system_rect.height - BOUND_DIMENSION) )

res.isBottom = true;

return res;

}



void ParticleSystemChain::ChooseSystemAtLayer(int layer)

{

if( (layer < 0) || (layer >= (int)all_ps.size()) )

choosedSystemLayer = -1;

else

 choosedSystemLayer = layer;

}



int ParticleSystemChain::GetChoosedSystemLayer() const

{

return choosedSystemLayer;

}



void ParticleSystemChain::SelectSystemAtLayer(int layer)

{

if( (layer < 0) || (layer >= (int)all_ps.size()) )

selectedSystemLayer = -1;

else

 selectedSystemLayer = layer;

}



int ParticleSystemChain::GetSelectedSystemLayer() const

{

return selectedSystemLayer;

}



ParticleSystemChainWorkMode ParticleSystemChain::GetWorkMode() const

{

return workMode;

}



void ParticleSystemChain::SetWorkMode(ParticleSystemChainWorkMode mode)

{

vector<ParticleSystem*>::iterator begin_iter = all_ps.begin();

vector<ParticleSystem*>::iterator end_iter = all_ps.end();

vector<ParticleSystem*>::iterator iter = begin_iter;

if(mode == ParticleSystemChainWorkMode_PLAYBACK || mode == ParticleSystemChainWorkMode_PLAYBACK_LOOP)

{

while(iter != end_iter)

{

(*iter)->start();

++iter;

}

timer.reset();

}

else//if(mode == ParticleSystemChainWorkMode_STATIC)

{

while(iter != end_iter)

{

(*iter)->stopExtra();

++iter;

}

}

workMode = mode;

}



void ParticleSystemChain::CallbackSystems()

{

if(workMode == ParticleSystemChainWorkMode_STATIC)

return;



double sec_interval = timer.getMilliseconds() / 1000.0;

timer.reset();

vector<ParticleSystem*>::iterator iter = all_ps.begin();

bool chain_is_run = false;

while(iter != all_ps.end())

{

(*iter)->callback(sec_interval);

if(!(*iter)->isFinished())

chain_is_run = true;

++iter;

}

if(chain_is_run)

return;



//!chain_is_run

if(workMode == ParticleSystemChainWorkMode_PLAYBACK)

SetWorkMode(ParticleSystemChainWorkMode_STATIC);

else// if(workMode == ParticleSystemChainWorkMode_PLAYBACK_LOOP)

SetWorkMode(ParticleSystemChainWorkMode_PLAYBACK_LOOP);//just restart

}



void ParticleSystemChain::DrawSystems()

{

vector<ParticleSystem*>::iterator iter = all_ps.begin();

if(workMode != ParticleSystemChainWorkMode_STATIC)

{

glEnable(GL_BLEND);

glBlendFunc(blendModeSrc, blendModeDst);

while(iter != all_ps.end())

{

(*iter)->draw();

++iter;

}

glDisable(GL_BLEND);

}

else

{

int i = 0;

while(iter != all_ps.end())

{

ParticleSystem* curr_ps = (*iter);

if(i == selectedSystemLayer)

curr_ps->setBoundColor(PSBOUND_SELECTED_COLOR);

else if(i == choosedSystemLayer)

curr_ps->setBoundColor(PSBOUNS_CHOOSED_COLOR);

else

curr_ps->setBoundColor(PSBOUND_COLOR);

curr_ps->drawBound();

++iter, ++i;

}

}

}



int ParticleSystemChain::GetBlendModeSrc() const

{

return blendModeSrc;

}



int ParticleSystemChain::GetBlendModeDst() const

{

return blendModeDst;

}



void ParticleSystemChain::SetBlendModeSrc(int mode)

{

blendModeSrc = mode;

}



void ParticleSystemChain::SetBlendModeDst(int mode)

{

blendModeDst = mode;

}



ParticleSystem* ParticleSystemChain::GetSystemAtLayer(int layer)

{

if( layer < 0 || layer >= (int)all_ps.size() )

return NULL;



return all_ps.at(layer);

}



MYRect ParticleSystemChain::GetInitialSystemsRect(unsigned int *systems_counter) const//systems bound rect on gl

{

*systems_counter = (unsigned int)all_ps.size();



double min_x = 0.0;

double min_y = 0.0;

double max_x = 0.0;

double max_y = 0.0;



vector<ParticleSystem*>::const_iterator begin_iter = all_ps.begin();

vector<ParticleSystem*>::const_iterator end_iter = all_ps.end();

vector<ParticleSystem*>::const_iterator iter = begin_iter;

while(iter != end_iter)

{

bool thereis_begin_ps = (iter == begin_iter);

if(thereis_begin_ps || min_x > (*iter)->data.initialX)

min_x = (*iter)->data.initialX;

if(thereis_begin_ps || min_y > (*iter)->data.initialY)

min_y = (*iter)->data.initialY;

double new_max = (*iter)->data.initialX + (*iter)->data.pAppearBoxSize.width;

if(thereis_begin_ps || max_x < new_max)

max_x = new_max;

new_max = (*iter)->data.initialY + (*iter)->data.pAppearBoxSize.height;

if(thereis_begin_ps || max_y < new_max)

max_y = new_max;

++iter;

}

MYPoint2D pos = MYPoint2DMake(min_x, min_y);

MYSize2D sz = MYSize2DMake(max_x - min_x, max_y - min_y);

return(MYRectMake(pos,sz));

}



int ParticleSystemChain::GetNumofSystems() const

{

return (int)all_ps.size();

}



//internals

ParticleSystemChain::ParticleSystemChain()

{

workMode = DEFAULT_PARTICLE_SYSTEM_CHAIN_WORK_MODE;

blendModeSrc = GL_ONE;

blendModeDst = GL_ONE_MINUS_SRC_ALPHA;

selectedSystemLayer = choosedSystemLayer = -1;

}



ParticleSystemChain::~ParticleSystemChain()

{

RemoveAll();

}



bool ParticleSystemChain::saveSystems(TiXmlElement* root) const

{

TiXmlElement tmp("SYSTEMS_DATA");

TiXmlElement *sys_data = (TiXmlElement*)root->InsertEndChild(tmp);

if(!sys_data)

return false;



sys_data->SetAttribute(ITEM_SELECTED, selectedSystemLayer);

if(all_ps.size() == 0)

return true;



vector<ParticleSystem*>::const_iterator iter = all_ps.end();

do

{

--iter;

if(!(*iter)->save(root))

return false;

}

while(iter != all_ps.begin());

return true;

}



bool ParticleSystemChain::loadSystems(TiXmlElement* root)

{

TiXmlElement *systems_data_ptr = (TiXmlElement*)root->FirstChild("SYSTEMS_DATA");

int selected_system_layer = -1;

if(systems_data_ptr)//new format file (ver. above 1.0)

systems_data_ptr->Attribute(ITEM_SELECTED, &selected_system_layer);

vector<ParticleSystem*> tmp_all_ps;

ParticleSystem *tmp_ps_ptr = new ParticleSystem();

while(bool is_success = tmp_ps_ptr->load(root))

{

tmp_all_ps.insert(tmp_all_ps.begin(), tmp_ps_ptr);

tmp_ps_ptr = new ParticleSystem();

}

delete tmp_ps_ptr;



if(tmp_all_ps.size() > 0 && selected_system_layer < 0)

selectedSystemLayer = 0;

else

 selectedSystemLayer = selected_system_layer;



//remove all old-created and add new

vector<ParticleSystem*>::iterator iter = all_ps.begin();

while(iter != all_ps.end())

{

delete((ParticleSystem*)*iter);

++iter;

}

all_ps.clear();

tmp_all_ps.swap(all_ps);

workMode = ParticleSystemChainWorkMode_STATIC;

return true;

}



//ParticleSystem.cpp (эмиттер)

#include "ParticleSystem.h"

#include "MYSpinCtrld.h"



#define PS_BOUNDED_RECT_COLOR wxColour(150, 150, 150, 255)



//XML element's attributes of PSs

#define TEXTURE_ATTR "texture_file_name"

#define LIFE_TIME_ATTR "life_time"

#define APPEAR_DELAY_ATTR "appear_delay"

#define PARTICLE_SPEED_X_ATTR "particle_speed_x"

#define PARTICLE_SPEED_Y_ATTR "particle_speed_y"

#define GRAVITY_X_ATTR "gravity_x"

#define GRAVITY_Y_ATTR "gravity_y"

#define MAX_COUNT_ATTR "max_count"

#define START_COUNT_ATTR "start_count"

#define APPEAR_BOX_W_ATTR "appear_box_w"

#define APPEAR_BOX_H_ATTR "appear_box_h"

#define RED_BEGIN_ATTR "red_begin"

#define RED_END_ATTR "red_end"

#define GREEN_BEGIN_ATTR "green_begin"

#define GREEN_END_ATTR "green_end"

#define BLUE_BEGIN_ATTR "blue_begin"

#define BLUE_END_ATTR "blue_end"

#define ALPHA_BEGIN_ATTR "alpha_begin"

#define ALPHA_END_ATTR "alpha_end"

#define SCALE_BEGIN_W_ATTR "scale_begin_w"

#define SCALE_BEGIN_H_ATTR "scale_begin_h"

#define SCALE_END_W_ATTR "scale_end_w"

#define SCALE_END_H_ATTR "scale_end_h"

#define DISPERSION_X_ATTR "dispersion_x"

#define DISPERSION_Y_ATTR "dispersion_y"

#define PS_X_ATTR "ps_x"

#define PS_Y_ATTR "ps_y"

#define PS_SPEED_X_ATTR "ps_speed_x"

#define PS_SPEED_Y_ATTR "ps_speed_y"

#define START_DELAY_ATTR "start_delay"

#define STOP_DELAY_ATTR "stop_delay"

#define ROTATE_ATTR "rotate"





//ctors, destructors, ...

ParticleSystem::ParticleSystem()

{

data.pLifeTime= 1.0;

data.pMaxCount = EXPL_MAX;

data.pCountOnStart = 1;

data.pGravityX = data.pGravityY = 0.0;



//p.speed, dispersion page

data.pMoveSpeedX = 0.0;

data.pMoveSpeedY = 0.0;

data.pKFDispersionX = 0.0;

data.pKFDispersionY = 0.0;



//p.scale page

data.pKFScaleBeginW = 1.0;

data.pKFScaleBeginH = 1.0;

data.pKFScaleEndW = 1.0;

data.pKFScaleEndH = 1.0;



//p.color page

data.pRedBegin = 1.0;

data.pGreenBegin = 1.0;

data.pBlueBegin = 1.0;

data.pAlphaBegin = 1.0;

data.pRedEnd = 1.0;

data.pGreenEnd = 1.0;

data.pBlueEnd = 1.0;

data.pAlphaEnd = 1.0;



//rotate

data.pAngleRotate = 0.0;



//start in, stop in page

data.startDelay = 0.0;

data.stopDelay = 1800.0;

data.pAppearDelay = 0.0;



//PS settings page

MYSize2D sz = {100.0,100.0};

data.pAppearBoxSize = sz;



data.speedChangeX = 0;

data.speedChangeY = 0;



data.initialX = currentX = BOUND_DIMENSION;

data.initialY = currentY = BOUND_DIMENSION;



boundedRectColor = PS_BOUNDED_RECT_COLOR;



particleTexPtr = NULL;

setDefaultParticleTex();



isRunb = false;

isFinishedb = false;



viewMatrixCache = (GLdouble*)malloc(sizeof(GLdouble) * 16);

assert(viewMatrixCache != NULL);

}



ParticleSystem::~ParticleSystem()

{

free(viewMatrixCache);

if(particleTexPtr)

delete particleTexPtr;

}



int ParticleSystem::setParticleTex(const wxString &texture_path)

{

MYTexture* tmp_tex = new MYTexture(texture_path);

int res = tmp_tex->getState();

if(res != TEX_OK)

{

delete tmp_tex;

return res;

}



if(particleTexPtr)

delete particleTexPtr;

particleTexPtr = tmp_tex;

data.particleTexFileName = texture_path;

MYTexCoordPoint *ptrTex = texCoord;

for(int i = 0; i < EXPL_MAX; i++)

{

ptrTex->x = 0.0; ptrTex->y = 0.0;

ptrTex++;

ptrTex->x = particleTexPtr->getMaxS(); ptrTex->y = 0.0; 

ptrTex++;

ptrTex->x = particleTexPtr->getMaxS(); ptrTex->y = particleTexPtr->getMaxT(); 

ptrTex++;



ptrTex->x = 0.0; ptrTex->y = 0.0; 

ptrTex++;

ptrTex->x = particleTexPtr->getMaxS(); ptrTex->y = particleTexPtr->getMaxT();

ptrTex++;

ptrTex->x = 0.0; ptrTex->y = particleTexPtr->getMaxT();

ptrTex++;

}

return TEX_OK;

}



void ParticleSystem::setDefaultParticleTex()

{

if(particleTexPtr)

delete particleTexPtr;

GLubyte *buffer = new GLubyte[8 * 8 * 4];

memset(buffer, 255, 8*8*4);//white colour

particleTexPtr = new MYTexture(32,16711680/*third byte pattern*/,65280/*second byte pattern*/,255/*first byte pattern*/

,8,8,buffer);

delete[] buffer;

data.particleTexFileName = wxString("");

}



double ParticleSystem::getX() const

{

return currentX;

}



double ParticleSystem::getY() const

{

return currentY;

}



void ParticleSystem::setX(double x)

{

data.initialX = currentX = x;

}



void ParticleSystem::setY(double y)

{

data.initialY = currentY = y;

}



double ParticleSystem::getSpeedChangeX() const

{

return data.speedChangeX;

}



double ParticleSystem::getSpeedChangeY() const

{

return data.speedChangeY;

}



void ParticleSystem::setSpeedChangeX(double speed)

{

data.speedChangeX = speed;

}



void ParticleSystem::setSpeedChangeY(double speed)

{

data.speedChangeY = speed;

}



double ParticleSystem::getStopDelay() const

{

return data.stopDelay;

}



double ParticleSystem::getStartDelay() const

{

return data.startDelay;

}



void ParticleSystem::setStopDelay(double time)

{

data.stopDelay = time;

}



void ParticleSystem::setStartDelay(double time)

{

data.startDelay = time;

}



double ParticleSystem::getLifeTime() const

{

return data.pLifeTime;

}



void ParticleSystem::setLifeTime(double time)

{

data.pLifeTime = time;

}



double ParticleSystem::getParticleAppearDelay() const

{

return data.pAppearDelay;

}



void ParticleSystem::setParticleAppearDelay(double time)

{

data.pAppearDelay = time;

}



double ParticleSystem::getMoveSpeedX() const

{

return data.pMoveSpeedX;

}



double ParticleSystem::getMoveSpeedY() const

{

return data.pMoveSpeedY;

}



void ParticleSystem::setMoveSpeedX(double speed)

{

data.pMoveSpeedX = speed;

}



void ParticleSystem::setMoveSpeedY(double speed)

{

data.pMoveSpeedY = speed;

}



double ParticleSystem::getGravityX() const

{

return data.pGravityX;

}



double ParticleSystem::getGravityY() const

{

return data.pGravityY;

}



void ParticleSystem::setGravityX(double gravity)

{

data.pGravityX = gravity;

}



void ParticleSystem::setGravityY(double gravity)

{

data.pGravityY = gravity;

}



int ParticleSystem::getMaxCount() const

{

return data.pMaxCount;

}



void ParticleSystem::setMaxCount(int count)

{

data.pMaxCount = count;

if(data.pCountOnStart > data.pMaxCount)

data.pCountOnStart = data.pMaxCount;

}



int ParticleSystem::getCountOnStart() const

{

return data.pCountOnStart;

}



void ParticleSystem::setCountOnStart(int count)

{

data.pCountOnStart = count;

}



MYSize2D ParticleSystem::getAppearBoxSize() const

{

return data.pAppearBoxSize;

}



void ParticleSystem::setAppearBoxSize(MYSize2D box)

{

data.pAppearBoxSize = box;

}



double ParticleSystem::getRedBegin() const

{

return data.pRedBegin;

}



double ParticleSystem::getGreenBegin() const

{

return data.pGreenBegin;

}



double ParticleSystem::getBlueBegin() const

{

return data.pBlueBegin;

}



double ParticleSystem::getAlphaBegin() const

{

return data.pAlphaBegin;

}



void ParticleSystem::setRedBegin(double red)

{

data.pRedBegin = red;

}



void ParticleSystem::setGreenBegin(double green)

{

data.pGreenBegin = green;

}



void ParticleSystem::setBlueBegin(double blue)

{

data.pBlueBegin = blue;

}



void ParticleSystem::setAlphaBegin(double alpha)

{

data.pAlphaBegin = alpha;

}



double ParticleSystem::getRedEnd() const

{

return data.pRedEnd;

}



double ParticleSystem::getGreenEnd() const

{

return data.pGreenEnd;

}



double ParticleSystem::getBlueEnd() const

{

return data.pBlueEnd;

}



double ParticleSystem::getAlphaEnd() const

{

return data.pAlphaEnd;

}



void ParticleSystem::setRedEnd(double red)

{

data.pRedEnd = red;

}



void ParticleSystem::setGreenEnd(double green)

{

data.pGreenEnd = green;

}



void ParticleSystem::setBlueEnd(double blue)

{

data.pBlueEnd = blue;

}



void ParticleSystem::setAlphaEnd(double alpha)

{

data.pAlphaEnd = alpha;

}



double ParticleSystem::getRotateAngle() const

{

return data.pAngleRotate;

}



void ParticleSystem::setRotateAngle(double angle)

{

data.pAngleRotate = angle;

}



double ParticleSystem::getKFScaleBeginW() const

{

return data.pKFScaleBeginW;

}



double ParticleSystem::getKFScaleBeginH() const

{

return data.pKFScaleBeginH;

}



void ParticleSystem::setKFScaleBeginW(double scale)

{

data.pKFScaleBeginW = scale;

}



void ParticleSystem::setKFScaleBeginH(double scale)

{

data.pKFScaleBeginH = scale;

}



double ParticleSystem::getKFScaleEndW() const

{

return data.pKFScaleEndW;

}



double ParticleSystem::getKFScaleEndH() const

{

return data.pKFScaleEndH;

}



void ParticleSystem::setKFScaleEndW(double scale)

{

data.pKFScaleEndW = scale;

}



void ParticleSystem::setKFScaleEndH(double scale)

{

data.pKFScaleEndH = scale;

}



double ParticleSystem::getKFDispersionX() const

{

return data.pKFDispersionX;

}



double ParticleSystem::getKFDispersionY() const

{

return data.pKFDispersionY;

}



void ParticleSystem::setKFDispersionX(double disp)

{

data.pKFDispersionX = disp;

}



void ParticleSystem::setKFDispersionY(double disp)

{

data.pKFDispersionY = disp;

}



wxString ParticleSystem::getParticleTexFileName() const

{

return data.particleTexFileName;

}



void ParticleSystem::copyDataFromParticleSystem(ParticleSystem* sys_from)

{

if(!sys_from)

return;



data.pLifeTime = sys_from->data.pLifeTime;

data.pMaxCount = sys_from->data.pMaxCount;

data.pCountOnStart = sys_from->data.pCountOnStart;

data.pGravityX = sys_from->data.pGravityX;

data.pGravityY = sys_from->data.pGravityY;



//p.speed, dispersion page

data.pMoveSpeedX = sys_from->data.pMoveSpeedX;

data.pMoveSpeedY = sys_from->data.pMoveSpeedY;

data.pKFDispersionX = sys_from->data.pKFDispersionX;

data.pKFDispersionY = sys_from->data.pKFDispersionY;



//p.scale page

data.pKFScaleBeginW = sys_from->data.pKFScaleBeginW;

data.pKFScaleBeginH = sys_from->data.pKFScaleBeginH;

data.pKFScaleEndW = sys_from->data.pKFScaleEndW;

data.pKFScaleEndH = sys_from->data.pKFScaleEndH;



//p.color page

data.pRedBegin = sys_from->data.pRedBegin;

data.pGreenBegin = sys_from->data.pGreenBegin;

data.pBlueBegin = sys_from->data.pBlueBegin;

data.pAlphaBegin = sys_from->data.pAlphaBegin;

data.pRedEnd = sys_from->data.pRedEnd;

data.pGreenEnd = sys_from->data.pGreenEnd;

data.pBlueEnd = sys_from->data.pBlueEnd;

data.pAlphaEnd = sys_from->data.pAlphaEnd;



//rotate

data.pAngleRotate = sys_from->data.pAngleRotate;



//start in, stop in page

data.startDelay = sys_from->data.startDelay;

data.stopDelay = sys_from->data.stopDelay;

data.pAppearDelay = sys_from->data.pAppearDelay;



//PS settings page

data.pAppearBoxSize = sys_from->data.pAppearBoxSize;



data.speedChangeX = sys_from->data.speedChangeX;

data.speedChangeY = sys_from->data.speedChangeY;



setX(sys_from->data.initialX);

setY(sys_from->data.initialY);



if(sys_from->data.particleTexFileName == "")

setDefaultParticleTex();

else

setParticleTex(sys_from->data.particleTexFileName);

}



bool ParticleSystem::isRun() const

{

return isRunb;

}



bool ParticleSystem::isFinished() const

{

return isFinishedb;

}



void ParticleSystem::start()

{

isRunb = true;

isFinishedb = false;

restart();

}



void ParticleSystem::stop()

{

isRunb = false;

}



void ParticleSystem::stopExtra()

{

isRunb = false;

finish();

}



void ParticleSystem::finish()

{

isFinishedb = true;

currentX = data.initialX;

currentY = data.initialY;

}



void ParticleSystem::restart()

{

startInTime = data.startDelay;

stopInTime = data.stopDelay;

timeForNextParticle = data.pAppearDelay;

int count = data.pCountOnStart;

for (int i=0; i<EXPL_MAX; i++)

{

if (count > 0)

{

initParticleAtIndex(i);

count--;

}

else

{

pTM[i] = 0;

}

}

}



void ParticleSystem::initParticleAtIndex(int i)

{

assert(i >= 0 && i < EXPL_MAX);



pTM[i] = data.pLifeTime;



pX[i] = fmod(rand(), data.pAppearBoxSize.width);

pY[i] = fmod(rand(), data.pAppearBoxSize.height);



double speedDeltaX = fmod(rand(), data.pKFDispersionX * 2 + 1) - data.pKFDispersionX;

pDx[i] = data.pMoveSpeedX + speedDeltaX;



double speedDeltaY = fmod(rand(), data.pKFDispersionY * 2 + 1) - data.pKFDispersionY;

pDy[i] = data.pMoveSpeedY + speedDeltaY;

}



void ParticleSystem::drawBound()

{

double appear_w = data.pAppearBoxSize.width;

double appear_h = data.pAppearBoxSize.height;



//draw bound itself

glColor4d(boundColor.Red()/255.0, boundColor.Green()/255.0, boundColor.Blue()/255.0, boundColor.Alpha()/255.0);

glBegin(GL_POLYGON);

glVertex2d(currentX - BOUND_DIMENSION, currentY - BOUND_DIMENSION);

glVertex2d(currentX + appear_w + BOUND_DIMENSION, currentY - BOUND_DIMENSION);

glVertex2d(currentX + appear_w + BOUND_DIMENSION, currentY + appear_h + BOUND_DIMENSION);

glVertex2d(currentX - BOUND_DIMENSION, currentY + appear_h + BOUND_DIMENSION);

glEnd();



//draw inner part of bound

glColor4d(boundedRectColor.Red()/255.0, boundedRectColor.Green()/255.0, boundedRectColor.Blue()/255.0,

 boundedRectColor.Alpha()/255.0);



glBegin(GL_POLYGON);

glVertex2d(currentX, currentY);

glVertex2d(currentX + appear_w, currentY);

glVertex2d(currentX + appear_w, currentY + appear_h);

glVertex2d(currentX, currentY + appear_h);

glEnd();

if(!particleTexPtr)

return;



//draw texture on left-top

double tex_w = particleTexPtr->getWidth();

double tex_h = particleTexPtr->getHeight();

glEnable(GL_TEXTURE_2D);

GLint binded;

glGetIntegerv(GL_TEXTURE_BINDING_2D,&binded);

glBindTexture(GL_TEXTURE_2D, particleTexPtr->getName());

glColor4d(1.0,1.0,1.0,1.0);



double real_tex_w, real_tex_h;

 real_tex_w = min(appear_w, tex_w);

real_tex_h = min(appear_h, tex_h);

double real_tex_s, real_tex_t;

real_tex_s = particleTexPtr->getMaxS() * ((double)real_tex_w) / ((double)tex_w);

real_tex_t = particleTexPtr->getMaxT() * ((double)real_tex_h) / ((double)tex_h);



glBegin(GL_POLYGON);

glTexCoord2d(0.0, 0.0);

glVertex2d(currentX, currentY);

glTexCoord2d(real_tex_s, 0.0);//texCoord[0].x,texCoord[0].y);

glVertex2d(currentX + real_tex_w, currentY);

glTexCoord2d(real_tex_s, real_tex_t);//texCoord[1].x,texCoord[1].y);

glVertex2d(currentX + real_tex_w, currentY + real_tex_h);

glTexCoord2d(0.0, real_tex_t);

glVertex2d(currentX, currentY + real_tex_h);

glEnd();



glBindTexture(GL_TEXTURE_2D, binded);

glDisable(GL_TEXTURE_2D);

}



void ParticleSystem::draw()

{

if(!particleTexPtr)

return;



if (isFinishedb)

return;



//if (int(startInTime*maj_kof) > 0)

if(startInTime > 0.0)

return;



glMatrixMode(GL_MODELVIEW);



MYPoint2D *ptrVert = verCoord;

MYParticleColor *ptrColor = color;

int count = 0;

double progress, x, y, w, h, r, g, b, a;

bool is_rotate = (data.pAngleRotate != 0.0);

for (int i = 0; i < EXPL_MAX; ++i)

{

progress = pTM[i];

x = pX[i];

y = pY[i];

if(progress > 0.0)

{

progress /= data.pLifeTime;



w = (data.pKFScaleEndW + progress * (data.pKFScaleBeginW - data.pKFScaleEndW)) * particleTexPtr->getWidth();

h = (data.pKFScaleEndH + progress * (data.pKFScaleBeginH - data.pKFScaleEndH)) * particleTexPtr->getHeight();



if(is_rotate)

{

double real_alpha = fmod(data.pAngleRotate * 360.0 * progress, 360.0);

glPushMatrix();

glTranslated(x, y, 0.0);

glRotated(real_alpha, 0.0, 0.0, 1.0);//clock wise direction

x = y = 0.0;

}



x -= w/2.0;//only CENTERS of particles initially placed in AppearingBox (0.5,0.5 origin)

y -= h/2.0;//only CENTERS of particles initially placed in AppearingBox (0.5,0.5 origin)



r = data.pRedEnd + progress * (data.pRedBegin - data.pRedEnd);

g = data.pGreenEnd + progress * (data.pGreenBegin - data.pGreenEnd);

b = data.pBlueEnd + progress * (data.pBlueBegin - data.pBlueEnd);

a = data.pAlphaEnd + progress * (data.pAlphaBegin - data.pAlphaEnd);



ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;

ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;

ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;

ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;

ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;

ptrColor->r = r; ptrColor->g = g; ptrColor->b = b; ptrColor->a = a; ptrColor++;



if(is_rotate)

{

double* m = viewMatrixCache;

glGetDoublev(GL_MODELVIEW_MATRIX, m);

double x2 = x + w;

double y2 = y + h;

double* tp = (double*)ptrVert;



ptrVert->x = m[0]*x + m[4]*y + m[12];ptrVert->y = m[1]*x + m[5]*y + m[13];ptrVert++;

ptrVert->x = m[0]*x2 + m[4]*y + m[12];ptrVert->y = m[1]*x2 + m[5]*y + m[13];ptrVert++;

ptrVert->x = m[0]*x2 + m[4]*y2 + m[12];ptrVert->y = m[1]*x2 + m[5]*y2 + m[13]; ptrVert++;

ptrVert->x = tp[0]; ptrVert->y = tp[1]; ptrVert++;

ptrVert->x = tp[4]; ptrVert->y = tp[5]; ptrVert++;

ptrVert->x = m[0]*x + m[4]*y2 + m[12];ptrVert->y = m[1]*x + m[5]*y2 + m[13];ptrVert++;



glPopMatrix();

}

else

{

ptrVert->x = x;ptrVert->y = y;ptrVert++;

ptrVert->x = x+w;ptrVert->y = y;ptrVert++;

ptrVert->x = x+w;ptrVert->y = y+h;ptrVert++;

ptrVert->x = x;ptrVert->y = y;ptrVert++;

ptrVert->x = x+w;ptrVert->y = y+h;ptrVert++;

ptrVert->x = x;ptrVert->y = y+h;ptrVert++;

}



count++;

}

}



glPushMatrix();

glTranslated(currentX, currentY, 0.0);



glEnable(GL_TEXTURE_2D);

GLint binded;

glGetIntegerv(GL_TEXTURE_BINDING_2D,&binded);

glBindTexture(GL_TEXTURE_2D, particleTexPtr->getName());



glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(2, GL_DOUBLE, 0, verCoord);



glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glTexCoordPointer(2, GL_DOUBLE, 0, texCoord);



glEnableClientState(GL_COLOR_ARRAY);

glColorPointer(4, GL_DOUBLE, 0, color);



glDrawArrays(GL_TRIANGLES, 0, count*6);



glDisableClientState(GL_COLOR_ARRAY);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

glDisableClientState(GL_VERTEX_ARRAY);



glBindTexture(GL_TEXTURE_2D,binded);

glDisable(GL_TEXTURE_2D);



glPopMatrix();

}



bool ParticleSystem::save(TiXmlElement* root_ptr) const

{

TiXmlElement element("PS");



element.SetAttribute(TEXTURE_ATTR, data.particleTexFileName);

element.SetDoubleAttribute(LIFE_TIME_ATTR, data.pLifeTime);

element.SetDoubleAttribute(APPEAR_DELAY_ATTR, data.pAppearDelay);

element.SetDoubleAttribute(PARTICLE_SPEED_X_ATTR, data.pMoveSpeedX);

element.SetDoubleAttribute(PARTICLE_SPEED_Y_ATTR, data.pMoveSpeedY);

element.SetDoubleAttribute(GRAVITY_X_ATTR, data.pGravityX);

element.SetDoubleAttribute(GRAVITY_Y_ATTR, data.pGravityY);

element.SetAttribute(MAX_COUNT_ATTR, data.pMaxCount);

element.SetAttribute(START_COUNT_ATTR, data.pCountOnStart);

element.SetDoubleAttribute(APPEAR_BOX_W_ATTR, data.pAppearBoxSize.width);

element.SetDoubleAttribute(APPEAR_BOX_H_ATTR, data.pAppearBoxSize.height);

element.SetDoubleAttribute(RED_BEGIN_ATTR, data.pRedBegin);

element.SetDoubleAttribute(RED_END_ATTR, data.pRedEnd);

element.SetDoubleAttribute(GREEN_BEGIN_ATTR, data.pGreenBegin);

element.SetDoubleAttribute(GREEN_END_ATTR, data.pGreenEnd);

element.SetDoubleAttribute(BLUE_BEGIN_ATTR, data.pBlueBegin);

element.SetDoubleAttribute(BLUE_END_ATTR, data.pBlueEnd);

element.SetDoubleAttribute(ALPHA_BEGIN_ATTR, data.pAlphaBegin);

element.SetDoubleAttribute(ALPHA_END_ATTR, data.pAlphaEnd);

element.SetDoubleAttribute(SCALE_BEGIN_W_ATTR, data.pKFScaleBeginW);

element.SetDoubleAttribute(SCALE_BEGIN_H_ATTR, data.pKFScaleBeginH);

element.SetDoubleAttribute(SCALE_END_W_ATTR, data.pKFScaleEndW);

element.SetDoubleAttribute(SCALE_END_H_ATTR, data.pKFScaleEndH);

element.SetDoubleAttribute(DISPERSION_X_ATTR, data.pKFDispersionX);

element.SetDoubleAttribute(DISPERSION_Y_ATTR, data.pKFDispersionY);

element.SetDoubleAttribute(PS_X_ATTR, data.initialX);

element.SetDoubleAttribute(PS_Y_ATTR, data.initialY);

element.SetDoubleAttribute(PS_SPEED_X_ATTR, data.speedChangeX);

element.SetDoubleAttribute(PS_SPEED_Y_ATTR, data.speedChangeY);

element.SetDoubleAttribute(START_DELAY_ATTR, data.startDelay);

element.SetDoubleAttribute(STOP_DELAY_ATTR, data.stopDelay);

element.SetDoubleAttribute(ROTATE_ATTR, data.pAngleRotate);



TiXmlElement* ptr_element = (TiXmlElement*)root_ptr->InsertEndChild(element);

return((bool)(ptr_element != NULL));

}



bool ParticleSystem::load(TiXmlElement*& element_ptr)

{

TiXmlElement *next_element_ptr = (TiXmlElement*)element_ptr->FirstChild("PS");

if(!next_element_ptr)

{

next_element_ptr = (TiXmlElement*)element_ptr->NextSibling("PS");

 if(!next_element_ptr)

 return false;

}



//read version 1.1 parameters

if(next_element_ptr->QueryIntAttribute(MAX_COUNT_ATTR, &data.pMaxCount) != TIXML_SUCCESS)

data.pMaxCount = EXPL_MAX;



//read all version parameters (obligatory)

if(next_element_ptr->QueryIntAttribute(START_COUNT_ATTR, &data.pCountOnStart) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(LIFE_TIME_ATTR, &data.pLifeTime) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(APPEAR_DELAY_ATTR, &data.pAppearDelay) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PARTICLE_SPEED_X_ATTR, &data.pMoveSpeedX) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PARTICLE_SPEED_Y_ATTR, &data.pMoveSpeedY) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(GRAVITY_X_ATTR, &data.pGravityX) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(GRAVITY_Y_ATTR, &data.pGravityY) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(APPEAR_BOX_W_ATTR, &data.pAppearBoxSize.width) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(APPEAR_BOX_H_ATTR, &data.pAppearBoxSize.height) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(RED_BEGIN_ATTR, &data.pRedBegin) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(RED_END_ATTR, &data.pRedEnd) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(GREEN_BEGIN_ATTR, &data.pGreenBegin) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(GREEN_END_ATTR, &data.pGreenEnd) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(BLUE_BEGIN_ATTR, &data.pBlueBegin) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(BLUE_END_ATTR, &data.pBlueEnd) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(ALPHA_BEGIN_ATTR, &data.pAlphaBegin) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(ALPHA_END_ATTR, &data.pAlphaEnd) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(SCALE_BEGIN_W_ATTR, &data.pKFScaleBeginW) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(SCALE_BEGIN_H_ATTR, &data.pKFScaleBeginH) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(SCALE_END_W_ATTR, &data.pKFScaleEndW) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(SCALE_END_H_ATTR, &data.pKFScaleEndH) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(DISPERSION_X_ATTR, &data.pKFDispersionX) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(DISPERSION_Y_ATTR, &data.pKFDispersionY) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PS_X_ATTR, &data.initialX) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PS_Y_ATTR, &data.initialY) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PS_SPEED_X_ATTR, &data.speedChangeX) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(PS_SPEED_Y_ATTR, &data.speedChangeY) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(START_DELAY_ATTR, &data.startDelay) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(STOP_DELAY_ATTR, &data.stopDelay) != TIXML_SUCCESS ||

 next_element_ptr->QueryDoubleAttribute(ROTATE_ATTR, &data.pAngleRotate) != TIXML_SUCCESS)

return false;



currentX = data.initialX;

currentY = data.initialY;

setParticleTex(next_element_ptr->Attribute(TEXTURE_ATTR));

element_ptr = next_element_ptr;

return true;

}



void ParticleSystem::callback(double sec_interval)

{

if(isFinishedb)

return;



//check for startInTime

startInTime -= sec_interval;

//if (((int)startInTime*maj_kof) > 0)

if(startInTime > 0.0)

return;

else

startInTime = 0.0;



//change DX DY

currentX += data.speedChangeX* sec_interval;

currentY += data.speedChangeY* sec_interval;



//check for the next particle

timeForNextParticle -= sec_interval;

double addParticleTime = 1.0;

if (timeForNextParticle <= 0.0)

{

addParticleTime = timeForNextParticle;

timeForNextParticle = data.pAppearDelay;

}



bool need_to_finish = true;

if(isRunb)

{

need_to_finish = false;

stopInTime -= sec_interval;

//if (((int)stopInTime*maj_kof) <= 0)

if(stopInTime <= 0.0)

stop();

}



//calculate entire number of particles alive

int curr_numof_particles = 0;

for(int i=0; i<EXPL_MAX; i++)

if(pTM[i] > 0.0)

 ++curr_numof_particles;



//process particles

for (int i=0; i<EXPL_MAX; i++)

{

pTM[i] -= sec_interval;

if (pTM[i] <= 0.0) 

{

if (addParticleTime <= 0.0 && curr_numof_particles < data.pMaxCount && isRunb)

{

//add new particle

addParticleTime += data.pAppearDelay;

++curr_numof_particles;

initParticleAtIndex(i);

}

}

else

{

need_to_finish = false;



pX[i] += sec_interval * pDx[i];

pY[i] += sec_interval * pDy[i];

pDx[i] += sec_interval * data.pGravityX;

pDy[i] += sec_interval * data.pGravityY;

}

}

if(need_to_finish)

finish();

}



void ParticleSystem::setBoundColor(wxColour color)

{

boundColor = color;

}



wxColour ParticleSystem::getBoundColor()

{

return boundColor;

}