openFrameworks — это обёртка С++ классов вокруг нескольких библиотек, т.е. что-то вроде клея для соединения этих библиотек в единое целое:
* OpenGL — для отображения графики
* FreeImage — для манипуляций с изображениями
* Freetype — для отображения и работы со шрифтами
* rtAudio — для аудио
* Quicktime (mac или pc) — для проигрывания видео и видеозахвата
Ключевые концепции openFrameworks:
* упрощение вещей.
* вы можете использовать любую из его частей независимо от других.
* предоставление прямого доступа к данным; например, пиксели изображения.
OpenFrameworks предназначен для «творческого кодинга» («creative coding») и может работать под Windows, MacOS X и Linux.
тип лицензии: MIT
чтобы работать с OpenFrameworks нужно иметь установленный VS C++ 2008
(да, по сравнению с Processing, где всё идёт в комплекте — это минус).
Скачиваем zip-архив с OpenFrameworks.
Обратите внимание, что OpenFrameworks выкладывается в двух версиях.
Простой и «толстой» (FAT); в последней содержатся дополнительные примеры (например, работа с OpenCV).
of_preRelease_v0061_vs2008_FAT.zip
Полученый архив нужно просто распаковать в удобную директорию
Например:
c:\DevTools\of_preRelease_v0061_vs2008_FAT\
и всё. Можно смотреть примеры.
Переходим в
\apps\examples\
, выбираем понравившийся проект, открываем директорию и запускаем .vcproj
Запустится VS C++ и теперь остаётся только запустить сборку проекта.
Создание нового openFrameworks-проекта
В readme описан процесс создания нового OpenFrameworks-проекта
и состоит он в копировании тестового пустого проекта в проект с новым названием:
a) скопируйте директорию внутри apps и вставьте в ту же самую директорию
т.е. (скопируйте «emptyExample» и вставьте «копия emptyExample»)
b) переименуйте получившуюся директорию, а внутри директории, переименуйте файлы .vcproj и .sln
т.е. переименуйте:
emptyExample.vcproj
в
coolExample.vcproj
c) откройте файл .vcproj в текстовом редакторе. измените старое название проекта на новое:
например, если скопировали emptyExample и хотите назвать его "coolExample" ,то файл должен выглядеть так:
в solution-файле, измените название .vcproj -файла:
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emptyExample", "emptyExample.vcproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" ProjectSection(ProjectDependencies) = postProject {5837595D-ACA9-485C-8E76-729040CE4B0B} = {5837595D-ACA9-485C-8E76-729040CE4B0B} EndProjectSection EndProjectна название, которое вы дали своему файлу:
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "coolExample", "coolExample.vcproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" ProjectSection(ProjectDependencies) = postProject {5837595D-ACA9-485C-8E76-729040CE4B0B} = {5837595D-ACA9-485C-8E76-729040CE4B0B} EndProjectSection EndProjectОбратите внимание, что в OpenFrameworks уже реализвано общение с контроллером Arduino по протоколу Firmata.
см. примерapps\examples\firmataExample\работа осуществляется через класс ofArduino (который, соответственно, использует класс ofSerial)
см.libs\openFrameworks\communication\пример OpenCV находится в дополнительных примерах, которые идут в расширенной ("толстой") версии OpenFrameworks:
apps\addonsExamples\opencvExample\поддержка OpenCV реализована в виде аддона:
addons\ofxOpenCv\и по версии используемых lib-файлов
addons\ofxOpenCv\libs\opencv\lib\vs2008\, используется версия OpenCV 1.1
openFrameworks и Arduino
Рассмотрим работу примера общения с Arduino в примере firmataExample, заодно поймём как нужно работать в OpenFrameworks.
Запустим проект
apps\examples\firmataExample\Он состоит из трёх файлов:
main.cpp
testApp.h
testApp.cppсодержимое main.cpp:
#include "ofMain.h" #include "testApp.h" #include "ofAppGlutWindow.h" //======================================================================== int main( ){ ofAppGlutWindow window; ofSetupOpenGL(&window, 800,600, OF_WINDOW); // <-------- setup the GL context // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp( new testApp()); }Кажется, тут всё понятно: создаётся окно, устанавливаются его параметры, а затем создаётся новый объект нашего testApp, который передаётся параметром в ofRunApp(), которая делает всю остальную работу, вызывая установочные testApp->setup() и testApp->update(), а затем в цикле отрисовки вызывая testApp->draw()
содержимое testApp.h:
#ifndef _TEST_APP #define _TEST_APP #include "ofMain.h" class testApp : public ofSimpleApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void windowResized(int w, int h); void setupArduino(); void updateArduino(); ofImage bgImage; ofTrueTypeFont font; ofArduino ard; bool bSetupArduino; // flag variable for setting up arduino once }; #endifвидим класс testApp ,у которого объявлено несколько функций.
самые важные - это:void setup(); void update(); void draw();ниже задаются функции-обработчики событий от клавиатуры и мышки, а ещё ниже уже пользовательские функции и пользовательские переменные.
видим объект для общения с Arduino по протоколу Firmata:
ofArduino ard;Соответственно в testApp.cpp написана реализация функций класса:
setup() ,как ясно из названия - это аналог setup() в Wiring-e и Processing-е; функция в которой происходит начальная установка и инициализация параметров.
В данном примере - установка фона, подгрузка картинки, загрузка шрифта и подключение к контроллеру Arduino:#include "testApp.h" void testApp::setup(){ ofSetVerticalSync(true); ofSetFrameRate(60); ofBackground(255,0,130); bgImage.loadImage("firmata.png"); font.loadFont("franklinGothic.otf", 20); // the connection speed has been changing in the // arduino firmata sketch. in 0017 it's 57600 // if you have problems try commenting/uncommenting // to change the speed // ard.connect("/dev/ttyUSB0", 115200); ard.connect("/dev/ttyUSB0", 57600); bSetupArduino = false; // flag so we setup arduino when its ready, you don't need to touch this :) }Нужно отметить, что для подключения к COM-порту под Windows придётся писать строчку вида:
ard.connect("\\\\.\\COM19", 57600);void testApp::update(){ if ( ard.isArduinoReady()){ // 1st: setup the arduino if haven't already: if (bSetupArduino == false){ setupArduino(); bSetupArduino = true; // only do this once } // 2nd do the update of the arduino updateArduino(); } } //-------------------------------------------------------------- void testApp::setupArduino(){ // this is where you setup all the pins and pin modes, etc for (int i = 0; i < 13; i++){ ard.sendDigitalPinMode(i, ARD_OUTPUT); } ard.sendDigitalPinMode(13, ARD_OUTPUT); ard.sendAnalogPinReporting(0, ARD_ANALOG); // AB: report data ard.sendDigitalPinMode(11, ARD_PWM); // on diecimelia: 11 pwm?*/ } //-------------------------------------------------------------- void testApp::updateArduino(){ // update the arduino, get any data or messages: ard.update(); ard.sendPwm(11, (int)(128 + 128 * sin(ofGetElapsedTimef()))); // pwm... }Нетрудно догадаться, что функция draw() - аналог одноимённой функции Processing-а:
void testApp::draw(){ bgImage.draw(0,0); if (!ard.isArduinoReady()){ font.drawString("arduino not ready\n", 545, 40); } else { font.drawString("analog pin 0: " + ofToString(ard.getAnalog(0)) + "\nsending pwm: " + ofToString((int)(128 + 128 * sin(ofGetElapsedTimef()))), 545, 40); } }так же видим, что при нажатии/отпускании кнопки мышки контроллеру Ardunio будет послано сообщение зажечь/погасить сигнальный светодиод на 13 порту.
void testApp::mousePressed(int x, int y, int button){ ard.sendDigital(13, ARD_HIGH); } //-------------------------------------------------------------- void testApp::mouseReleased(int x, int y, int button){ ard.sendDigital(13, ARD_LOW); }После сборки проекта в каталоге
apps\examples\firmataExample\bin\появится исполняемый файл
firmataExample.exe
,а так же будут скопированы необходимые для работы и распространения dll-ки:
fmodex.dll
fmodexL.dll
FreeImage.dll
FreeType-6.dll
glut32.dll
Zlib.dll
так же обратите на подкаталог data, в котором содержатся необходимые для работы файлы:
firmata.png - файл изображения Arduino
franklinGothic.otf - файл используемого шрифтаCвой openFrameworks-проект для Arduino
Итак, вроде всё более-менее понятно.
Чтобы закрепить материал нужно попробовать написать свой проект 🙂
Т.к. проект будет для общения с Arduino - я скопирую не пустой проект emptyExample, а уже рассмотренный firmataExample.Назову проект myArduinoExample
Проект будет аналогом рассмотренного ранее проекта Processing-а arduio_output.
Т.е. выведем в окошко квадратики состояния цифровых выходов ардуины; каждый квадратик будет обозначать один цифровой выход контроллера от 13 до 0. Щелкая по нему, мы переключаем состояние межу HIGH и LOW.
Однако просто выводить квадратики скучно, поэтому возьмём фотографию контроллера Arduino и будем щёлкать по изображению портов.переименую и отредактирую файлы
myArduinoExample.sln
и
myArduinoExample.vcproj
заменив строчку firmataExample на myArduinoExample.
Заменим и переименуем картинку.
Пора редактировать код 🙂Первым делом, нам нужно определить положение портов на картинке:
для этого добавим в класс testApp две переменные mouseX и mouseY для сохранения координат нажатия мышки.
Установку значения этих переменных будем производить по нажатию мышки в обработчике mousePressed():void testApp::mousePressed(int x, int y, int button){ printf("[click] x: %d y: %d\n", x, y); mouseX=x; mouseY=y; }вывод координат добавим в функцию draw():
// выводим где был последний клик мышкой :) if(mouseX || mouseY){ ofSetColor(50, 100, 200); font.drawString("x: " + ofToString(mouseX) + " y: " + ofToString(mouseY), 600, 100); ofSetColor(255, 255, 255); }Обратите внимание - шрифт изначально выводится белым цветом 🙂
по примерам видно, что для того чтобы изменить цвет нужно добавить строчкуofSetColor(50, 100, 200); font.drawString("x: " + ofToString(mouseX) + " y: " + ofToString(mouseY), 600, 100);в конце нужно добавить
ofSetColor(255, 255, 255);, чтобы цвет не залил весь экран 😉
Собираем код, щёлкаем по картинке и получаем координаты:
по y - около 95 а по X: 13 - 300 12 - 320 11 - 340 10 - 360 9 - 380 8 - 400 7 - 440 6 - 460 5 - 480 4 - 500 3 - 520 2 - 540Остаётся нарисовать в этих местах квадратики.
Как задаётся цвет мы уже знаем, квадратик же рисуется функциейofRect(x, y, w, h);Вот и всё. Остаётся определить место клика мышкой и просто менять состояние порта на противоположное.
Для хранения текущего состояния порта заведём массив
int pins[PIN_COUNT];Обнуляем этот массив в функции setup(), а затем добавляем проверочный код на какой квадратик порта кликнули в функцию-обработчик mousePressed():
void testApp::mousePressed(int x, int y, int button){ printf("[click] x: %d y: %d\n", x, y); mouseX=x; mouseY=y; // проверка попадания по Y if(mouseY>90 && mouseY<105){ printf("[i] Y ok!\n"); // проверка попадания по X if(mouseX>290 && mouseX<560){ // определяем куда кликнули :) for(int i=2; i<=13; i++){ float xx; if(i<=7){ xx = 540 - 20*(i-1) + 10; } else{ xx = 400 - 20*(i-7) + 10; } if( abs(xx+7.5-x)<13 ){ printf("[i] X ok! pin: %d\n", i); // меняем состояние порта if(pins[i]){ ard.sendDigital(i, ARD_LOW); pins[i]=0; } else{ ard.sendDigital(i, ARD_HIGH); pins[i]=1; } break; } } } } }и соответственно меняем цвет квадратика в функции draw():
void testApp::draw(){ // показываем изображения (в качестве фона) bgImage.draw(0,0); if (!ard.isArduinoReady()){ font.drawString("arduino not ready\n", 545, 40); } // выводим где был последний клик мышкой :) if(mouseX || mouseY){ ofSetColor(50, 100, 200); font.drawString("x: " + ofToString(mouseX) + " y: " + ofToString(mouseY), 600, 100); ofSetColor(255, 255, 255); //ofDrawBitmapString("x: " + ofToString(mouseX) + " y: " + ofToString(mouseY), 545, 130); } float x,y, w=15, h=15; // нарисуем квадратики портов for(int i=2; i<=13; i++){ // в зависимости от состояния порта - определяем цвет if(pins[i]){ ofSetColor(200, 0, 0); } else{ ofSetColor(0, 200, 0); } y = 90; if(i<=7){ x = 540 - 20*(i-1) + 10; } else{ x = 400 - 20*(i-7) + 10; } // рисуем квадратик ofRect(x, y, w, h); } ofSetColor(255, 255, 255); }Вот как выглядит окошко программы:
Скачать программу с исходниками. (2.5 Mb - так много потому что в комплекте идут dll-библиотеки используемые openFrameworks-ом, без которых программа не запустится )
Вывод - действительно просто, быстро и удобно 🙂 А ещё OpenGL 😉
читать ещё: openFrameworks vs Processing
Ссылки
официальный сайт - http://www.openframeworks.cc
FAQ - http://www.openframeworks.cc/about/faq
форум - http://www.openframeworks.cc/forum/index.php
wiki - http://wiki.openframeworks.cchttp://en.wikipedia.org/wiki/OpenFrameworks
http://wiki.openframeworks.cc/index.php?title=OfAmsterdam
OpenGL tutorialsПо теме
Практическое программирование Arduino- программирование работы с COM-портом
Arduino и Matlab
Arduino и LabVIEW
Processing и Arduino