diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000000..4331fa18e0b --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,19 @@ +version: 1.0.{build} +os: Visual Studio 2015 RC +configuration: Debug +platform: +- x86 +- x64 +shallow_clone: true +clone_depth: 10 +environment: + PATH: C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% +build: + project: libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj + parallel: true + verbosity: minimal +test_script: +- cmd: >- + cd scripts/ci/vs + + run_tests.bat diff --git a/.gitattributes b/.gitattributes index 59a05413941..6eddf295723 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,8 @@ # Declare files that will always have CRLF line endings on checkout. *.sln text eol=crlf *.vcxproj* text eol=crlf +.appveyor.yml text eol=crlf +*.bat text eol=crlf # Denote all files that are truly binary and should not be modified. *.png binary diff --git a/.gitignore b/.gitignore index e5de792a470..0b1fa3fcdea 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,12 @@ apps/* *.o examples/**/[Dd]ebug*/ examples/**/[Rr]elease*/ +examples/**/gcc-debug/ +examples/**/gcc-release/ +tests/**/[Dd]ebug*/ +tests/**/[Rr]elease*/ +tests/**/gcc-debug/ +tests/**/gcc-release/ *.mode* *.app/ *.pyc @@ -72,6 +78,19 @@ ipch/ local.properties .externalToolBuilders +# Android Studio +.idea +.gradle +gradle +gradlew +gradlew.bat + +# QtCreator +*.qbs.user +*.pro.user +*.pri + + ######################### # operating system ######################### @@ -107,3 +126,5 @@ Desktop.ini ######################### .mailmap +/apps*/ + diff --git a/.gitmodules b/.gitmodules index 626eeaa3609..ccce6e7c252 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "apps/projectGenerator/projectGeneratorSimple"] +[submodule "apps/projectGenerator"] path = apps/projectGenerator url = https://github.com/openframeworks/projectGenerator.git diff --git a/.travis.linux.yml b/.travis.linux.yml deleted file mode 100644 index 9ce437471a3..00000000000 --- a/.travis.linux.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: c++ -sudo: required -compiler: gcc -#cache: -# - ccache -# - apt -env: - matrix: - - NAME="linux" \ - OF_ROOT="$PWD" \ - SCRIPT="scripts/linux/testTemplate.sh" -before_install: - - sudo scripts/linux/ubuntu/install_dependencies.sh - - export CXX=g++-4.9 -script: - $SCRIPT -git: - depth: 1 -notifications: - webhooks: http://192.237.185.151/web-hooks/travis_done.cgi diff --git a/.travis.yml b/.travis.yml index d0e15727e62..b11e1f1b3bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,35 +1,72 @@ - -language: objective-c -compiler: clang -node_js: '0.10' -env: - global: - - secure: kjz286d6rs2VHpv4WnxAOYXcdTIaTaABZ0SNXf27r5H+NDu5qx8ZSeCmj/9op/sDjTtpkLKhi2a0njUCWwak28RAWP3dNkT92MkUPVKBkevznSxWeqwLHoUos3AJnhPMB+cwrWvmRC+Ljt5K1q8SxQsS/HXM9pzKL3DG3qxM+eo= - matrix: - - NAME="osx" \ - SCRIPT_PATH="scripts/$NAME" \ - SCRIPT="$SCRIPT_PATH/testTemplate.sh" - - NAME="ios" \ - SCRIPT_PATH="scripts/$NAME" \ - SCRIPT="$SCRIPT_PATH/testTemplate.sh" - - NAME="android-armv7" \ - SCRIPT_PATH="scripts/android" \ - OF_ROOT="$PWD" \ - SCRIPT="$SCRIPT_PATH/testTemplate.sh armv7" - - NAME="android-x86" \ - SCRIPT_PATH="scripts/android" \ - OF_ROOT="$PWD" \ - SCRIPT="$SCRIPT_PATH/testTemplate.sh x86" - - NAME="docs" \ - SCRIPT_PATH="scripts/dev" \ - SCRIPT="$SCRIPT_PATH/documentation.sh" -before_install: - "if [ \"$NAME\" == \"docs\" ]; then scripts/dev/documentation.sh before_install; fi" +language: c++ +compiler: gcc +sudo: true +matrix: + include: + # fully specify builds, include can't dynamically expand matrix entries + # relative order of sudo and env is important so that addons: is recognized + - os: linux + dist: trusty + sudo: required + env: TARGET="linux" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - g++-4.9 + - gdb + - os: osx + compiler: clang + env: TARGET="osx" + - os: osx + compiler: clang + env: TARGET="ios" + - os: linux + sudo: false + env: TARGET="android" OPT="armv7" + cache: + directories: + - ~/android-ndk-r10e + - os: linux + sudo: false + env: TARGET="android" OPT="x86" + cache: + directories: + - ~/android-ndk-r10e + # disable docs test for now + #- os: linux + # sudo: false + # env: + # - TARGET="docs" + # - secure: kjz286d6rs2VHpv4WnxAOYXcdTIaTaABZ0SNXf27r5H+NDu5qx8ZSeCmj/9op/sDjTtpkLKhi2a0njUCWwak28RAWP3dNkT92MkUPVKBkevznSxWeqwLHoUos3AJnhPMB+cwrWvmRC+Ljt5K1q8SxQsS/HXM9pzKL3DG3qxM+eo= + # addons: + # apt: + # packages: + # - python-software-properties + # - doxygen + # - ncftp + # Exclude the default build that would otherwise be generated + # see https://github.com/travis-ci/travis-ci/issues/1228 + exclude: + - compiler: gcc + #allow_failures: + # # temporary until we find out how to prevent (spurious) build failures + # - env: + # - TARGET="docs" + # - secure: kjz286d6rs2VHpv4WnxAOYXcdTIaTaABZ0SNXf27r5H+NDu5qx8ZSeCmj/9op/sDjTtpkLKhi2a0njUCWwak28RAWP3dNkT92MkUPVKBkevznSxWeqwLHoUos3AJnhPMB+cwrWvmRC+Ljt5K1q8SxQsS/HXM9pzKL3DG3qxM+eo= install: - "if [ \"$NAME\" == \"android-armv7\" ] || [ \"$NAME\" == \"android-x86\" ]; then scripts/android/install_tests_env.sh; fi" + - if [ "$TARGET" == "android" ] || [ "$TARGET" == "linux" ] || [ "$TARGET" == "docs" ] || [ "$TARGET" == "osx" ]; then + scripts/ci/$TARGET/install.sh; + fi script: - "$SCRIPT" + - scripts/ci/$TARGET/build.sh $OPT + - if [ "$TARGET" == "osx" ] || [ "$TARGET" == "linux" ]; then + scripts/ci/$TARGET/run_tests.sh; + fi after_success: - "if [ \"$NAME\" == \"docs\" ]; then scripts/dev/documentation.sh after_success; fi" + # this will only run fully on a commit, not a PR, due to secure above + if [ "$TARGET" == "docs" ]; then scripts/ci/$TARGET/after_success.sh; fi git: depth: 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b90afb418b..ec197d70e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,34 @@ OF 0.9.0 / modified ------------------------------------------------------------------------------ +GENERAL +------- + ++ added a new Project Generator ++ added CODE_OF_CONDUCT.md based on the Contributor Covenant and Berlin Code of Conduct, iteratively refined through group discussion +/ code cleanup (fixed many typos, warnings, memleaks, implicit conversions, types, const-correctness, duplicated and missing definitions/functions, removed internal use of deprecated methods and unnecessary code) ++ move towards C++11 ++ added automated (unit) testing on several OSes via travis-ci.org +/ updated third party libraries (Poco 1.6, Freetype 2.5.5, FreeImage 3.17, OpenSSL 1.01j) ++ higher precision and monotonic timers +/ documentation and many examples fixed/adjusted to new code base ++ QtCreator project files and wizard added ++ Apothecary received a lot of fixes and updates to adjust to the new codebase ++ Makefile enforces recompilation when flags change + CORE ---- + ### app / setupOpenGL and ofApp___Window use ofWindowMode instead of int / fix exit callbacks to allow for calling of the destructors, and better signal handling / changed windowEntry event to mouseEntered/mouseExted, added these callbacks when registering for mouse events + + clipboard supports UTF8 + + added scrollwheel support for GLFW + / ofAppNoWindow refactored to remove unused methods + + main loop can be set via ofSetMainLoop() + + support for semantic versioning ### 3d / ofEasyCam: removes roll rotation when rotating inside the arcball @@ -21,19 +42,27 @@ CORE / ofDrawGrid: arguments changed to ```float stepSize, size_t numberOfSteps``` instead of ```float scale, float ticks``` / ofDrawGridPlane: arguments changed to ```float stepSize, size_t numberOfSteps``` instead of ```float scale, float ticks``` / ofCamera: fix calculations on first frame or before first call to begin + + ofCamera: orthograpic projection with coordinates relative to viewport + / ofNode orbit now uses quaternions to avoid Gimball Lock + / ofGraphics immediate mode style primitives renamed to ofDraw* + +### communication + / ofArduino: added missing initializations + / easyCam: zRot flipped correctly + +### events + + added isEnabled() and size() to ofBaseEvent ### gl - + Programmable lights and materials - + New area light type on programmable renderer - + Separate model matrix + + programmable lights and materials + + new area light type on programmable renderer + + separate model matrix + ofBufferObject wraps GL buffers for easy use, see compute shader and pixel buffer examples for usage + ofGetCurrentNormalMatrix + ofSetOpenGL(ES)Version, allows to set any specific GL version - + ofTexture::enableMipmap() auto-generate mipmaps on load - for textures which support - mipmaps (that's TEXTURE_2D textures loaded after ofDisableArbTex() ) - + ofTexture::generateMipmap() generate mipmap after a texture was loaded, - if the texture target supports mipmaps (see above). + + ofTexture::enableMipmap() auto-generate mipmaps on load - for textures which support mipmaps (that's TEXTURE_2D textures loaded after ofDisableArbTex() ) + + ofTexture::generateMipmap() generate mipmap after a texture was loaded, if the texture target supports mipmaps (see above). + ofTexture::disableMipmap() disables auto-generation of mipmap for texture - removed compressed mipmaps based on deprecated glu methods - ofSetTextureWrap() : deprecated (use corresponding ofTexture member method) @@ -42,95 +71,179 @@ CORE - ofSetMinMagFilters() : deprecated (use corresponding ofTexture member method) - ofGetUsingCustomMinMagFilters() : deprecated - ofRestoreMinMagFilters() : deprecated + + ofTexture::allocateAsBufferTexture(), a dedicated way to allocate ofTextures as Buffer Texture. Useful to pass large amounts of uniform data to shaders. See TextureBufferInstanceExample + ofShader: report offending lines on compiling errors + + ofShader: setUniformMatrix now accepts an (optional) count parameter, so you can pass an array of matrices + ofGLUtils: better support for half float types - / getTextureReference -> getTexture - / ofVbo refector: ofVbo will, in programmable renderer, automatically recognise - attribute locations 0, 1, 2, 3 as position, color, texture, normal attributes - can be set using either using convenience methods e.g. - `ofVbo::setTexCoordData(...)` or the more flexible - `ofVbo::setAttributeData(ofShader::TEXCOORD_ATTRIBUTE, ...)` which allows - for 3d texture coordinates. + / syntax change: getTextureReference() -> getTexture() + / GPU optimisations giving the GPU driver more leverage to optimise drawing speed + / ofVbo refector: ofVbo will, in programmable renderer, automatically recognise attribute locations 0, 1, 2, 3 as position, color, texture, normal attributes can be set using either using convenience methods e.g. `ofVbo::setTexCoordData(...)` or the more flexible `ofVbo::setAttributeData(ofShader::TEXCOORD_ATTRIBUTE, ...)` which allows for 3D texture coordinates. / Fix ofTexture::readToPixels for non RGBA or 4 aligned formats / Rename ofTextureData.glTypeInternal -> ofTextureDataData.glInternalFormat (this brings the parameter's name into sync with the OpenGL enum it represents) + / Rename ofFbo::destroy -> clear to be consistent with other classes + + added Data struct to ofMaterial + / drawElements() now has an offset into the index buffer + + ### graphics + ofTruetypeFont: kerning and better hinting and spacing + ofDrawBitmapString: can draw any type not only strings / ofImage: can load image via https - / getPixelsRef() deprecated and getPixels() now returns ofPixels - temporarily ofPixels auto casts to unsigned char* so old code - is still compatible + / getPixelsRef() deprecated and getPixels() now returns ofPixels temporarily ofPixels auto casts to unsigned char* so old code is still compatible / ofPixels::getPixels() -> getData() - + ofPixels support for YUV formats, the prefered allocation method - changes from channels to ofPixelFormat like: - pix.allocate(w,h,OF_PIXELS_RGB) + + ofPixels support for YUV formats, the prefered allocation method changes from channels to ofPixelFormat like: pix.allocate(w,h,OF_PIXELS_RGB) / fixed ofSetBackgroundColor / added ofGetBackgroundColor and ofGetBackgroundAuto - removed ofbBGColor and ofbBGClear / ofImage::loadImage() -> load() / ofImage::saveImage() -> save() + ofBeginSaveScreenAsSVG + / ofPolyline::addVertexes changed to ofPolyline::addVertices + / ofImage allows pixel color access via index + / ellipse supported correctly in ofCairoRenderer + +### math + / updated ofMath.h + + ofVecXf based ofNoise functions + +### projectGenerator + / moved apps & common code for PG to a separate repo + + added a new app to replace the simple and legacy projectGenerators, using an HTML-based frontend built with electron + / updated commandline PG with more features & better output, both for standalone use and to support the electron-based PG + + added support for local addons outside the ../../../addons folder via the commandLine PG and the addons.make file + + added templates for platform-specific configs, different OpenGL versions, etc + + added scrolling feature for addons panel in legacy PG ### sound / ofFmodSoundPlayer: fix for file handles not being closed - / Deprecated all ofBaseSoundInput/Output methods that do not take an ofSoundBuffer. + + ofSoundBuffer class for encapsulating a buffer of raw samples (see new soundBufferExample) + + ofSoundDevice class for representing sound i/o devices + + ofSoundStream::getMatchingDevices() for finding sound devices by name and / or channel count + / deprecated all ofBaseSoundInput/Output methods that do not take an ofSoundBuffer + / ofSoundPlayer::getIsPlaying() changed to ::isPlaying() + - removed ofSoundStream::listDevices(), see ::getDeviceList() or ::printDeviceList() + +### types + + ofRectangle: added `setSize` method. + + ofRectangle: added `operator -` method. + ### utils - / better timming in fps calculation + / better timing in fps calculation + ofFpsCounter allows to easily meassure the fps of any element + ofTimer allows to create a precise periodic waitable timer - + ofThreadChannel: thread synchronization primitive to make it - easier to work with threads avoiding the need for mutexes in - most cases. see example/utils/threadChannelExample / ofBuffer::getBinaryBuffer() -> getData() + + ofThreadChannel introduced for easier multithreading + / ofSerial::enumerateDevices() -> listDevices() + / "ms" is now always 3 digits long when generating timestamps + - removed ofThreadLogger + + more and better logging ### video / gstreamer: fix memory leaks when closing a video element - + gstreamer: support for YUV formats when using the programmable renderer - using OF_PIXELS_NATIVE as pixel format will choose the fastest format + + gstreamer: support for YUV formats when using the programmable renderer using OF_PIXELS_NATIVE as pixel format will choose the fastest format / gstreamer: faster reload by default and optional asynchronous load / ofVideoPlayer::loadMovie() -> load() / ofVideoGrabber::initGrabber() -> setup() -### types - + ofRectangle: added `setSize` method. - + ofRectangle: added `operator -` method. + / AVFoundation player is now the default for OS X 10.8+ + + AVFoundation player now has a loadAsync for asynchronous video loading + / DirectShow video player is now default for Microsoft Windows + / Replaced deprecated methods in ofAVFoundationPlayer + + test for player during initialization + PLATFORM SPECIFIC ----------------- ### Emscripten - + New platform! + + new platform! + / Raspberry Pi 2 is now default ARMv7 variant ### ofxiOS - + xcode 6.0 updates + + Xcode 6.0 updates + deployment target moved up to iOS 5.1.1 + + iOS ARM64 C++11 support + / tab-indentation specified in the openFrameworks Xcode project (ofApp is still user-specified) + / AVSoundPlayer now uses shared audio session to better cooperate with AVFoundationVideoPlayer + / no longer calling ofReloadGLResources in ofxiOS + + ofxiOSKeybaord exposes UITextField + + added ofAppiOSWindow::Settings for controlling the app settings + / replaced ofPtr with shared_ptr in ofxiOSVideoGrabber + - removed old target checks + + adjusted scale factor for iPhone6 and iPhone6+ + + added simulator support iPhones + + hint at using SDK 5.0 or later -### android - + fix camera stretching artifacts experienced on some devices when using 16:9 - aspect ratios - + remove support for arm5 since no devices seem to have that cpu anymore and it - was problematic with certain libraries - -### linux and arm linux - + opencv libs are now installed in the system, rerun install_dependencies if you - are having problems compiling projects that use opencv - -### windows - + activated high precission timming to fix inaccurate fps calculations - -### osx - / moved system framework dependencies from Xcode project to CoreOF.xcconfig +### Android + + fix camera stretching artifacts experienced on some devices when using 16:9 aspect ratios + + support for Android Studio + + remove support for ARM5 since no devices seem to have that cpu anymore and it was problematic with certain libraries + - removed statistics and globals + + added multiwindow and touch support + + added helper method ofCallStaticVoidJavaMethod() + / better handling of video when app is paused + / getTextureReference() refactored to getTexture() + + added gradle.properties file + +### Linux (incl. ARM) + + allow passing -j to compileOF.sh for parallel compilation + / native package managers handle OpenCV libraries + / adjusted Makefile for Raspberry Pi 2 + +### Microsoft Windows + + activated high precision timing to fix inaccurate fps calculations + / multiprocessor compilation enabled by default + / added support for Visual Studio 2015 and Windows 10 + +### OSX and iOS + / moved ofApp system framework dependencies from Xcode project to CoreOF.xcconfig / removed GLUT from project template, see libs/glut/lib/osx if you need GLUT + / tab-indentation specified in the openFrameworks Xcode project (ofApp is still user-specified) + / use robocopy instead of xcopy in the post-build step to minimize file transfers + + 10.8+ support + / empty clipboard doesn’t crash anymore + / compilation via Makefile also works without Xcode + / unified AVFoundation video player CORE ADDONS ----------- + +### ofx3DModelLoader + - removed as it was using some really old gl calls and ofxAssimpModelLoader already loads 3D studio models + +### ofxAssimpModelLoader + / Updated to assimp 3 + +### ofxGui + + extendent ofxBaseGui + +### ofxiOSVideoPlayer + / API update + / ofxButton::valueChanged() includes sender + +### ofxKinect + / Bugfix for kinects not keeping their IDs when using multiple kinects + + 64bit updates for Microsoft Windows + +### ofxNetwork + + peek() to look into sockets + ### ofxOpenCV / updated ofxCvHaarFinder to not use textures on internal image objects, allowing for usage within threads. + / removed OpenCV binary libraries, installation moved to Linux package managers + / OpenCV updated to 2.4.9 ### ofxSynth - - Removed, see ofxMaxim for a replacement (https://github.com/micknoise/Maximilian) + - Removed, see ofxMaxim for a replacement (https://github.com/micknoise/Maximilian) -### ofxKinect - / Bugfix for kinects not keeping their IDs when using multiple kinects. +### ofxTCPManager + + timeout after 5 seconds by default + / using std mutexes to lock + +### ofxUDPManager + / updated error logging + +### ofxMultiTouch + - Removed - functionality provided by core events PROJECT GENERATOR ----------------- diff --git a/README.md b/README.md index a3be6cb266e..08feb9e97fa 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,10 @@ openFrameworks is a C++ toolkit for creative coding. If you are new to OF, welc ##Build status -OSX, iOS and Android [![Build Status](https://travis-ci.org/openframeworks/openFrameworks.svg?branch=master)](https://travis-ci.org/openframeworks/openFrameworks) +Linux, OSX, iOS and Android [![Build Status](https://travis-ci.org/openframeworks/openFrameworks.svg?branch=master)](https://travis-ci.org/openframeworks/openFrameworks) Visual studio [![Build status](https://ci.appveyor.com/api/projects/status/sm9jxy0u56bl8syi/branch/master?svg=true)](https://ci.appveyor.com/project/arturoc/openframeworks/branch/master) -Linux [![Build Status](https://travis-ci.org/openframeworkstests/openFrameworks.svg)](https://travis-ci.org/openframeworkstests/openFrameworks) - folder structure -------- diff --git a/addons/.gitignore b/addons/.gitignore index 79a9d1ff54f..6000646f925 100644 --- a/addons/.gitignore +++ b/addons/.gitignore @@ -22,6 +22,8 @@ ofxAndroid/ofAndroidLib/gen !ofxVectorGraphics !ofxXmlSettings !ofxEmscripten +!ofxUnitTests +!ofxProjectGenerator # don't ignore the .gitignore file !.gitignore diff --git a/addons/ofx3DModelLoader/src/3DS/Vector3DS.h b/addons/ofx3DModelLoader/src/3DS/Vector3DS.h deleted file mode 100644 index 987f5f18740..00000000000 --- a/addons/ofx3DModelLoader/src/3DS/Vector3DS.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - Vector3DS class - © Keith O'Conor 2004 - keith.oconor @ {cs.tcd.ie, gmail.com} -*/ - -#ifndef VECTOR_H -#define VECTOR_H - -#include -#include - -class Vector3DS{ -public: - float x; - float y; - float z; - - /* - Vector3DS(); - Vector3DS(float a, float b, float c); - Vector3DS(Vector3DS& copy); - - Vector3DS& operator=(const Vector3DS &other); - int operator== (const Vector3DS &other); - int operator!= (const Vector3DS &other); - Vector3DS operator+(const Vector3DS &other); - Vector3DS operator-(const Vector3DS &other); - Vector3DS operator*(const float &value); - Vector3DS operator/(const float &value); - Vector3DS& operator+=(const Vector3DS &other); - Vector3DS& operator-=(const Vector3DS &other); - Vector3DS& operator*=(const float& other); - Vector3DS& operator/=(const float& other); - float operator[](unsigned i); - - float length(); - float lengthSq(); - float dotProduct(const Vector3DS &other); - Vector3DS crossProduct(const Vector3DS &other); - void normalize(); - float distance(const Vector3DS &other); - float distanceSq(const Vector3DS &other); - void set(float newX, float newY, float newZ); - void zero(); - */ - - ///////////////// - // Constructors - ///////////////// - - inline Vector3DS():x(0),y(0),z(0){} - inline Vector3DS(const float a, const float b, const float c):x(a),y(b),z(c){} - inline Vector3DS(const Vector3DS& copy):x(copy.x),y(copy.y),z(copy.z){} - - ////////////// - // Operators - ////////////// - - inline Vector3DS& operator= (const Vector3DS &other){ - x=other.x;y=other.y;z=other.z; - return *this; - } - - inline int operator== (const Vector3DS &other) const{ - return (x==other.x && y==other.y && z==other.z); - } - inline int operator!= (const Vector3DS &other) const{ - return (x!=other.x || y!=other.y || z!=other.z); - } - - inline Vector3DS operator+ (const Vector3DS &other) const{ - return Vector3DS(x+other.x, y+other.y, z+other.z); - } - - inline Vector3DS operator- (const Vector3DS &other) const{ - return Vector3DS(x-other.x, y-other.y, z-other.z); - } - - inline Vector3DS operator* (const float &value) const{ - return Vector3DS(x*value, y*value, z*value); - } - - inline Vector3DS operator/ (const float &value) const{ - return Vector3DS(x/value, y/value, z/value); - } - - inline Vector3DS& operator+= (const Vector3DS &other){ - x+=other.x; - y+=other.y; - z+=other.z; - return *this; - } - inline Vector3DS& operator-= (const Vector3DS &other){ - x-=other.x; - y-=other.y; - z-=other.z; - return *this; - } - - inline Vector3DS& operator*= (const float &value){ - x*=value; - y*=value; - z*=value; - return *this; - } - - inline Vector3DS& operator/= (const float &value){ - x/=value; - y/=value; - z/=value; - return *this; - } - - inline float operator[] (unsigned i) const{ - switch(i){ - case 0:return x; - case 1:return y; - case 2:return z; - default: - terminate(); - break; - } - } - - ///////////////////// - // Other operations - ///////////////////// - - inline float length() const{ - float len=(x*x)+(y*y)+(z*z); - return (float)sqrt(len); - } - - inline float lengthSq() const{ - return (x*x)+(y*y)+(z*z); - } - - inline float dotProduct(const Vector3DS &other) const{ - //this[dot]other - return (x*other.x) + (y*other.y) + (z*other.z); - } - - inline Vector3DS crossProduct(const Vector3DS &other) const{ - //(x1,y1,z1)◊(x2,y2,z2) = (y1z2-y2z1, x2z1-x1z2, x1y2-x2y1). - return Vector3DS( - (y*other.z) - (z*other.y), - (z*other.x) - (x*other.z), - (x*other.y) - (y*other.x) - ); - } - - inline void normalize(){ - float len=length(); - if(len==0)return; - len=1.0f/len; - x*=len; - y*=len; - z*=len; - } - - inline float distance(const Vector3DS &other) const{ - return (Vector3DS(other.x-x,other.y-y,other.z-z)).length(); - } - - inline float distanceSq(const Vector3DS &other) const{ - return (Vector3DS(other.x-x,other.y-y,other.z-z)).lengthSq(); - } - - inline void set(float newX, float newY, float newZ){ - x=newX;y=newY;z=newZ; - } - - inline void zero(){ - x=y=z=0; - } - -}; - -typedef Vector3DS Vertex; - -const Vector3DS vZero=Vector3DS(0,0,0); - - ///////////////////////////// - // Global stream operators -////////////////////////////// -inline std::ostream& operator<<(std::ostream &str, const Vector3DS &v){ - str<is_open()){ - std::cout<<"[3DS] ERROR: Could not open '"<tellg()) == 0){ - std::cout<<"[3DS] ERROR: Model '"<close(); - return; - } - - // Extract path from filename - int lastSlashPosition=-1, lastForwardSlash=-1, lastBackslash=-1; - lastForwardSlash = (int)m_filename.find_last_of('/'); - lastBackslash = (int)m_filename.find_last_of('\\'); - if(lastForwardSlash > lastSlashPosition) lastSlashPosition = lastForwardSlash; - if(lastBackslash > lastSlashPosition) lastSlashPosition = lastBackslash; - m_filepath = m_filename.substr(0,lastSlashPosition+1); - m_filename = m_filename.substr(lastSlashPosition+1); - - // Check to make sure file is valid 3DS format (begins with 0x4D4D) - ushort chunkHeader; - unsigned int chunkLength; - - modelFile->seekg(0, std::ios::beg); - modelFile->read((char*)&chunkHeader,2); - modelFile->read((char*)&chunkLength,4); - - if(chunkHeader != CHUNK_MAIN){ - std::cout<<"[3DS] ERROR: Model '"<close(); - return; - } - - // Detect VBO support - std::stringstream extStream((const char*)glGetString(GL_EXTENSIONS)); - std::string nextToken; - bool isVBOSupported=false; - while(!extStream.eof()){ - extStream >> nextToken; - if(nextToken == "GL_ARB_vertex_buffer_object"){ - isVBOSupported=true; - break; - } - } - m_drawMode = DRAW_VERTEX_ARRAY; - - - // Initialise bounding box to min & max 4-byte float values - m_boundingBox.minX = m_boundingBox.minY = m_boundingBox.minZ = 3.4e+38f; - m_boundingBox.maxX = m_boundingBox.maxY = m_boundingBox.maxZ = 3.4e-38f; - - // Read all 3DS chunks recursively - - long end; - modelFile->seekg (0, ios::end); - end = modelFile->tellg(); - modelFile->seekg (0, ios::beg); - - - while(!modelFile->eof() && (end != modelFile->tellg())){ - readChunk(modelFile, modelFile->tellg(), chunkLength); - } - - m_centerX = (m_boundingBox.minX + m_boundingBox.maxX) / 2.f; - m_centerY = (m_boundingBox.minY + m_boundingBox.maxY) / 2.f; - m_centerZ = (m_boundingBox.minZ + m_boundingBox.maxZ) / 2.f; - - // Model loaded, clean up - modelFile->close(); - delete modelFile; - std::cout<<"[3DS] Model '"<tellg() < (objectStart + objectLength)) && !modelFile->eof()){ - - offset = modelFile->tellg(); - - modelFile->read((char*)&chunkHeader, 2); - modelFile->read((char*)&chunkLength, 4); - - if(DEBUG_OUTPUT) std::cout<setDrawMode(m_drawMode); - - // Read object name - do{ - modelFile->read(¤tLetter,1); - name += currentLetter; - }while(currentLetter!='\0' && name.length()<20); - m_currentMesh->setName(name); - if(DEBUG_OUTPUT) std::cout<<" Object: "<tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - - if(m_currentMesh->getNumFaces() != 0){ - m_currentMesh->buildMesh(); - m_meshes.push_back(*m_currentMesh); - } - delete m_currentMesh; - break; - - ///////////////////// - // Geometry chunks - //////////////////// - - case CHUNK_MESH:continue; - - case CHUNK_VERTICES: - modelFile->read((char*)&numVertices,2); - - for(v=0; v < numVertices*3; v+=3){ - modelFile->read((char*)&vertexX,4); - modelFile->read((char*)&vertexY,4); - modelFile->read((char*)&vertexZ,4); - - // 3DS Max has different axes to OpenGL - vertexX *= m_scale; - vertexY *= m_scale; - vertexZ *= m_scale; - - m_currentMesh->addVertex(vertexX);// x - m_currentMesh->addVertex(vertexY);// y - m_currentMesh->addVertex(vertexZ);// z - - // Update bounding box - if(vertexX < m_boundingBox.minX) - m_boundingBox.minX = vertexX; - if(vertexY < m_boundingBox.minY) - m_boundingBox.minY = vertexY; - if(vertexZ < m_boundingBox.minZ) - m_boundingBox.minZ = vertexZ; - - if(vertexX > m_boundingBox.maxX) - m_boundingBox.maxX = vertexX; - if(vertexY > m_boundingBox.maxY) - m_boundingBox.maxY = vertexY; - if(vertexZ > m_boundingBox.maxZ) - m_boundingBox.maxZ = vertexZ; - } - break; - - case CHUNK_TEXCOORDS: // texcoords list - modelFile->read((char*)&numVertices,2); - for(v=0; v < numVertices*2; v+=2){ - modelFile->read((char*)&vertexX,4); - modelFile->read((char*)&vertexY,4); - m_currentMesh->addTexcoord(vertexX); - m_currentMesh->addTexcoord(vertexY); - } - break; - - case CHUNK_FACES: - modelFile->read((char*)&m_tempUshort,2); - - for(v=0; v < m_tempUshort*3; v+=3){ - modelFile->read((char*)&usTemp1,2); - modelFile->read((char*)&usTemp2,2); - modelFile->read((char*)&usTemp3,2); - m_currentMesh->addFaceIndex(usTemp1); - m_currentMesh->addFaceIndex(usTemp2); - m_currentMesh->addFaceIndex(usTemp3); - - modelFile->read((char*)&usTemp,2); //face flags - } - - // Read face sub-chunks - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - break; - - case CHUNK_SMOOTHING_GROUP: - for(v=0; v < m_tempUshort; v++){ - modelFile->read((char*)&uiTemp,4); - m_currentMesh->addFaceSmoothing(uiTemp); - //if(DEBUG_OUTPUT) std::cout<<"Smoothing: "<read(¤tLetter,1); - name += currentLetter; - }while(currentLetter!='\0' && name.length()<20); - - modelFile->read((char*)&m_tempUshort,2); - - for(v=0; v < m_tempUshort; v++){ - modelFile->read((char*)&usTemp,2); - m_currentMesh->addMaterialFace(name, usTemp); - } - - name.erase(); - - break; - - case CHUNK_MATERIAL_BLOCK: - if(DEBUG_OUTPUT) std::cout<tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - - m_materials[m_currentMaterial->getName()] = *m_currentMaterial; - delete m_currentMaterial; - break; - - case CHUNK_MATERIAL_NAME: - // Read material name and add to current material - do{ - modelFile->read(¤tLetter,1); - name += currentLetter; - }while(currentLetter!='\0' && name.length()<20); - m_currentMaterial->setName(name); - if(DEBUG_OUTPUT) std::cout<<" Material: "<getName()<<"("<getName().size()<<")"<tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->loadTexture(m_filepath + m_tempString, chunkHeader); - hasTexture = true; - - break; - - case CHUNK_MAP_FILENAME: - // Read texture map filename - m_tempString.erase(); - do{ - modelFile->read(¤tLetter,1); - m_tempString += currentLetter; - }while(currentLetter!='\0' && m_tempString.length()<20); - break; - - case CHUNK_MATERIAL_TWO_SIDED: - m_currentMaterial->setTwoSided(true); - break; - - case CHUNK_DIFFUSE_COLOR: - // Read color sub-chunks - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setDiffuseColor(m_currentColor); - - break; - - case CHUNK_AMBIENT_COLOR: - // Read color sub-chunks - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setAmbientColor(m_currentColor); - - break; - - case CHUNK_SPECULAR_COLOR: - // Read color sub-chunks - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setSpecularColor(m_currentColor); - - break; - - case CHUNK_SPECULAR_EXPONENT: - // Read percent sub-chunk - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setSpecularExponent(m_tempFloat); - break; - - case CHUNK_SHININESS: - // Read percent sub-chunk - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setShininess(m_tempFloat); - break; - - case CHUNK_TRANSPARENCY: - // Read percent sub-chunk - readChunk(modelFile, modelFile->tellg(), chunkLength - (long(modelFile->tellg()) - offset)); - m_currentMaterial->setOpacity(1.0f - m_tempFloat); - break; - - ///////////////////// - // Global chunks - //////////////////// - - case CHUNK_RGB_FLOAT: - case CHUNK_RGB_FLOAT_GAMMA: - modelFile->read((char*)&m_currentColor[0],4); - modelFile->read((char*)&m_currentColor[1],4); - modelFile->read((char*)&m_currentColor[2],4); - break; - - case CHUNK_RGB_BYTE: - case CHUNK_RGB_BYTE_GAMMA: - modelFile->read((char*)&rgbByte,1); m_currentColor[0]=float(rgbByte)/255.f; - modelFile->read((char*)&rgbByte,1); m_currentColor[1]=float(rgbByte)/255.f; - modelFile->read((char*)&rgbByte,1); m_currentColor[2]=float(rgbByte)/255.f; - break; - - case CHUNK_PERCENT_INT: - modelFile->read((char*)&usTemp,2); - m_tempFloat = usTemp / 100.f; - break; - - case CHUNK_PERCENT_FLOAT: - modelFile->read((char*)&m_tempFloat,4); - m_tempFloat /= 100.f; - break; - - default:break; // any other chunk - - } - - // Go to the next chunk's header (if any left in object) - modelFile->seekg(offset + chunkLength, std::ios::beg); - } - -} - -void material3DS::loadTexture(std::string filename, int chunkType){ - - string lowerCaseStr = filename; - std::transform(lowerCaseStr.begin(),lowerCaseStr.end(),lowerCaseStr.begin(), ::tolower); - - if((lowerCaseStr.find(".jpg") == std::string::npos) && (lowerCaseStr.find(".png") == std::string::npos) && (lowerCaseStr.find(".tga") == std::string::npos) && (lowerCaseStr.find(".bmp") == std::string::npos)){ - std::cout<<"[3DS] WARNING: Could not load map '"< newMatFaces; - - // mark each face off as assigned to a material so - // we can figure out which faces have no material - std::vector assignedFaces; - std::vector::iterator assignedFacesIter; - assignedFaces.assign(m_faces.size() / 3, false); - - // loop over each material - std::map >::iterator matFacesIter; - for(matFacesIter=m_materialFaces.begin(); matFacesIter!=m_materialFaces.end(); ++matFacesIter){ - //std::cout<<" Faces in material '"<first<<"': "<second.size()<::iterator facesIter; - for(facesIter=matFacesIter->second.begin(); facesIter!=matFacesIter->second.end(); ++facesIter){ - newMatFaces.push_back(m_faces[((*facesIter)*3)]); - newMatFaces.push_back(m_faces[((*facesIter)*3)+1]); - newMatFaces.push_back(m_faces[((*facesIter)*3)+2]); - assignedFaces[*facesIter]=true; - } - - //replace the material's face indices with the actual face vertex indices - m_materialFaces[matFacesIter->first].assign(newMatFaces.begin(),newMatFaces.end()); - newMatFaces.clear(); - } - - // Make a default material and assign any unused faces to it - int numUnassignedFaces=0; - for(assignedFacesIter=assignedFaces.begin(); assignedFacesIter!=assignedFaces.end(); ++assignedFacesIter){ - if(*assignedFacesIter == false){ - numUnassignedFaces++; - //assign face to default material - } - } - //std::cout<<"numUnassignedFaces: "< >::iterator materialsIter; - for(materialsIter=m_materialFaces.begin(); materialsIter!=m_materialFaces.end(); ++materialsIter){ - const material3DS& currentMaterial = m_parentModel->getMaterial(materialsIter->first); - - // Bind texture map (if any) - bool hasTextureMap = currentMaterial.hasTextureMap(); - if(hasTextureMap) { - glBindTexture(GL_TEXTURE_2D, currentMaterial.getTextureMapId()); - } - else - glBindTexture(GL_TEXTURE_2D, 0); - - const GLfloat *specular = currentMaterial.getSpecularColor(); - float shininess = currentMaterial.getShininess(); - float adjustedSpecular[4] = {specular[0]*shininess, specular[1]*shininess, specular[2]*shininess, 1}; - -#ifndef TARGET_OPENGLES - glPushAttrib(GL_LIGHTING_BIT); -#endif - -#ifdef TARGET_OPENGLES - /* In OpenGL ES, the GL_FRONT_AND_BACK flag is the only flag that can be passed */ - materialFaces = GL_FRONT_AND_BACK; -#else - if(currentMaterial.isTwoSided()){ - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1); - materialFaces = GL_FRONT_AND_BACK; - } - else{ - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); - materialFaces = GL_FRONT; - } -#endif - - // Apply material colors - if(glIsEnabled(GL_LIGHTING)){ - //const GLfloat matZero[4]={0,0,0,0}; - const GLfloat matOne[4]={1,1,1,1}; - if(hasTextureMap){ //replace color with texture, but keep lighting contribution - glMaterialfv(materialFaces, GL_DIFFUSE, matOne); - } - else glMaterialfv(materialFaces, GL_DIFFUSE, currentMaterial.getDiffuseColor()); - glMaterialfv(materialFaces, GL_AMBIENT, currentMaterial.getAmbientColor()); - glMaterialfv(materialFaces, GL_SPECULAR, adjustedSpecular); - glMaterialf(materialFaces, GL_SHININESS, 128.f * currentMaterial.getSpecularExponent()); - } - else - { - const float* color = currentMaterial.getDiffuseColor(); - glColor4f(color[0], color[1], color[2], 1.0f); - } - - const std::vector *currentMatFaces = &(materialsIter->second); - numFaces = (int)currentMatFaces->size(); //number of faces in this material - - switch(m_drawMode){ - case DRAW_IMMEDIATE_MODE: - // This is like DRAW_VERTEX_ARRAY, but the array is not already constructed, so we need to do it here - for(face=0; facesecond[0])); - - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_NORMAL_ARRAY ); - if(hasTextureMap){ - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - } - - break; - - - case DRAW_VBO: - - glGenBuffers( 1 , &m_verticesArrayId ); - glBindBuffer( GL_ARRAY_BUFFER , m_verticesArrayId ); - glBufferData( GL_ARRAY_BUFFER , m_vertices.size() * sizeof( float ) , &m_vertices[0] , GL_STATIC_DRAW ); - - glGenBuffers( 1 , &m_normalsArrayId ); - glBindBuffer( GL_ARRAY_BUFFER , m_normalsArrayId ); - glBufferData( GL_ARRAY_BUFFER , m_normals.size() * sizeof( float ) , &m_normals[0] , GL_STATIC_DRAW ); - - if(hasTextureMap){ - glGenBuffers( 1 , &m_texcoordsArrayId ); - glBindBuffer( GL_ARRAY_BUFFER , m_texcoordsArrayId ); - glBufferData( GL_ARRAY_BUFFER , m_texcoords.size() * sizeof( float ) , &m_texcoords[0] , GL_STATIC_DRAW ); - } - - //vPos = getAttribLocation( - - break; - - default: - std::cout<<"[3DS] ERROR: Invalid mesh draw mode specified"<::iterator meshIter; - for(meshIter = m_meshes.begin(); meshIter != m_meshes.end(); meshIter++) - meshIter->draw( ); -} - diff --git a/addons/ofx3DModelLoader/src/3DS/model3DS.h b/addons/ofx3DModelLoader/src/3DS/model3DS.h deleted file mode 100644 index 08e324d608e..00000000000 --- a/addons/ofx3DModelLoader/src/3DS/model3DS.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - 3DS model loader - � Keith O'Conor 2005 - keith.oconor @ {cs.tcd.ie, gmail.com} -*/ - -#ifndef MODEL3DS_H -#define MODEL3DS_H - -#pragma warning(disable: 4786) //ignore truncated STL debug identifiers warnings - -#include "ofMain.h" -#include "texture3DS.h" -#include "Vector3DS.h" - -#include "ofx3DBaseLoader.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CHUNK_MAIN 0x4D4D -#define CHUNK_3D_EDITOR 0x3D3D -#define CHUNK_OBJECT_BLOCK 0x4000 -#define CHUNK_MESH 0x4100 -#define CHUNK_VERTICES 0x4110 -#define CHUNK_FACES 0x4120 -#define CHUNK_FACE_MATERIAL 0x4130 -#define CHUNK_SMOOTHING_GROUP 0x4150 -#define CHUNK_TEXCOORDS 0x4140 -#define CHUNK_MATERIAL_BLOCK 0xAFFF -#define CHUNK_MATERIAL_NAME 0xA000 -#define CHUNK_AMBIENT_COLOR 0xA010 -#define CHUNK_DIFFUSE_COLOR 0xA020 -#define CHUNK_SPECULAR_COLOR 0xA030 -#define CHUNK_SPECULAR_EXPONENT 0xA040 -#define CHUNK_SHININESS 0xA041 -#define CHUNK_TRANSPARENCY 0xA050 -#define CHUNK_MATERIAL_TWO_SIDED 0xA081 -#define CHUNK_TEXTURE_MAP 0xA200 -#define CHUNK_BUMP_MAP 0xA230 -#define CHUNK_REFLECTION_MAP 0xA220 -#define CHUNK_MAP_FILENAME 0xA300 -#define CHUNK_RGB_FLOAT 0x0010 -#define CHUNK_RGB_BYTE 0x0011 -#define CHUNK_RGB_BYTE_GAMMA 0x0012 -#define CHUNK_RGB_FLOAT_GAMMA 0x0013 -#define CHUNK_PERCENT_INT 0x0030 -#define CHUNK_PERCENT_FLOAT 0x0031 - -#define DRAW_IMMEDIATE_MODE 0x01 -#define DRAW_VERTEX_ARRAY 0x02 -#define DRAW_VBO 0x03 - -#define DEBUG_OUTPUT false - -class model3DS; -class mesh3DS; -class material3DS; - -typedef unsigned short ushort; - - /////////////////////////////////////////////////////// - // 3DS Material - // Describes a material to be used by a mesh3DS -///////////////////////////////////////////////////// - -class material3DS{ -private: - std::string m_name; - float m_diffuseColor[3]; - float m_ambientColor[3]; - float m_specularColor[3]; - float m_specularExponent; - float m_shininess; - float m_opacity; - GLuint m_textureMapId; - GLuint m_bumpMapId; - bool m_hasTextureMap; - bool m_hasBumpMap; - bool m_twoSided; - -public: - material3DS():m_hasTextureMap(false),m_hasBumpMap(false),m_twoSided(false){} - void loadTexture(std::string filename, int mapType); - - std::string getName()const{return m_name;} - const float* getDiffuseColor()const{return m_diffuseColor;} - const float* getAmbientColor()const{return m_ambientColor;} - const float* getSpecularColor()const{return m_specularColor;} - float getSpecularExponent()const{return m_specularExponent;} - float getShininess()const{return m_shininess;} - float getOpacity()const{return m_opacity;} - GLuint getTextureMapId()const{return m_textureMapId;} - GLuint getBumpMapId()const{return m_bumpMapId;} - bool hasTextureMap()const{return m_hasTextureMap;} - bool hasBumpMap()const{return m_hasBumpMap;} - bool isTwoSided()const{return m_twoSided;} - - void setName(const std::string newName){m_name = newName;} - void setDiffuseColor(const float* newColor){memcpy(m_diffuseColor,newColor,sizeof(float)*3);} - void setAmbientColor(const float* newColor){memcpy(m_ambientColor,newColor,sizeof(float)*3);} - void setSpecularColor(const float* newColor){memcpy(m_specularColor,newColor,sizeof(float)*3);} - void setShininess(const float newShininess){m_shininess = newShininess;} - void setSpecularExponent(const float newExponent){m_specularExponent = newExponent;} - void setOpacity(const float newOpacity){m_opacity = newOpacity;} - void setTwoSided(const bool isTwoSided){m_twoSided = isTwoSided;} - -}; - - /////////////////////////////////////////////////////// - // 3DS Mesh - // Contains all vertex, face, texcoord & normal data -/////////////////////////////////////////////////////// - -class mesh3DS{ -private: - std::string m_name; - std::string m_materialName; - model3DS *m_parentModel; - - std::vector m_vertices; - std::vector m_normals; - std::vector m_faces; - std::vector m_faceSmoothing; - std::vector m_texcoords; - std::map > m_materialFaces; - - //VBO IDs - GLuint m_verticesArrayId; - GLuint m_normalsArrayId; - GLuint m_texcoordsArrayId; - - unsigned int m_drawMode; - -public: - - mesh3DS(model3DS *parentModel):m_parentModel(parentModel){} - - void buildMesh(); - void calculateNormals(); - void sortFacesByMaterial(); - void draw(); - - void addVertex(const float vertex){m_vertices.push_back(vertex);} - void addFaceIndex(const ushort faceIndex){m_faces.push_back(faceIndex);} - void addMaterialFace(const std::string &name, const ushort faceIndex){m_materialFaces[name].push_back(faceIndex);} - void addFaceSmoothing(const unsigned int smoothing){m_faceSmoothing.push_back(smoothing);} - void addTexcoord(const float texcoord){m_texcoords.push_back(texcoord);} - - std::string getMaterial()const{return m_materialName;} - std::string getName()const{return m_name;} - int getNumFaces()const{return (int)m_faces.size();} - - void setMaterial(const std::string &newMat){m_materialName = newMat;} - void setName(const std::string newName){m_name = newName;} - void setDrawMode(const unsigned int newDrawMode){m_drawMode = newDrawMode;} -}; - - ////////////////////////////////////////////////////////////////// - // 3DS Model - // Contains all the meshes & materials that make up a 3DS model -////////////////////////////////////////////////////////////////// - -typedef struct{ - float minX,maxX; - float minY,maxY; - float minZ,maxZ; -} boundingBox3DS; - -class model3DS : public ofx3DBaseLoader{ -private: - std::string m_filename; - std::string m_filepath; - std::vector m_meshes; - std::map m_materials; - unsigned int m_drawMode; - boundingBox3DS m_boundingBox; - float m_scale; - float m_centerX, m_centerY, m_centerZ; - - // temporaries used while reading chunks - mesh3DS *m_currentMesh; - material3DS *m_currentMaterial; - std::vector *m_currentMaterialFaces; - float m_currentColor[3]; - ushort m_tempUshort; - float m_tempFloat; - std::string m_tempString; - - void readChunk(std::ifstream *modelFile, const int objectStart, const int objectLength); - - // Private copy and assignment constructors - // to prevent object being copied - model3DS(const model3DS &model); - model3DS &operator=(const model3DS &model); - -public: - model3DS(); - void loadModel(const char* filename, float scale = 1); - void loadModel(string filename, float scale); - void draw(); - - std::string getFilename(){return m_filename;} - const material3DS& getMaterial(const std::string &matName){return m_materials[matName];} -}; - -#endif //MODEL3DS_H diff --git a/addons/ofx3DModelLoader/src/3DS/texture3DS.cpp b/addons/ofx3DModelLoader/src/3DS/texture3DS.cpp deleted file mode 100644 index 633d9d5bf2f..00000000000 --- a/addons/ofx3DModelLoader/src/3DS/texture3DS.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - BMP texture loader - � Keith O'Conor 2005 - keith.oconor @ {cs.tcd.ie, gmail.com} - - adapted for openFrameworks by Theodore Watson - theo@openframeworks.cc -*/ - -#include "texture3DS.h" - -texture3DS::texture3DS(string filename, const int textureId){ - - ofImage img; - if( !img.load(filename) ){ - ofLogError("texture3DS") << "couldn't open " << filename; - } - - m_width = img.getWidth(); - m_height = img.getHeight(); - switch( img.getImageType() ){ - case OF_IMAGE_UNDEFINED: - m_bpp = 0; - break; - - case OF_IMAGE_GRAYSCALE: - m_bpp = 8; - break; - - case OF_IMAGE_COLOR: - m_bpp = 24; - break; - - case OF_IMAGE_COLOR_ALPHA: - m_bpp = 32; - break; - - default: - m_bpp = 0; - break; - } - - if( m_width <= 0 || m_height <= 0){ - ofLogError("texture3DS") << "dimensions less than 0 \"" << filename << "\": " << m_width << "x" << m_height; - } - - if(m_bpp != 32 && m_bpp != 24){ - ofLogError("texture3DS") << "invalid texture color depth \"" << filename << "\", must be uncompressed 24/32bpp png, jpg, bmp, or tga"; - return; - } - - // Determine format - int fileFormat, internalFormat; - switch(m_bpp){ - case 24:fileFormat = GL_RGB; internalFormat = GL_RGB; break; - case 32:fileFormat = GL_RGBA; internalFormat = GL_RGBA; break; - default: - ofLogError("texture3DS") << "invalid texture color depth \"" << filename << "\", must be uncompressed 24/32bpp"; - return; - } - - - // FLIP THE PIXELS - //we need to flip the image vertically - unsigned char * ptrToPixels = img.getPixels().getData(); - int bytesPP = (m_bpp / 8); - - //this extra allocation is because of a glu bug - http://osdir.com/ml/video.mesa3d.devel/2005-02/msg00035.html - unsigned char * flippedPixels = new unsigned char[bytesPP * m_width * (m_height+1)]; - unsigned char * ptrToFlipped = flippedPixels; - - int numBytesPerLine = m_width * bytesPP; - - //go to the beginning of the bottom line of pixels of the image - ptrToPixels += ( numBytesPerLine * (m_height-1) ); - - //then step through line at a time copying the whole line from the original - //to the flipped pixels - //- the original starts at the bottom and goes up - //- the flipped starts at the top and goes down - for(int y = 0; y < m_height; y++){ - memcpy(ptrToFlipped, ptrToPixels, numBytesPerLine * sizeof( char ) ); - ptrToPixels -= numBytesPerLine; - ptrToFlipped += numBytesPerLine; - } - - - // Bind texture ID to load - glBindTexture(GL_TEXTURE_2D, textureId); - - // Set texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // Upload texture to card with bound texture ID -#ifdef TARGET_OPENGLES - glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_width, m_height, 0, fileFormat, GL_UNSIGNED_BYTE, flippedPixels); -#else - gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, m_width, m_height, fileFormat, GL_UNSIGNED_BYTE, flippedPixels); -#endif - - ofLogVerbose("texture3DS") << "loaded \"" << filename << "\""; -} diff --git a/addons/ofx3DModelLoader/src/3DS/texture3DS.h b/addons/ofx3DModelLoader/src/3DS/texture3DS.h deleted file mode 100644 index 94a6c815a23..00000000000 --- a/addons/ofx3DModelLoader/src/3DS/texture3DS.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "ofMain.h" - - -class texture3DS{ -private: - int m_width; - int m_height; - int m_bpp; - int m_format; - -public: - texture3DS(std::string filename, const int textureId); - - int getWidth(){return m_width;} - int getHeight(){return m_width;} - int getBpp(){return m_bpp;} - -}; - diff --git a/addons/ofx3DModelLoader/src/ofx3DBaseLoader.h b/addons/ofx3DModelLoader/src/ofx3DBaseLoader.h deleted file mode 100644 index a0cff5ffcd6..00000000000 --- a/addons/ofx3DModelLoader/src/ofx3DBaseLoader.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -class ofx3DBaseLoader{ - - public: - ofx3DBaseLoader(){ - hasTexture = false; - } - virtual void loadModel(string model, float scale = 1.0){} - virtual void loadModel(string model){} - virtual ~ofx3DBaseLoader(){} - virtual void draw(){ ofLogNotice("ofx3DBaseLoader") << "draw() not implemented"; } - virtual void draw( GLint paramModelTexture ){ ofLogNotice("ofx3DBaseLoader") << "draw() not implemented"; } - - bool hasTexture; - -}; \ No newline at end of file diff --git a/addons/ofx3DModelLoader/src/ofx3DModelLoader.h b/addons/ofx3DModelLoader/src/ofx3DModelLoader.h deleted file mode 100644 index 92735526e05..00000000000 --- a/addons/ofx3DModelLoader/src/ofx3DModelLoader.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "ofMain.h" -#include "model3DS.h" - -class ofx3DModelLoader{ - - public: - ofx3DModelLoader(); - ~ofx3DModelLoader(); - - void loadModel(string modelName, float scale = 1.0); - void setPosition(float x, float y, float z); - void setScale(float x, float y, float z); - void setRotation(int which, float angle, float rot_x, float rot_y, float r_z); - void draw(); - - vector rotAngle; - vector rotAxis; - ofPoint scale; - ofPoint pos; - - int numRotations; - ofx3DBaseLoader * model; - -}; diff --git a/addons/ofx3DModelLoader/src/ofx3dModelLoader.cpp b/addons/ofx3DModelLoader/src/ofx3dModelLoader.cpp deleted file mode 100644 index f446a8e7c58..00000000000 --- a/addons/ofx3DModelLoader/src/ofx3dModelLoader.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "ofx3DModelLoader.h" - -//------------------------------------------- -static string getExtension( string filename ){ - std::string::size_type idx; - idx = filename.rfind('.'); - - if(idx != std::string::npos){ - return filename.substr(idx+1); - } - else{ - return ""; - } -} - -//------------------------------------------- -ofx3DModelLoader::ofx3DModelLoader(){ - numRotations = 0; - rotAngle.clear(); - rotAxis.clear(); - scale = ofPoint(1, 1, 1); - - model = NULL; -} - -//------------------------------------------ -void ofx3DModelLoader::loadModel(string modelName, float scale){ - if( model != NULL)delete model; - - string ext = getExtension( modelName ); - if( ext == "3ds" || ext == "3DS" ){ - model = new model3DS(); - ofLogVerbose("ofx3DModelLoader") << "loadModel(): loading \"" << modelName << "\""; - model->loadModel( modelName.c_str(), scale); - } - else{ - ofLogError("ofx3DModelLoader") << "loadModel(): couldn't load \"" - << modelName << "\", not a .3ds or .3DS model file"; - } -} - -//------------------------------------------- -ofx3DModelLoader::~ofx3DModelLoader(){ - if( model != NULL )delete model; -} - -//------------------------------------------- -void ofx3DModelLoader::setPosition(float x, float y, float z){ - pos.x = x; - pos.y = y; - pos.z = z; -} - -void ofx3DModelLoader::setScale(float x, float y, float z){ - scale.x = x; - scale.y = y; - scale.z = z; -} - -//------------------------------------------- -void ofx3DModelLoader::setRotation(int which, float angle, float rot_x, float rot_y, float rot_z){ - - if(which + 1 > numRotations){ - int diff = 1 + (which - numRotations); - for(int i = 0; i < diff; i++){ - rotAngle.push_back(0); - rotAxis.push_back(ofPoint()); - } - numRotations = rotAngle.size(); - } - - rotAngle[which] = angle; - rotAxis[which].x = rot_x; - rotAxis[which].y = rot_y; - rotAxis[which].z = rot_z; -} - -//------------------------------------------- -void ofx3DModelLoader::draw(){ - glPushMatrix(); - glTranslatef(pos.x, pos.y, pos.z); - glScalef(scale.x, scale.y, scale.z); - for(int i = 0; i < numRotations; i++){ - glRotatef(rotAngle[i], rotAxis[i].x, rotAxis[i].y, rotAxis[i].z); - } - - glShadeModel(GL_SMOOTH); - if( model->hasTexture) - glEnable(GL_TEXTURE_2D); - model->draw(); - if( model->hasTexture) - glDisable(GL_TEXTURE_2D); - glPopMatrix(); -} diff --git a/addons/ofxAndroid/ofAndroidLib/build.gradle b/addons/ofxAndroid/ofAndroidLib/build.gradle index 10ca43cad6b..2f229faa3d5 100644 --- a/addons/ofxAndroid/ofAndroidLib/build.gradle +++ b/addons/ofxAndroid/ofAndroidLib/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 19 - buildToolsVersion "21.1.1" + compileSdkVersion 22 + buildToolsVersion "23.0.1" defaultConfig { minSdkVersion 8 - targetSdkVersion 17 + targetSdkVersion 22 versionCode 1 versionName "1.0" } @@ -33,38 +33,3 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } -/** Configure OpenFrameworks by writing paths.make */ -task configureOF(dependsOn: rootProject.ofNdkSetup) { - def projectRoot = file("$projectDir/../../../libs/openFrameworksCompiled/project") - ext.projectRoot = projectRoot.absolutePath - - doLast { - def pathsFile = file("$projectRoot/android/paths.make") - pathsFile.withPrintWriter { out -> - out.println("NDK_ROOT=${rootProject.ofNdkSetup.ext.ndkDirectory}") - out.println("SDK_ROOT=${rootProject.ofNdkSetup.ext.sdkDirectory}") - } - } -} - -task compileReleaseOF(dependsOn: configureOF) << { - rootProject.ofRunMake(["-C", configureOF.ext.projectRoot, "PLATFORM_OS=Android", "Release"]) -} - -task compileDebugOF(dependsOn: configureOF) << { - rootProject.ofRunMake(["-C", configureOF.ext.projectRoot, "PLATFORM_OS=Android", "Debug"]) -} - -task cleanOF(dependsOn: configureOF) << { - rootProject.ofRunMake(["-C", configureOF.ext.projectRoot, "PLATFORM_OS=Android", "clean"]) -} - - -clean { - dependsOn cleanOF -} - -project.afterEvaluate { - compileDebugNdk.dependsOn(compileDebugOF) - compileReleaseNdk.dependsOn(compileReleaseOF) -} diff --git a/addons/ofxAndroid/ofAndroidLib/project.properties b/addons/ofxAndroid/ofAndroidLib/project.properties index ca8132402ef..c57400d008a 100644 --- a/addons/ofxAndroid/ofAndroidLib/project.properties +++ b/addons/ofxAndroid/ofAndroidLib/project.properties @@ -9,4 +9,4 @@ android.library=true # Project target. -target=android-21 +target=android-19 diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java index 0ff94d52c0d..5310b936e55 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java +++ b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java @@ -218,12 +218,9 @@ public void run() { } - String app_name=""; try { int app_name_id = Class.forName(packageName+".R$string").getField("app_name").getInt(null); - app_name = ofActivity.getResources().getText(app_name_id).toString().toLowerCase(Locale.US); - Log.i("OF","app name: " + app_name); - + if(copydata){ StatFs stat = new StatFs(dataPath); double sdAvailSize = (double)stat.getAvailableBlocks() @@ -238,8 +235,7 @@ public void run() { fileId = files[i].getInt(null); String resName = ofActivity.getResources().getText(fileId).toString(); fileName = resName.substring(resName.lastIndexOf("/")); - Log.i("OF","checking " + fileName); - if(fileName.equals("/" + app_name + "resources.zip")){ + if(fileName.equals("/ofdataresources.zip")){ from = ofActivity.getResources().openRawResource(fileId); try{ @@ -1023,25 +1019,34 @@ public static boolean isApplicationSetup(){ public static native boolean hasNeon(); static { - try{ - Log.i("OF","static init"); - System.loadLibrary("neondetection"); - if(hasNeon()){ - Log.i("OF","loading neon optimized library"); - System.loadLibrary("OFAndroidApp_neon"); - }else{ - Log.i("OF","loading not-neon optimized library"); - System.loadLibrary("OFAndroidApp"); - } - }catch(Throwable e){ - Log.i("OF","failed neon detection, loading not-neon library",e); - System.loadLibrary("OFAndroidApp"); - } - Log.i("OF","initializing app"); + + Log.i("OF","static init"); + + try { + Log.i("OF","loading x86 library"); + System.loadLibrary("OFAndroidApp_x86"); + } + catch(Throwable ex) { + Log.i("OF","failed x86 loading, trying neon detection",ex); + + try{ + System.loadLibrary("neondetection"); + if(hasNeon()){ + Log.i("OF","loading neon optimized library"); + System.loadLibrary("OFAndroidApp_neon"); + } + else{ + Log.i("OF","loading not-neon optimized library"); + System.loadLibrary("OFAndroidApp"); + } + }catch(Throwable ex2){ + Log.i("OF","failed neon detection, loading not-neon library",ex2); + System.loadLibrary("OFAndroidApp"); + } + } + Log.i("OF","initializing app"); } - - public static SurfaceView getGLContentView() { return mGLView; } diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java index 026a828465a..529b7f86cb7 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java +++ b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java @@ -1,19 +1,15 @@ package cc.openframeworks; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; - -import android.annotation.SuppressLint; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.Camera.Size; +import android.os.Build; import android.util.Log; import android.view.OrientationEventListener; @@ -28,67 +24,88 @@ public OFAndroidVideoGrabber(){ public int getId(){ return instanceId; } - + public static boolean supportsTextureRendering(){ + return Build.VERSION.SDK_INT >= 11; + } + + public void setTexture(int texID){ + if (Build.VERSION.SDK_INT < 11) { + return; + } + try { - Class.forName("android.graphics.SurfaceTexture"); - return true; - } catch (ClassNotFoundException e) { - return false; + // Create surface texture instance + surfaceTexture = new SurfaceTexture(texID); + + // set texture as preview surface for camera + camera.setPreviewTexture(surfaceTexture); + } catch (Exception e1) { + Log.e("OF","Error initializing gl surface",e1); } } - public void initGrabber(int w, int h, int _targetFps){ - initGrabber(w,h,_targetFps,0); + public void close(){ + stopGrabber(); } - - public void setTexture(int texID){ - if(supportsTextureRendering()){ - try { - // get SurfaceTexture class and create an instance - Class surfaceTextureClass = Class.forName("android.graphics.SurfaceTexture"); - Constructor constructor = surfaceTextureClass.getConstructor(int.class); - surfaceTexture = constructor.newInstance(texID); - - // set texture as preview surface for camera - Method setPreviewTexture = camera.getClass().getMethod("setPreviewTexture", surfaceTextureClass); - setPreviewTexture.invoke(camera, surfaceTexture); - } catch (Exception e1) { - Log.e("OF","Error initializing gl surface",e1); - } + + public int getNumCameras(){ + if (Build.VERSION.SDK_INT < 9) { + return 1; } + + return Camera.getNumberOfCameras(); } - - public void initGrabber(int w, int h, int _targetFps, int texID){ + + public int getCameraFacing(int facing){ + if (Build.VERSION.SDK_INT < 9) { + return 0; + } + + int numCameras = Camera.getNumberOfCameras(); + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + for(int i=0;i cameraInfoClass = Class.forName("android.hardware.Camera$CameraInfo"); - Object cameraInfo = null; - Field field = null; - if ( cameraInfoClass != null ) { - cameraInfo = cameraInfoClass.newInstance(); - } - if ( cameraInfo != null ) { - field = cameraInfo.getClass().getField( "facing" ); - } - Method getCameraInfoMethod = Camera.class.getMethod( "getCameraInfo", Integer.TYPE, cameraInfoClass ); - for(int i=0;i= 9) { + camera = Camera.open(deviceID); + } else { camera = Camera.open(); - } + } + } catch (Exception e) { + Log.e("OF","Error trying to open specific camera, trying default",e); + camera = Camera.open(); + } + + if(_texID != -1) { + texID = _texID; + setTexture(texID); } - - setTexture(texID); Camera.Parameters config = camera.getParameters(); @@ -106,18 +123,18 @@ public void initGrabber(int w, int h, int _targetFps, int texID){ for(Integer i : config.getSupportedPreviewFrameRates()){ Log.i("OF",i.toString()); } - + Log.i("OF", "Grabber default format: " + config.getPreviewFormat()); Log.i("OF", "Grabber default preview size: " + config.getPreviewSize().width + "," + config.getPreviewSize().height); config.setPictureSize(w, h); config.setPreviewSize(w, h); config.setPreviewFormat(ImageFormat.NV21); - try{ + try{ Method setRecordingHint = config.getClass().getMethod("setRecordingHint",boolean.class); setRecordingHint.invoke(config, true); - }catch(Exception e){ - Log.i("OF","couldn't set recording hint"); - } + }catch(Exception e){ + Log.i("OF","couldn't set recording hint"); + } try{ camera.setParameters(config); }catch(Exception e){ @@ -129,61 +146,136 @@ public void initGrabber(int w, int h, int _targetFps, int texID){ height = config.getPreviewSize().height; if(width!=w || height!=h) Log.w("OF","camera size different than asked for, resizing (this can slow the app)"); - - if(_targetFps!=-1){ - config = camera.getParameters(); - config.setPreviewFrameRate(_targetFps); - try{ - camera.setParameters(config); - }catch(Exception e){ - Log.e("OF","couldn init camera", e); + targetFps = _targetFps; + + // If target fps is not defined, then take the maximum fps + if(targetFps == -1) { + for(Integer i : config.getSupportedPreviewFrameRates()){ + if(targetFps < i) { + targetFps = i; + } } } - - targetFps = _targetFps; - Log.i("OF","camera settings: " + width + "x" + height); - - // it actually needs (width*height) * 3/2 + + Log.i("OF", "Grabber fps: " + targetFps); + config = camera.getParameters(); + config.setPreviewFrameRate(targetFps); + try{ + camera.setParameters(config); + } catch(Exception e){ + Log.e("OF","couldn init camera", e); + } + + Log.i("OF", "camera settings: " + width + "x" + height); + int bufferSize = width * height; - bufferSize = bufferSize * ImageFormat.getBitsPerPixel(config.getPreviewFormat()) / 8; - buffer = new byte[bufferSize]; - - orientationListener = new OrientationListener(OFAndroid.getContext()); - orientationListener.enable(); + if(buffer == null || buffer.length != bufferSize) { + // it actually needs (width*height) * 3/2 + bufferSize = bufferSize * ImageFormat.getBitsPerPixel(config.getPreviewFormat()) / 8; + buffer[0] = new byte[bufferSize]; + buffer[1] = new byte[bufferSize]; + } + + //orientationListener = new OrientationListener(OFAndroid.getContext()); + //orientationListener.enable(); thread = new Thread(this); thread.start(); initialized = true; } - - public void update(){ - if(supportsTextureRendering()){ - Class surfaceTextureClass; + + public void stopGrabber(){ + if(initialized){ + Log.i("OF", "stopping camera"); + camera.stopPreview(); + previewStarted = false; try { - surfaceTextureClass = Class.forName("android.graphics.SurfaceTexture"); - Method updateTexImage = surfaceTextureClass.getMethod("updateTexImage"); - if(surfaceTexture != null) updateTexImage.invoke(surfaceTexture); + thread.join(); + } catch (InterruptedException e) { + Log.e("OF", "problem trying to close camera thread", e); + } + camera.setPreviewCallback(null); + try { + if (Build.VERSION.SDK_INT >= 11) { + camera.setPreviewTexture(surfaceTexture); + } } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); } - //SurfaceTexture surface = (SurfaceTexture)surfaceTexture; - //surface.updateTexImage(); + camera.release(); + //orientationListener.disable(); + initialized = false; + } + } + + public void update(){ + try { + if (Build.VERSION.SDK_INT >= 11) { + surfaceTexture.updateTexImage(); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + + try { + // Add the other buffer to the callback queue to indicate we are ready for new frame + camera.addCallbackBuffer(buffer[bufferFlipFlip?0:1]); + bufferFlipFlip = !bufferFlipFlip; + } catch (Exception e) { + Log.e("OF", "error adding buffer", e); + } + } + + // Getting the current frame data as byte array + // Notice: this locks the thread, you need to call releaseFrameData() when done + public byte[] getFrameData(){ + //threadLock.lock(); + return buffer[bufferFlipFlip?0:1]; + } + + public void releaseFrameData(){ + //threadLock.unlock(); } public void getTextureMatrix(float[] mtx) { - Class surfaceTextureClass; + if (android.os.Build.VERSION.SDK_INT < 9) { + return; + } + try { - surfaceTextureClass = Class.forName("android.graphics.SurfaceTexture"); - Method getTransformMatrix = surfaceTextureClass.getMethod("getTransformMatrix",float[].class); - if(surfaceTexture != null) getTransformMatrix.invoke(surfaceTexture,mtx); + if(surfaceTexture != null) surfaceTexture.getTransformMatrix(mtx); + } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } - + + public int getCameraOrientation(int _deviceID){ + if (android.os.Build.VERSION.SDK_INT < 9) { + return 0; + } + + if(_deviceID == -1) _deviceID = deviceID; + + Camera.CameraInfo info = null; + info = new Camera.CameraInfo(); + Camera.getCameraInfo(_deviceID, info); + return info.orientation; + } + + public int getFacingOfCamera(int _deviceID){ + if (android.os.Build.VERSION.SDK_INT < 9) { + return 0; + } + + if(_deviceID == -1) _deviceID = deviceID; + + Camera.CameraInfo info = new Camera.CameraInfo(); + Camera.getCameraInfo(_deviceID, info); + return info.facing; + } + public boolean setAutoFocus(boolean autofocus){ if(initialized){ @@ -221,25 +313,7 @@ public void onAutoFocus(boolean success, Camera camera) { @Override public void appStop(){ if(initialized){ - Log.i("OF","stopping camera"); - camera.stopPreview(); - previewStarted = false; - try { - thread.join(); - } catch (InterruptedException e) { - Log.e("OF", "problem trying to close camera thread", e); - } - camera.setPreviewCallback(null); - if(supportsTextureRendering()){ - try { - Class surfaceTextureClass = Class.forName("android.graphics.SurfaceTexture"); - Method setPreviewTexture = camera.getClass().getMethod("setPreviewTexture", surfaceTextureClass); - setPreviewTexture.invoke(camera, (Object)null); - } catch (Exception e) { - } - } - camera.release(); - orientationListener.disable(); + stopGrabber(); } } @@ -252,7 +326,7 @@ public void appPause(){ @Override public void appResume(){ if(initialized){ - orientationListener.enable(); + //orientationListener.enable(); } } @@ -260,42 +334,27 @@ public void onPreviewFrame(byte[] data, Camera camera) { //Log.i("OF","video buffer length: " + data.length); //Log.i("OF", "size: " + camera.getParameters().getPreviewSize().width + "x" + camera.getParameters().getPreviewSize().height); //Log.i("OF", "format " + camera.getParameters().getPreviewFormat()); + + // Tell the of app that a new frame has arrived newFrame(data, width, height, instanceId); - if(addBufferMethod!=null){ - try { - addBufferMethod.invoke(camera, buffer); - } catch (Exception e) { - Log.e("OF","error adding buffer",e); - } - } - //camera.addCallbackBuffer(data); - + + // Don't add in the buffer again, but instead wait for the cpp code to call update } public void run() { thread.setPriority(Thread.MAX_PRIORITY); try { - addBufferMethod = Camera.class.getMethod("addCallbackBuffer", byte[].class); - addBufferMethod.invoke(camera, buffer); - Camera.class.getMethod("setPreviewCallbackWithBuffer", Camera.PreviewCallback.class).invoke(camera, this); + // Add the first callback buffer to the queue + camera.addCallbackBuffer(buffer[0]); + camera.setPreviewCallbackWithBuffer(this); + Log.i("OF","setting camera callback with buffer"); } catch (SecurityException e) { - Log.e("OF","security exception, check permissions in your AndroidManifest to acces to the camera",e); - } catch (NoSuchMethodException e) { - try { - Camera.class.getMethod("setPreviewCallback", Camera.PreviewCallback.class).invoke(camera, this); - Log.i("OF","setting camera callback without buffer"); - } catch (SecurityException e1) { - Log.e("OF","security exception, check permissions in your AndroidManifest to acces to the camera",e1); - } catch (Exception e1) { - Log.e("OF","cannot create callback, the camera can only be used from api v7",e1); - } + Log.e("OF","security exception, check permissions in your AndroidManifest to access to the camera",e); } catch (Exception e) { Log.e("OF","error adding callback",e); } - //camera.addCallbackBuffer(buffer); - //camera.setPreviewCallbackWithBuffer(this); try{ camera.startPreview(); previewStarted = true; @@ -304,6 +363,7 @@ public void run() { } } + // Currently not used private class OrientationListener extends OrientationEventListener{ private int rotation = -1; @@ -337,19 +397,17 @@ public void onOrientationChanged(int orientation) { private Camera camera; private int deviceID = -1; - private byte[] buffer; + private byte[][] buffer = {null, null}; + private boolean bufferFlipFlip = false; private int width, height, targetFps; + private int texID; private Thread thread; private int instanceId; private static int nextId=0; public static Map camera_instances = new HashMap(); - //private static OFCameraSurface cameraSurface = null; - //private static ViewGroup rootViewGroup = null; private boolean initialized = false; private boolean previewStarted = false; - private Method addBufferMethod; - private OrientationListener orientationListener; - Object surfaceTexture; + SurfaceTexture surfaceTexture; } diff --git a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp index c734fe6aa3d..e7d9864b8ff 100644 --- a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp +++ b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp @@ -133,12 +133,6 @@ void ofAppAndroidWindow::setup(const ofGLESWindowSettings & settings){ } ofGetJNIEnv()->CallStaticVoidMethod(javaClass,method,glesVersion); - - if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){ - static_cast(currentRenderer.get())->setup(settings.glesVersion,0); - }else{ - static_cast(currentRenderer.get())->setup(); - } } void ofAppAndroidWindow::update(){ @@ -238,7 +232,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env; ofJavaVM = vm; - ofLog(OF_LOG_NOTICE,"JNI_OnLoad called"); + ofLogVerbose() << "JNI_OnLoad called"; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ofLogError("ofAppAndroidWindow") << "failed to get environment using GetEnv()"; return -1; @@ -268,7 +262,7 @@ Java_cc_openframeworks_OFAndroid_onPause( JNIEnv* env, jobject thiz ){ void Java_cc_openframeworks_OFAndroid_onResume( JNIEnv* env, jobject thiz ){ - ofLogNotice("ofAppAndroidWindow") << "onResume"; + ofLogVerbose("ofAppAndroidWindow") << "onResume"; if(paused){ ofNotifyEvent(ofxAndroidEvents().resume); paused = false; @@ -289,21 +283,21 @@ Java_cc_openframeworks_OFAndroid_onDestroy( JNIEnv* env, jclass thiz ){ void Java_cc_openframeworks_OFAndroid_onSurfaceDestroyed( JNIEnv* env, jclass thiz ){ surfaceDestroyed = true; - ofLogNotice("ofAppAndroidWindow") << "onSurfaceDestroyed"; + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceDestroyed"; ofNotifyEvent(ofxAndroidEvents().unloadGL); } void Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ if(appSetup){ - ofLogNotice("ofAppAndroidWindow") << "onSurfaceCreated"; + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated"; if(!surfaceDestroyed){ ofNotifyEvent(ofxAndroidEvents().unloadGL); } ofNotifyEvent(ofxAndroidEvents().reloadGL); - ofPushStyle(); + window->renderer()->pushStyle(); window->renderer()->setupGraphicDefaults(); - ofPopStyle(); + window->renderer()->popStyle(); surfaceDestroyed = false; }else{ if(window->renderer()->getType()==ofGLProgrammableRenderer::TYPE){ @@ -311,18 +305,20 @@ Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ }else{ static_cast(window->renderer().get())->setup(); } - ofLogNotice() << "renderer created"; } } void Java_cc_openframeworks_OFAndroid_setup( JNIEnv* env, jclass thiz, jint w, jint h ) { - ofLogNotice("ofAppAndroidWindow") << "setup"; + ofLogVerbose("ofAppAndroidWindow") << "setup " << w << "x" << h; paused = false; sWindowWidth = w; sWindowHeight = h; + window->renderer()->startRender(); + if(bSetupScreen) window->renderer()->setupScreen(); window->events().notifySetup(); + window->renderer()->finishRender(); appSetup = true; } @@ -380,10 +376,10 @@ Java_cc_openframeworks_OFAndroid_render( JNIEnv* env, jclass thiz ) events.pop(); } } - window->events().notifyUpdate(); window->renderer()->startRender(); + window->events().notifyUpdate(); if(bSetupScreen) window->renderer()->setupScreen(); window->events().notifyDraw(); window->renderer()->finishRender(); diff --git a/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp b/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp index 8804e59678c..e70da6bb4c3 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp +++ b/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp @@ -45,7 +45,7 @@ ofxAndroidSoundStream::~ofxAndroidSoundStream(){ ofRemoveListener(ofxAndroidEvents().resume,this,&ofxAndroidSoundStream::resume); } -vector ofxAndroidSoundStream::getDeviceList() const{ +std::vector ofxAndroidSoundStream::getDeviceList(ofSoundDevice::Api api) const{ ofLogWarning("ofxAndroidSoundStream") << "getDeviceList() isn't implemented on android"; return vector(); } @@ -62,28 +62,28 @@ void ofxAndroidSoundStream::setOutput(ofBaseSoundOutput * _soundOutput){ soundOutputPtr = _soundOutput; } -bool ofxAndroidSoundStream::setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ +bool ofxAndroidSoundStream::setup(const ofSoundStreamSettings & settings){ if(instance!=NULL && instance!=this){ ofLogError("ofxAndroidSoundStream") << "setup(): multiple instances detected, only one instance allowed"; return false; } // Find the minimum input buffer size allowed by the Android device - int input_buffer_size = inChannels*getMinInBufferSize(sampleRate,inChannels) * 2; + int input_buffer_size = settings.numInputChannels*getMinInBufferSize(settings.sampleRate,settings.numInputChannels) * 2; // setup size of input circular-buffer input_buffer.setup(input_buffer_size,0); // deallocate and reallocate if setup() is called more than once - in_float_buffer.allocate(bufferSize,inChannels); - in_float_buffer.setSampleRate(sampleRate); - out_float_buffer.allocate(bufferSize,outChannels); - out_float_buffer.setSampleRate(sampleRate); + in_float_buffer.allocate(settings.bufferSize,settings.numInputChannels); + in_float_buffer.setSampleRate(settings.sampleRate); + out_float_buffer.allocate(settings.bufferSize,settings.numOutputChannels); + out_float_buffer.setSampleRate(settings.sampleRate); tickCount = 0; - requestedBufferSize = bufferSize; - totalOutRequestedBufferSize = bufferSize*outChannels; - totalInRequestedBufferSize = bufferSize*inChannels; + requestedBufferSize = settings.bufferSize; + totalOutRequestedBufferSize = settings.bufferSize*settings.numOutputChannels; + totalInRequestedBufferSize = settings.bufferSize*settings.numInputChannels; // JNI: Try to find and call OFAndroidSoundStream.getInstance().setup(outChannels,inChannels,sampleRate,bufferSize,nBuffers) if(!ofGetJavaVMPtr()){ @@ -110,11 +110,11 @@ bool ofxAndroidSoundStream::setup(int outChannels, int inChannels, int sampleRat jobject javaObject = env->CallStaticObjectMethod(javaClass,soundStreamSingleton); jmethodID javaSetup = env->GetMethodID(javaClass,"setup","(IIIII)V"); // call setup() - if(javaObject && javaSetup) - env->CallVoidMethod(javaObject,javaSetup,outChannels,inChannels,sampleRate,bufferSize,nBuffers); - else + if(javaObject && javaSetup){ + env->CallVoidMethod(javaObject,javaSetup,settings.numOutputChannels,settings.numInputChannels,settings.sampleRate,settings.bufferSize,settings.numBuffers); + }else{ ofLogError("ofxAndroidSoundStream") << "setup(): couldn't get OFAndroidSoundStream instance or setup method"; - + } // Store instance pointer to ofxAndroidSoundStream (singleton pattern) instance = this; isPaused = false; @@ -122,19 +122,17 @@ bool ofxAndroidSoundStream::setup(int outChannels, int inChannels, int sampleRat return true; } -bool ofxAndroidSoundStream::setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ - // Set audio I/O callback classes - if(inChannels > 0) setInput(app); - if(outChannels > 0) setOutput(app); - // Setup audio I/O buffers - return setup(outChannels,inChannels,sampleRate,bufferSize,nBuffers); -} - void ofxAndroidSoundStream::start(){ if(isPaused){ resume(); }else{ - setup(out_float_buffer.getNumChannels(),in_float_buffer.getNumChannels(),out_float_buffer.getSampleRate(),requestedBufferSize,1); + ofSoundStreamSettings settings; + settings.numOutputChannels = out_float_buffer.getNumChannels(); + settings.numInputChannels = in_float_buffer.getNumChannels(); + settings.sampleRate = out_float_buffer.getSampleRate(); + settings.bufferSize = requestedBufferSize; + settings.numBuffers = 1; + setup(settings); } } diff --git a/addons/ofxAndroid/src/ofxAndroidSoundStream.h b/addons/ofxAndroid/src/ofxAndroidSoundStream.h index 9d2046a3a69..7db8f9026ec 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundStream.h +++ b/addons/ofxAndroid/src/ofxAndroidSoundStream.h @@ -11,14 +11,13 @@ class ofxAndroidSoundStream : public ofBaseSoundStream{ public: ofxAndroidSoundStream(); ~ofxAndroidSoundStream(); - - std::vector getDeviceList() const; + + std::vector getDeviceList(ofSoundDevice::Api api) const; void setDeviceID(int deviceID); void setInput(ofBaseSoundInput * soundInput); void setOutput(ofBaseSoundOutput * soundOutput); - bool setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); - bool setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); + bool setup(const ofSoundStreamSettings & settings); void start(); void stop(); @@ -26,7 +25,8 @@ class ofxAndroidSoundStream : public ofBaseSoundStream{ long unsigned long getTickCount() const; - int getDeviceID() const{return 0;} + ofSoundDevice getInDevice() const{ return ofSoundDevice(); } + ofSoundDevice getOutDevice() const{ return ofSoundDevice(); } int getNumInputChannels() const; int getNumOutputChannels() const; int getSampleRate() const; diff --git a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp index e41764dcdec..7c6b38759c3 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp +++ b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp @@ -15,9 +15,12 @@ struct ofxAndroidVideoGrabber::Data{ bool bIsFrameNew; bool bGrabberInited; + bool bUsePixels; + int width; + int height; ofPixelFormat internalPixelFormat; - ofPixels frontPixels; - ofPixels backPixels; + bool bNewBackFrame; + ofPixels frontBuffer, backBuffer; ofTexture texture; jfloatArray matrixJava; int cameraId; @@ -25,12 +28,12 @@ struct ofxAndroidVideoGrabber::Data{ bool newPixels; int attemptFramerate; jobject javaVideoGrabber; + Data(); ~Data(); void onAppPause(); void onAppResume(); void loadTexture(); - void reloadTexture(); }; map> & instances(){ @@ -51,6 +54,9 @@ static jclass getJavaClass(){ } static void InitConvertTable(); +static void ConvertYUV2RGB(unsigned char *src0,unsigned char *src1,unsigned char *dst_ori, + int width,int height); +static void ConvertYUV2toRGB565(unsigned char* yuvs, unsigned char* rgbs, int width, int height); ofxAndroidVideoGrabber::Data::Data() :bIsFrameNew(false) @@ -59,6 +65,7 @@ ofxAndroidVideoGrabber::Data::Data() ,appPaused(false) ,newPixels(false) ,attemptFramerate(-1) +,bUsePixels(true) ,javaVideoGrabber(nullptr){ JNIEnv *env = ofGetJNIEnv(); @@ -103,39 +110,37 @@ ofxAndroidVideoGrabber::Data::~Data(){ } void ofxAndroidVideoGrabber::Data::loadTexture(){ + ofTextureData td; + GLuint texId[1]; + glGenTextures(1, texId); + + glEnable(GL_TEXTURE_EXTERNAL_OES); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId[0]); + + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (!ofIsGLProgrammableRenderer()) { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } - if(!texture.texData.bAllocated) return; - - glGenTextures(1, (GLuint *)&texture.texData.textureID); - - glEnable(texture.texData.textureTarget); - - glBindTexture(texture.texData.textureTarget, (GLuint)texture.texData.textureID); + glDisable(GL_TEXTURE_EXTERNAL_OES); - glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + // Set the externally created texture reference + texture.setUseExternalTextureID(texId[0]); + texture.texData.width = width; + texture.texData.height = height; + texture.texData.tex_w = width; + texture.texData.tex_h = height; + texture.texData.tex_t = 1; // Hack! + texture.texData.tex_u = 1; + texture.texData.textureTarget = GL_TEXTURE_EXTERNAL_OES; + texture.texData.glInternalFormat = GL_RGBA; - glDisable(texture.texData.textureTarget); } -void ofxAndroidVideoGrabber::Data::reloadTexture(){ - - JNIEnv *env = ofGetJNIEnv(); - if (!env) { - ofLogError("ofxAndroidVideoGrabber") << "reloadTexture(): couldn't get environment using GetEnv()"; - return; - } - jmethodID javasetTexture = env->GetMethodID(getJavaClass(),"setTexture","(I)V"); - if(!javasetTexture){ - ofLogError("ofxAndroidVideoPlayer") << "reloadTexture(): couldn't get java setTexture for VideoPlayer"; - return; - } - env->CallVoidMethod(javaVideoGrabber,javasetTexture,texture.getTextureData().textureID); -} ofxAndroidVideoGrabber::ofxAndroidVideoGrabber() :data(new Data){ @@ -172,7 +177,20 @@ void ofxAndroidVideoGrabber::Data::onAppResume(){ appPaused = false; } vector ofxAndroidVideoGrabber::listDevices() const{ - return vector(); + + vector devices; + + int numDevices = getNumCameras(); + for(int i = 0; i < numDevices; i++){ + int facing = getFacingOfCamera(i); + ofVideoDevice vd; + vd.deviceName = facing == 0? "Back" : "Front"; + vd.id = i; + vd.bAvailable = true; + devices.push_back(vd); + } + + return devices; } bool ofxAndroidVideoGrabber::isFrameNew() const{ @@ -190,33 +208,52 @@ void ofxAndroidVideoGrabber::update(){ data->newPixels = false; data->bIsFrameNew = true; - if(supportsTextureRendering()){ - jmethodID update = ofGetJNIEnv()->GetMethodID(getJavaClass(), "update", "()V"); - ofGetJNIEnv()->CallVoidMethod(data->javaVideoGrabber, update); - - jmethodID javaGetTextureMatrix = ofGetJNIEnv()->GetMethodID(getJavaClass(),"getTextureMatrix","([F)V"); - if(!javaGetTextureMatrix){ - ofLogError("ofxAndroidVideoPlayer") << "update(): couldn't get java javaGetTextureMatrix for VideoPlayer"; - return; - } - ofGetJNIEnv()->CallVoidMethod(data->javaVideoGrabber,javaGetTextureMatrix,data->matrixJava); - jfloat * m = ofGetJNIEnv()->GetFloatArrayElements(data->matrixJava,0); - - ofMatrix4x4 vFlipTextureMatrix; - vFlipTextureMatrix.scale(1,-1,1); - vFlipTextureMatrix.translate(0,1,0); - ofMatrix4x4 textureMatrix(m); - data->texture.setTextureMatrix( vFlipTextureMatrix * textureMatrix ); - - ofGetJNIEnv()->ReleaseFloatArrayElements(data->matrixJava,m,0); + if (data->bNewBackFrame && data->bUsePixels) { + //std::unique_lock lck(data->mtx); + std::swap(data->backBuffer, data->frontBuffer); + data->bNewBackFrame = false; } - }else{ + + // Call update in the java code + // This will tell the camera api that we are ready for a new frame + jmethodID update = ofGetJNIEnv()->GetMethodID(getJavaClass(), "update", "()V"); + ofGetJNIEnv()->CallVoidMethod(data->javaVideoGrabber, update); + + // Get the texture matrix + jmethodID javaGetTextureMatrix = ofGetJNIEnv()->GetMethodID(getJavaClass(),"getTextureMatrix","([F)V"); + if(!javaGetTextureMatrix){ + ofLogError("ofxAndroidVideoPlayer") << "update(): couldn't get java javaGetTextureMatrix for VideoPlayer"; + return; + } + ofGetJNIEnv()->CallVoidMethod(data->javaVideoGrabber,javaGetTextureMatrix,data->matrixJava); + jfloat * m = ofGetJNIEnv()->GetFloatArrayElements(data->matrixJava,0); + + ofMatrix4x4 vFlipTextureMatrix; + vFlipTextureMatrix.scale(-1,-1,1); + vFlipTextureMatrix.translate(1,1,0); + ofMatrix4x4 textureMatrix(m); + data->texture.setTextureMatrix(vFlipTextureMatrix * textureMatrix ); + + ofGetJNIEnv()->ReleaseFloatArrayElements(data->matrixJava,m,0); + } else { data->bIsFrameNew = false; } } void ofxAndroidVideoGrabber::close(){ - + // Release texture + glDeleteTextures(1, &data->texture.texData.textureID); + + JNIEnv *env = ofGetJNIEnv(); + jclass javaClass = getJavaClass(); + jmethodID javaCloseGrabber = env->GetMethodID(javaClass,"close","()V"); + if(data->javaVideoGrabber && javaCloseGrabber){ + env->CallVoidMethod(data->javaVideoGrabber,javaCloseGrabber); + } else { + ofLogError("ofxAndroidVideoGrabber") << "close(): couldn't get OFAndroidVideoGrabber close grabber method"; + } + + data->bGrabberInited = false; } @@ -248,54 +285,40 @@ bool ofxAndroidVideoGrabber::setup(int w, int h){ return false; } + ofLogNotice() << "initializing camera with external texture"; + + // Load opengl texture + data->width = w; + data->height = h; + data->loadTexture(); + + bool bInit = initCamera(); + if(!bInit) return false; + + ofLogVerbose("ofxAndroidVideoGrabber") << "initGrabber(): camera initialized correctly"; + data->appPaused = false; + return true; +} + +bool ofxAndroidVideoGrabber::initCamera(){ JNIEnv *env = ofGetJNIEnv(); if(!env) return false; - jclass javaClass = env->FindClass("cc/openframeworks/OFAndroidVideoGrabber"); + jclass javaClass = getJavaClass(); - if(supportsTextureRendering()){ - ofLogNotice() << "initializing camera with external texture"; - ofTextureData td; - td.width = w; - td.height = h; - td.tex_w = td.width; - td.tex_h = td.height; - td.tex_t = 1; // Hack! - td.tex_u = 1; - td.textureTarget = GL_TEXTURE_EXTERNAL_OES; - td.glInternalFormat = GL_RGBA; - td.bFlipTexture = false; - - // hack to initialize gl resources from outside ofTexture - data->texture.texData = td; - data->texture.texData.bAllocated = true; - data->loadTexture(); - - jmethodID javaInitGrabber = env->GetMethodID(javaClass,"initGrabber","(IIII)V"); - if(data->javaVideoGrabber && javaInitGrabber){ - env->CallVoidMethod(data->javaVideoGrabber,javaInitGrabber,w,h,data->attemptFramerate,data->texture.texData.textureID); - }else{ - ofLogError("ofxAndroidVideoGrabber") << "initGrabber(): couldn't get OFAndroidVideoGrabber init grabber method"; - return false; - } - }else{ - jmethodID javaInitGrabber = env->GetMethodID(javaClass,"initGrabber","(III)V"); - if(data->javaVideoGrabber && javaInitGrabber){ - env->CallVoidMethod(data->javaVideoGrabber,javaInitGrabber,w,h,data->attemptFramerate); - }else{ - ofLogError("ofxAndroidVideoGrabber") << "initGrabber(): couldn't get OFAndroidVideoGrabber init grabber method"; - return false; - } + jmethodID javaInitGrabber = env->GetMethodID(javaClass,"initGrabber","(IIII)V"); + if(data->javaVideoGrabber && javaInitGrabber){ + env->CallVoidMethod(data->javaVideoGrabber,javaInitGrabber,data->width,data->height,data->attemptFramerate,data->texture.texData.textureID); + } else { + ofLogError("ofxAndroidVideoGrabber") << "initGrabber(): couldn't get OFAndroidVideoGrabber init grabber method"; + return false; } //ofLogVerbose("ofxAndroidVideoGrabber") << "initGrabber(): new frame callback size: " << (int) width << "x" << (int) height; - data->frontPixels.allocate(w,h,getPixelFormat()); data->bGrabberInited = true; - ofLogVerbose("ofxAndroidVideoGrabber") << "initGrabber(): camera initialized correctly"; - data->appPaused = false; return true; -} +}; bool ofxAndroidVideoGrabber::isInitialized() const{ return data->bGrabberInited; @@ -304,18 +327,94 @@ bool ofxAndroidVideoGrabber::isInitialized() const{ void ofxAndroidVideoGrabber::videoSettings(){ } -ofPixels& ofxAndroidVideoGrabber::getPixels(){ - return data->frontPixels; +void ofxAndroidVideoGrabber::setUsePixels(bool usePixels){ + data->bUsePixels = usePixels; +} + +ofPixels& ofxAndroidVideoGrabber::getPixels(){ + if(!data->bUsePixels){ + ofLogNotice()<<"Calling getPixels will not return frame data when setUsePixels(false) has been set"; + } + + return data->frontBuffer; } const ofPixels& ofxAndroidVideoGrabber::getPixels() const { - return data->frontPixels; + return const_cast(this)->getPixels(); } void ofxAndroidVideoGrabber::setVerbose(bool bTalkToMe){ } +int ofxAndroidVideoGrabber::getCameraFacing(int facing)const{ + JNIEnv *env = ofGetJNIEnv(); + if(!env) return -1; + + jclass javaClass = getJavaClass(); + + jmethodID javagetCameraFacing = env->GetMethodID(javaClass,"getCameraFacing","(I)I"); + if(data->javaVideoGrabber && javagetCameraFacing){ + return env->CallIntMethod(data->javaVideoGrabber,javagetCameraFacing,facing); + } else { + ofLogError("ofxAndroidVideoGrabber") << "getCameraFacing(): couldn't get OFAndroidVideoGrabber getCameraFacing method"; + return -1; + } +} + +int ofxAndroidVideoGrabber::getBackCamera()const{ + return getCameraFacing(0); +} + +int ofxAndroidVideoGrabber::getFrontCamera()const{ + return getCameraFacing(1); +} + +int ofxAndroidVideoGrabber::getNumCameras() const{ + JNIEnv *env = ofGetJNIEnv(); + if(!env) return 0; + + jclass javaClass = getJavaClass(); + + jmethodID javagetNumCameras= env->GetMethodID(javaClass,"getNumCameras","()I"); + if(data->javaVideoGrabber && javagetNumCameras){ + return env->CallIntMethod(data->javaVideoGrabber,javagetNumCameras); + } else { + ofLogError("ofxAndroidVideoGrabber") << "getNumCameras(): couldn't get OFAndroidVideoGrabber getNumCameras method"; + return 0; + } +} + +int ofxAndroidVideoGrabber::getCameraOrientation(int device)const{ + JNIEnv *env = ofGetJNIEnv(); + if(!env) return 0; + + jclass javaClass = getJavaClass(); + + jmethodID javagetCameraOrientation= env->GetMethodID(javaClass,"getCameraOrientation","(I)I"); + if(data->javaVideoGrabber && javagetCameraOrientation){ + return env->CallIntMethod(data->javaVideoGrabber,javagetCameraOrientation, device); + } else { + ofLogError("ofxAndroidVideoGrabber") << "getCameraOrientation(): couldn't get OFAndroidVideoGrabber getCameraOrientation method"; + return 0; + } +} + +int ofxAndroidVideoGrabber::getFacingOfCamera(int device)const{ + JNIEnv *env = ofGetJNIEnv(); + if(!env) return 0; + + jclass javaClass = getJavaClass(); + + jmethodID javagetFacingOfCamera= env->GetMethodID(javaClass,"getFacingOfCamera","(I)I"); + if(data->javaVideoGrabber && javagetFacingOfCamera){ + return env->CallIntMethod(data->javaVideoGrabber,javagetFacingOfCamera, device); + } else { + ofLogError("ofxAndroidVideoGrabber") << "getFacingOfCamera(): couldn't get OFAndroidVideoGrabber getFacingOfCamera method"; + return 0; + } +} + void ofxAndroidVideoGrabber::setDeviceID(int _deviceID){ JNIEnv *env = ofGetJNIEnv(); @@ -326,7 +425,7 @@ void ofxAndroidVideoGrabber::setDeviceID(int _deviceID){ jmethodID javasetDeviceID = env->GetMethodID(javaClass,"setDeviceID","(I)V"); if(data->javaVideoGrabber && javasetDeviceID){ env->CallVoidMethod(data->javaVideoGrabber,javasetDeviceID,_deviceID); - }else{ + } else { ofLogError("ofxAndroidVideoGrabber") << "setDeviceID(): couldn't get OFAndroidVideoGrabber setDeviceID method"; return; } @@ -351,11 +450,11 @@ void ofxAndroidVideoGrabber::setDesiredFrameRate(int framerate){ } float ofxAndroidVideoGrabber::getHeight() const{ - return data->frontPixels.getHeight(); + return data->height; } float ofxAndroidVideoGrabber::getWidth() const{ - return data->frontPixels.getWidth(); + return data->width; } bool ofxAndroidVideoGrabber::setPixelFormat(ofPixelFormat pixelFormat){ @@ -383,85 +482,85 @@ ofPixelFormat ofxAndroidVideoGrabber::getPixelFormat() const{ { static bool inited = false; if(inited) return; - long int crv,cbu,cgu,cgv; - int i,ind; - - crv = 104597; cbu = 132201; /* fra matrise i global.h */ - cgu = 25675; cgv = 53279; - - for (i = 0; i < 256; i++) { - crv_tab[i] = (i-128) * crv; - cbu_tab[i] = (i-128) * cbu; - cgu_tab[i] = (i-128) * cgu; - cgv_tab[i] = (i-128) * cgv; - tab_76309[i] = 76309*(i-16); - } + long int crv,cbu,cgu,cgv; + int i,ind; + + crv = 104597; cbu = 132201; /* fra matrise i global.h */ + cgu = 25675; cgv = 53279; + + for (i = 0; i < 256; i++) { + crv_tab[i] = (i-128) * crv; + cbu_tab[i] = (i-128) * cbu; + cgu_tab[i] = (i-128) * cgu; + cgv_tab[i] = (i-128) * cgv; + tab_76309[i] = 76309*(i-16); + } - for (i=0; i<384; i++) - clp[i] =0; - ind=384; - for (i=0;i<256; i++) - clp[ind++]=i; - ind=640; - for (i=0;i<384;i++) - clp[ind++]=255; + for (i=0; i<384; i++) + clp[i] =0; + ind=384; + for (i=0;i<256; i++) + clp[ind++]=i; + ind=640; + for (i=0;i<384;i++) + clp[ind++]=255; - inited = true; + inited = true; } void ConvertYUV2RGB(unsigned char *src0,unsigned char *src1,unsigned char *dst_ori, - int width,int height) + int width,int height) { - register int y1,y2,u,v; - register unsigned char *py1,*py2; - register int i,j, c1, c2, c3, c4; - register unsigned char *d1, *d2; - - int width3 = 3*width; - py1=src0; - py2=py1+width; - d1=dst_ori; - d2=d1+width3; - for (j = 0; j < height; j += 2) { - for (i = 0; i < width; i += 2) { - - v = *src1++; - u = *src1++; - - c1 = crv_tab[v]; - c2 = cgu_tab[u]; - c3 = cgv_tab[v]; - c4 = cbu_tab[u]; - - //up-left - y1 = tab_76309[*py1++]; - *d1++ = clp[384+((y1 + c1)>>16)]; - *d1++ = clp[384+((y1 - c2 - c3)>>16)]; - *d1++ = clp[384+((y1 + c4)>>16)]; - - //down-left - y2 = tab_76309[*py2++]; - *d2++ = clp[384+((y2 + c1)>>16)]; - *d2++ = clp[384+((y2 - c2 - c3)>>16)]; - *d2++ = clp[384+((y2 + c4)>>16)]; - - //up-right - y1 = tab_76309[*py1++]; - *d1++ = clp[384+((y1 + c1)>>16)]; - *d1++ = clp[384+((y1 - c2 - c3)>>16)]; - *d1++ = clp[384+((y1 + c4)>>16)]; - - //down-right - y2 = tab_76309[*py2++]; - *d2++ = clp[384+((y2 + c1)>>16)]; - *d2++ = clp[384+((y2 - c2 - c3)>>16)]; - *d2++ = clp[384+((y2 + c4)>>16)]; - } - d1 += width3; - d2 += width3; - py1+= width; - py2+= width; - } + register int y1,y2,u,v; + register unsigned char *py1,*py2; + register int i,j, c1, c2, c3, c4; + register unsigned char *d1, *d2; + + int width3 = 3*width; + py1=src0; + py2=py1+width; + d1=dst_ori; + d2=d1+width3; + for (j = 0; j < height; j += 2) { + for (i = 0; i < width; i += 2) { + + v = *src1++; + u = *src1++; + + c1 = crv_tab[v]; + c2 = cgu_tab[u]; + c3 = cgv_tab[v]; + c4 = cbu_tab[u]; + + //up-left + y1 = tab_76309[*py1++]; + *d1++ = clp[384+((y1 + c1)>>16)]; + *d1++ = clp[384+((y1 - c2 - c3)>>16)]; + *d1++ = clp[384+((y1 + c4)>>16)]; + + //down-left + y2 = tab_76309[*py2++]; + *d2++ = clp[384+((y2 + c1)>>16)]; + *d2++ = clp[384+((y2 - c2 - c3)>>16)]; + *d2++ = clp[384+((y2 + c4)>>16)]; + + //up-right + y1 = tab_76309[*py1++]; + *d1++ = clp[384+((y1 + c1)>>16)]; + *d1++ = clp[384+((y1 - c2 - c3)>>16)]; + *d1++ = clp[384+((y1 + c4)>>16)]; + + //down-right + y2 = tab_76309[*py2++]; + *d2++ = clp[384+((y2 + c1)>>16)]; + *d2++ = clp[384+((y2 - c2 - c3)>>16)]; + *d2++ = clp[384+((y2 + c4)>>16)]; + } + d1 += width3; + d2 += width3; + py1+= width; + py2+= width; + } } @@ -478,130 +577,126 @@ ofPixelFormat ofxAndroidVideoGrabber::getPixelFormat() const{ //we tackle the conversion two pixels at a time for greater speed void ConvertYUV2toRGB565(unsigned char* yuvs, unsigned char* rgbs, int width, int height) { - //the end of the luminance data - int lumEnd = width * height; - //points to the next luminance value pair - int lumPtr = 0; - //points to the next chromiance value pair - int chrPtr = lumEnd; - //points to the next byte output pair of RGB565 value - int outPtr = 0; - //the end of the current luminance scanline - int lineEnd = width; - register int R, G, B; - register int Y1; - register int Y2; - register int Cr; - register int Cb; - - while (true) { - - //skip back to the start of the chromiance values when necessary - if (lumPtr == lineEnd) { - if (lumPtr == lumEnd) break; //we've reached the end - //division here is a bit expensive, but's only done once per scanline - chrPtr = lumEnd + ((lumPtr >> 1) / width) * width; - lineEnd += width; - } - - //read the luminance and chromiance values - Y1 = yuvs[lumPtr++] & 0xff; - Y2 = yuvs[lumPtr++] & 0xff; - Cr = (yuvs[chrPtr++] & 0xff) - 128; - Cb = (yuvs[chrPtr++] & 0xff) - 128; - - //generate first RGB components - B = Y1 + ((454 * Cb) >> 8); - if(B < 0) B = 0; else if(B > 255) B = 255; - G = Y1 - ((88 * Cb + 183 * Cr) >> 8); - if(G < 0) G = 0; else if(G > 255) G = 255; - R = Y1 + ((359 * Cr) >> 8); - if(R < 0) R = 0; else if(R > 255) R = 255; - //NOTE: this assume little-endian encoding - rgbs[outPtr++] = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - rgbs[outPtr++] = (unsigned char) ((R & 0xf8) | (G >> 5)); - - //generate second RGB components - B = Y2 + ((454 * Cb) >> 8); - if(B < 0) B = 0; else if(B > 255) B = 255; - G = Y2 - ((88 * Cb + 183 * Cr) >> 8); - if(G < 0) G = 0; else if(G > 255) G = 255; - R = Y2 + ((359 * Cr) >> 8); - if(R < 0) R = 0; else if(R > 255) R = 255; - //NOTE: this assume little-endian encoding - rgbs[outPtr++] = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - rgbs[outPtr++] = (unsigned char) ((R & 0xf8) | (G >> 5)); - } + //the end of the luminance data + int lumEnd = width * height; + //points to the next luminance value pair + int lumPtr = 0; + //points to the next chromiance value pair + int chrPtr = lumEnd; + //points to the next byte output pair of RGB565 value + int outPtr = 0; + //the end of the current luminance scanline + int lineEnd = width; + register int R, G, B; + register int Y1; + register int Y2; + register int Cr; + register int Cb; + + while (true) { + + //skip back to the start of the chromiance values when necessary + if (lumPtr == lineEnd) { + if (lumPtr == lumEnd) break; //we've reached the end + //division here is a bit expensive, but's only done once per scanline + chrPtr = lumEnd + ((lumPtr >> 1) / width) * width; + lineEnd += width; + } + + //read the luminance and chromiance values + Y1 = yuvs[lumPtr++] & 0xff; + Y2 = yuvs[lumPtr++] & 0xff; + Cr = (yuvs[chrPtr++] & 0xff) - 128; + Cb = (yuvs[chrPtr++] & 0xff) - 128; + + //generate first RGB components + B = Y1 + ((454 * Cb) >> 8); + if(B < 0) B = 0; else if(B > 255) B = 255; + G = Y1 - ((88 * Cb + 183 * Cr) >> 8); + if(G < 0) G = 0; else if(G > 255) G = 255; + R = Y1 + ((359 * Cr) >> 8); + if(R < 0) R = 0; else if(R > 255) R = 255; + //NOTE: this assume little-endian encoding + rgbs[outPtr++] = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + rgbs[outPtr++] = (unsigned char) ((R & 0xf8) | (G >> 5)); + + //generate second RGB components + B = Y2 + ((454 * Cb) >> 8); + if(B < 0) B = 0; else if(B > 255) B = 255; + G = Y2 - ((88 * Cb + 183 * Cr) >> 8); + if(G < 0) G = 0; else if(G > 255) G = 255; + R = Y2 + ((359 * Cr) >> 8); + if(R < 0) R = 0; else if(R > 255) R = 255; + //NOTE: this assume little-endian encoding + rgbs[outPtr++] = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + rgbs[outPtr++] = (unsigned char) ((R & 0xf8) | (G >> 5)); + } } void ConvertYUV2toRGB565_2(unsigned char *src0,unsigned char *src1,unsigned char *dst_ori, - int width,int height) + int width,int height) { - register int y1,y2,u,v; - register unsigned char *py1,*py2; - register int i,j, c1, c2, c3, c4; - register unsigned char *d1, *d2; - register int R,G,B; - int width2 = 2*width; - py1=src0; - py2=py1+width; - d1=dst_ori; - d2=d1+width2; - for (j = 0; j < height; j += 2) { - for (i = 0; i < width; i += 2) { - - v = *src1++; - u = *src1++; - - c1 = crv_tab[v]; - c2 = cgu_tab[u]; - c3 = cgv_tab[v]; - c4 = cbu_tab[u]; - - //up-left - y1 = tab_76309[*py1++]; - R = clp[384+((y1 + c1)>>16)]; - G = clp[384+((y1 - c2 - c3)>>16)]; - B = clp[384+((y1 + c4)>>16)]; - *d1++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - *d1++ = (unsigned char) ((R & 0xf8) | (G >> 5)); - - //down-left - y2 = tab_76309[*py2++]; - B = clp[384+((y2 + c1)>>16)]; - G = clp[384+((y2 - c2 - c3)>>16)]; - R = clp[384+((y2 + c4)>>16)]; - *d2++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - *d2++ = (unsigned char) ((R & 0xf8) | (G >> 5)); - - //up-right - y1 = tab_76309[*py1++]; - R = clp[384+((y1 + c1)>>16)]; - G = clp[384+((y1 - c2 - c3)>>16)]; - B = clp[384+((y1 + c4)>>16)]; - *d1++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - *d1++ = (unsigned char) ((R & 0xf8) | (G >> 5)); - - //down-right - y2 = tab_76309[*py2++]; - B = clp[384+((y2 + c1)>>16)]; - G = clp[384+((y2 - c2 - c3)>>16)]; - R = clp[384+((y2 + c4)>>16)]; - *d2++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); - *d2++ = (unsigned char) ((R & 0xf8) | (G >> 5)); - } - d1 += width2; - d2 += width2; - py1+= width; - py2+= width; - } + register int y1,y2,u,v; + register unsigned char *py1,*py2; + register int i,j, c1, c2, c3, c4; + register unsigned char *d1, *d2; + register int R,G,B; + int width2 = 2*width; + py1=src0; + py2=py1+width; + d1=dst_ori; + d2=d1+width2; + for (j = 0; j < height; j += 2) { + for (i = 0; i < width; i += 2) { + + v = *src1++; + u = *src1++; + + c1 = crv_tab[v]; + c2 = cgu_tab[u]; + c3 = cgv_tab[v]; + c4 = cbu_tab[u]; + + //up-left + y1 = tab_76309[*py1++]; + R = clp[384+((y1 + c1)>>16)]; + G = clp[384+((y1 - c2 - c3)>>16)]; + B = clp[384+((y1 + c4)>>16)]; + *d1++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + *d1++ = (unsigned char) ((R & 0xf8) | (G >> 5)); + + //down-left + y2 = tab_76309[*py2++]; + B = clp[384+((y2 + c1)>>16)]; + G = clp[384+((y2 - c2 - c3)>>16)]; + R = clp[384+((y2 + c4)>>16)]; + *d2++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + *d2++ = (unsigned char) ((R & 0xf8) | (G >> 5)); + + //up-right + y1 = tab_76309[*py1++]; + R = clp[384+((y1 + c1)>>16)]; + G = clp[384+((y1 - c2 - c3)>>16)]; + B = clp[384+((y1 + c4)>>16)]; + *d1++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + *d1++ = (unsigned char) ((R & 0xf8) | (G >> 5)); + + //down-right + y2 = tab_76309[*py2++]; + B = clp[384+((y2 + c1)>>16)]; + G = clp[384+((y2 - c2 - c3)>>16)]; + R = clp[384+((y2 + c4)>>16)]; + *d2++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3)); + *d2++ = (unsigned char) ((R & 0xf8) | (G >> 5)); + } + d1 += width2; + d2 += width2; + py1+= width; + py2+= width; + } } - /*static int time_one_frame = 0; - static int acc_time = 0; - static int num_frames = 0; - static int time_prev_out = 0;*/ extern "C"{ jint @@ -609,41 +704,41 @@ Java_cc_openframeworks_OFAndroidVideoGrabber_newFrame(JNIEnv* env, jobject thi auto data = instances()[cameraId].lock(); if(!data) return 1; - auto currentFrame = (unsigned char*)env->GetPrimitiveArrayCritical(array, NULL); - if(!currentFrame) return 1; + if(data->bUsePixels) { + jboolean isCopy; + auto currentFrame = (unsigned char *) env->GetByteArrayElements(array, &isCopy); + //ofLog()<<"Is copy: "<<(isCopy?true:false); - ofPixels & pixels = data->backPixels; - bool needsResize=false; - if(pixels.getWidth()!=width || pixels.getHeight()!=height){ - needsResize = true; - pixels.allocate(width,height,data->internalPixelFormat); - } + if (!currentFrame) return 1; + + ofPixels &pixels = data->backBuffer; + bool needsResize = false; + if (pixels.getWidth() != width || pixels.getHeight() != height) { + needsResize = true; + pixels.allocate(width, height, data->internalPixelFormat); + } + + if (data->internalPixelFormat == OF_PIXELS_RGB) { + ConvertYUV2RGB(currentFrame, // y component + currentFrame + (width * height), // uv components + pixels.getData(), width, height); + } else if (data->internalPixelFormat == OF_PIXELS_RGB565) { + ConvertYUV2toRGB565(currentFrame, pixels.getData(), width, height); + } else if (data->internalPixelFormat == OF_PIXELS_MONO) { + pixels.setFromPixels(currentFrame, width, height, OF_IMAGE_GRAYSCALE); + } + if (needsResize) { + pixels.resize(data->width, data->height, OF_INTERPOLATE_NEAREST_NEIGHBOR); + } + env->ReleaseByteArrayElements(array, (jbyte*)currentFrame, 0); - //time_one_frame = ofGetSystemTime(); - if(data->internalPixelFormat==OF_PIXELS_RGB){ - ConvertYUV2RGB(currentFrame, // y component - currentFrame+(width*height), // uv components - pixels.getData(),width,height); - }else if(data->internalPixelFormat==OF_PIXELS_RGB565){ - ConvertYUV2toRGB565(currentFrame,pixels.getData(),width,height); - }else if(data->internalPixelFormat==OF_PIXELS_MONO){ - pixels.setFromPixels(currentFrame,width,height,OF_IMAGE_GRAYSCALE); + data->bNewBackFrame=true; } - if(needsResize){ - data->backPixels.resize(data->frontPixels.getWidth(), data->frontPixels.getHeight(), OF_INTERPOLATE_NEAREST_NEIGHBOR); - } - /*acc_time += ofGetSystemTime() - time_one_frame; - num_frames ++; - if(ofGetSystemTime() - time_prev_out > 5000){ - time_prev_out = ofGetSystemTime(); - ofLogNotice("ofxAndroidVideoGrabber") << "avg time: " << float(acc_time)/float(num_frames); - }*/ - - env->ReleasePrimitiveArrayCritical(array,currentFrame ,0); data->newPixels = true; + return 0; } } diff --git a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h index ef2166e4fe9..6b0809f3421 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h +++ b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h @@ -19,41 +19,74 @@ class ofxAndroidVideoGrabber: public ofBaseVideoGrabber{ ofxAndroidVideoGrabber(); ~ofxAndroidVideoGrabber(); - //needs implementing vector listDevices() const; - bool setup(int w, int h); - bool isInitialized() const; + bool setup(int w, int h); + bool isInitialized() const; - bool isFrameNew() const; - void update(); + bool isFrameNew() const; + void update(); ofPixels& getPixels(); const ofPixels& getPixels() const; - void close(); + void setUsePixels(bool usePixels); - float getHeight() const; - float getWidth() const; + void close(); + + float getHeight() const; + float getWidth() const; //should implement! void setVerbose(bool bTalkToMe); - void setDeviceID(int _deviceID); + + + /// Set desired frame rate of the camera. + /// By default will the camera pick the highest frame rate available void setDesiredFrameRate(int framerate); + + /// Set specific camera device id. + /// Must be a value between 0 and numCameras. + /// Default is first back facing camera + void setDeviceID(int _deviceID); + void videoSettings(); bool setPixelFormat(ofPixelFormat pixelFormat); ofPixelFormat getPixelFormat() const; // specifics android + /// Get device id of back facing camera. + /// Returns -1 if no match is found + int getBackCamera()const; + + /// Get device id of front facing (selfie) camera. + /// Returns -1 if no match is found + int getFrontCamera()const; + + /// Get the physical orientation of the camera. Typically on a phone the camera mounted in + /// landscape mode, this returns 90 + int getCameraOrientation(int device=-1)const; + + /// Get facing of camera. + /// Leave device = -1 to get selected cameras facing + /// + /// Returns 0 on backfacing camera, and 1 on frontal facing camera. + int getFacingOfCamera(int device=-1)const; + bool setAutoFocus(bool autofocus); ofTexture * getTexturePtr(); - ofEvent newFrameE; + bool supportsTextureRendering(); struct Data; private: - bool supportsTextureRendering(); + int getCameraFacing(int facing)const; + + /// Get number of cameras available + int getNumCameras()const; + + bool initCamera(); // only to be used internally to resize; ofPixelsRef getAuxBuffer(); diff --git a/addons/ofxAssimpModelLoader/addon_config.mk b/addons/ofxAssimpModelLoader/addon_config.mk index b30bf414cb9..b3c8bc676c7 100644 --- a/addons/ofxAssimpModelLoader/addon_config.mk +++ b/addons/ofxAssimpModelLoader/addon_config.mk @@ -80,4 +80,9 @@ linux64: ADDON_LIBS_EXCLUDE = libs/assimp ADDON_INCLUDES_EXCLUDE = libs/assimp/% +msys2: + ADDON_PKG_CONFIG_LIBRARIES = assimp + ADDON_LIBS_EXCLUDE = libs/assimp + ADDON_INCLUDES_EXCLUDE = libs/assimp/% + diff --git a/addons/ofxAssimpModelLoader/libs/assimp/lib/osx/assimp.a b/addons/ofxAssimpModelLoader/libs/assimp/lib/osx/assimp.a index a4a873e4c4c..e42d7c6f71d 100644 Binary files a/addons/ofxAssimpModelLoader/libs/assimp/lib/osx/assimp.a and b/addons/ofxAssimpModelLoader/libs/assimp/lib/osx/assimp.a differ diff --git a/addons/ofxAssimpModelLoader/libs/assimp/lib/win_cb/libassimp.dll b/addons/ofxAssimpModelLoader/libs/assimp/lib/win_cb/libassimp.dll deleted file mode 100644 index 9abe0a1e001..00000000000 Binary files a/addons/ofxAssimpModelLoader/libs/assimp/lib/win_cb/libassimp.dll and /dev/null differ diff --git a/addons/ofxAssimpModelLoader/scripts/formulas/assimp.sh b/addons/ofxAssimpModelLoader/scripts/formulas/assimp.sh index ee7ad0f9009..b5061345514 100755 --- a/addons/ofxAssimpModelLoader/scripts/formulas/assimp.sh +++ b/addons/ofxAssimpModelLoader/scripts/formulas/assimp.sh @@ -14,7 +14,7 @@ GIT_URL= # GIT_URL=https://github.com/assimp/assimp.git GIT_TAG= -FORMULA_TYPES=( "osx" "osx-clang-libc++" "ios" "android" "emscripten" "vs" ) +FORMULA_TYPES=( "osx" "ios" "tvos" "android" "emscripten" "vs" ) # download the source code and unpack it into LIB_NAME function download() { @@ -28,8 +28,7 @@ function download() { # fix an issue with static libs being disabled - see issue https://github.com/assimp/assimp/issues/271 # this could be fixed fairly soon - so see if its needed for future releases. - if [ "$TYPE" == "ios" ] ; then - + if [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then echo "iOS" elif [ "$TYPE" == "vs" ] ; then #ADDED EXCEPTION, FIX DOESN'T WORK IN VS @@ -62,19 +61,31 @@ function build() { rm -f CMakeCache.txt || true # we don't use the build script for iOS now as it is less reliable than doing it our self - if [ "$TYPE" == "ios" ] ; then + if [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then # ref: http://stackoverflow.com/questions/6691927/how-to-build-assimp-library-for-ios-device-and-simulator-with-boost-library export TOOLCHAIN=$XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain export TARGET_IOS - local IOS_ARCHS="armv7 arm64 i386 x86_64" #armv7s + local IOS_ARCHS + if [[ "${TYPE}" == "tvos" ]]; then + IOS_ARCHS="x86_64 arm64" + elif [[ "$TYPE" == "ios" ]]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi + local STDLIB="libc++" local CURRENTPATH=`pwd` echo $CURRENTPATH - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + SDKVERSION="" + if [[ "${TYPE}" == "tvos" ]]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [[ "$TYPE" == "ios" ]]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi + DEVELOPER=$XCODE_DEV_ROOT TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER @@ -121,14 +132,20 @@ function build() { echo "Building $IOS_ARCH " - export PLATFORM="" if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; - then - PLATFORM="iPhoneSimulator" - - else - PLATFORM="iPhoneOS" - fi + then + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + fi + else + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + fi + fi export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" export CROSS_SDK="${PLATFORM}.sdk" @@ -136,25 +153,38 @@ function build() { MIN_IOS_VERSION=$IOS_MIN_SDK_VER - # min iOS version for arm64 is iOS 7 - - if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures - elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors - fi - - MIN_TYPE=-miphoneos-version-min= - if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_TYPE=-mios-simulator-version-min= - fi - - export EXTRA_PLATFORM_CFLAGS="$" - export EXTRA_PLATFORM_LDFLAGS="$ -L${CROSS_TOP}/SDKs/$CROSS_SDK/usr/lib/" + # min iOS version for arm64 is iOS 7 + + if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures + elif [ "${IOS_ARCH}" == "i386" ]; then + MIN_IOS_VERSION=7.0 # 6.0 to prevent start linking errors + fi + MIN_TYPE=-miphoneos-version-min= + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + fi + + export EXTRA_PLATFORM_CFLAGS="" + export EXTRA_PLATFORM_LDFLAGS=" -L${CROSS_TOP}/SDKs/$CROSS_SDK/usr/lib/" echo $EXTRA_PLATFORM_LDFLAGS - EXTRA_LINK_FLAGS="-arch $IOS_ARCH -stdlib=libc++ -Os -DHAVE_UNISTD_H=1 -DNDEBUG -fPIC " + EXTRA_LINK_FLAGS="-arch $IOS_ARCH $BITCODE -DNDEBUG -stdlib=libc++ -Os -DHAVE_UNISTD_H=1 -DNDEBUG -fPIC " EXTRA_FLAGS="$EXTRA_LINK_FLAGS -pipe -no-cpp-precomp -funroll-loops $MIN_TYPE$MIN_IOS_VERSION -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/" unset CFLAGS LDFLAGS CPPFLAGS CXXFLAGS DEVROOT SDKROOT @@ -199,12 +229,19 @@ function build() { SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` DEVELOPER=$XCODE_DEV_ROOT TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain + + if [[ "${TYPE}" == "tvos" ]] ; then + $TOOLCHAIN/usr/bin/lipo -create libassimp-arm64.a \ + libassimp-x86_64.a \ + -output "../../lib/$TYPE/assimp.a" + elif [[ "$TYPE" == "ios" ]]; then # libassimp-armv7s.a \ - $TOOLCHAIN/usr/bin/lipo -create libassimp-armv7.a \ - libassimp-arm64.a \ - libassimp-i386.a \ - libassimp-x86_64.a \ - -output "../../lib/$TYPE/assimp.a" + $TOOLCHAIN/usr/bin/lipo -create libassimp-armv7.a \ + libassimp-arm64.a \ + libassimp-i386.a \ + libassimp-x86_64.a \ + -output "../../lib/$TYPE/assimp.a" + fi cd ../../ @@ -224,19 +261,21 @@ function build() { CURRENTPATH=`pwd` cd lib/$TYPE - SLOG="$CURRENTPATH/lib/$TYPE-stripping.log" - local TOBESTRIPPED - for TOBESTRIPPED in $( ls -1) ; do - $TOOLCHAIN/usr/bin/strip -x $TOBESTRIPPED >> "${SLOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 100 "${LOG}" - echo "Problem while stripping lib - Please check ${SLOG}" - exit 1 - else - echo "Strip Successful for ${SLOG}" - fi - done + if [ "$TYPE" == "ios"]; then + SLOG="$CURRENTPATH/lib/$TYPE-stripping.log" + local TOBESTRIPPED + for TOBESTRIPPED in $( ls -1) ; do + $TOOLCHAIN/usr/bin/strip -x $TOBESTRIPPED >> "${SLOG}" 2>&1 + if [ $? != 0 ]; + then + tail -n 100 "${LOG}" + echo "Problem while stripping lib - Please check ${SLOG}" + exit 1 + else + echo "Strip Successful for ${SLOG}" + fi + done + fi cd ../../ echo "--------------------" @@ -281,8 +320,8 @@ function build() { echo "Completed Assimp for $TYPE | $ARCH | $VS_VER" - elif [ "$TYPE" == "win_cb" ] ; then - echoWarning "TODO: win_cb build" + elif [ "$TYPE" == "msys2" ] ; then + echoWarning "TODO: msys2 build" elif [ "$TYPE" == "android" ] ; then @@ -346,7 +385,7 @@ function copy() { fi elif [ "$TYPE" == "osx" ] ; then cp -Rv lib/libassimp.a $1/lib/$TYPE/assimp.a - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then cp -Rv lib/$TYPE/assimp.a $1/lib/$TYPE/assimp.a elif [ "$TYPE" == "android" ]; then mkdir -p $1/lib/$TYPE/armeabi-v7a/ diff --git a/addons/ofxAssimpModelLoader/src/ofxAssimpMeshHelper.h b/addons/ofxAssimpModelLoader/src/ofxAssimpMeshHelper.h index 012fe76445c..62e22497ee6 100644 --- a/addons/ofxAssimpModelLoader/src/ofxAssimpMeshHelper.h +++ b/addons/ofxAssimpModelLoader/src/ofxAssimpMeshHelper.h @@ -11,7 +11,7 @@ #include #include "ofxAssimpTexture.h" -class aiMesh; +struct aiMesh; class ofxAssimpMeshHelper { diff --git a/addons/ofxAssimpModelLoader/src/ofxAssimpModelLoader.cpp b/addons/ofxAssimpModelLoader/src/ofxAssimpModelLoader.cpp index e13b0b6844f..234fff6e939 100644 --- a/addons/ofxAssimpModelLoader/src/ofxAssimpModelLoader.cpp +++ b/addons/ofxAssimpModelLoader/src/ofxAssimpModelLoader.cpp @@ -26,8 +26,11 @@ bool ofxAssimpModelLoader::loadModel(string modelName, bool optimize){ ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): loading \"" << file.getFileName() << "\" from \"" << file.getEnclosingDirectory() << "\""; - if(scene != NULL){ + if(scene.get() != nullptr){ clear(); + // we reset the shared_ptr explicitly here, to force the old + // aiScene to be deleted **before** a new aiScene is created. + scene.reset(); } // sets various properties & flags to a default preference @@ -45,25 +48,25 @@ bool ofxAssimpModelLoader::loadModel(ofBuffer & buffer, bool optimize, const cha ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): loading from memory buffer \"." << extension << "\""; - if(scene != NULL){ + if(scene.get() != nullptr){ clear(); + // we reset the shared_ptr explicitly here, to force the old + // aiScene to be deleted **before** a new aiScene is created. + scene.reset(); } // sets various properties & flags to a default preference unsigned int flags = initImportProperties(optimize); // loads scene from memory buffer - note this will not work for multipart files (obj, md3, etc) - scene = shared_ptr(aiImportFileFromMemoryWithProperties(buffer.getBinaryBuffer(), buffer.size(), flags, extension, store.get()), aiReleaseImport); + scene = shared_ptr(aiImportFileFromMemoryWithProperties(buffer.getData(), buffer.size(), flags, extension, store.get()), aiReleaseImport); bool bOk = processScene(); return bOk; } -unsigned int ofxAssimpModelLoader::initImportProperties(bool optimize) { - store.reset(); - - aiPropertyStore * storePtr = aiCreatePropertyStore(); - store = ( shared_ptr )storePtr; +unsigned int ofxAssimpModelLoader::initImportProperties(bool optimize) { + store.reset(aiCreatePropertyStore(), aiReleasePropertyStore); // only ever give us triangles. aiSetImportPropertyInteger(store.get(), AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT ); @@ -83,18 +86,15 @@ bool ofxAssimpModelLoader::processScene() { normalizeFactor = ofGetWidth() / 2.0; if(scene){ - calculateDimensions(); loadGLResources(); update(); + calculateDimensions(); if(getAnimationCount()) ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): scene has " << getAnimationCount() << "animations"; else { ofLogVerbose("ofxAssimpModelLoader") << "loadMode(): no animations"; - } - - ofAddListener(ofEvents().exit,this,&ofxAssimpModelLoader::onAppExit); - + } return true; }else{ @@ -106,14 +106,6 @@ bool ofxAssimpModelLoader::processScene() { return false; } -// automatic destruction on app exit makes the app crash because of some bug in assimp -// this is a hack to clear every object on the exit callback of the application -// FIXME: review when there's an update of assimp -//------------------------------------------- -void ofxAssimpModelLoader::onAppExit(ofEventArgs & args){ - clear(); - scene.reset(); -} //------------------------------------------- void ofxAssimpModelLoader::createEmptyModel(){ @@ -143,8 +135,13 @@ void ofxAssimpModelLoader::calculateDimensions(){ normalizedScale = scene_max.x-scene_min.x; normalizedScale = MAX(scene_max.y - scene_min.y,normalizedScale); normalizedScale = MAX(scene_max.z - scene_min.z,normalizedScale); - normalizedScale = 1.f / normalizedScale; - normalizedScale *= normalizeFactor; + if (abs(normalizedScale) < std::numeric_limits::epsilon()){ + ofLogWarning("ofxAssimpModelLoader") << "Error calculating normalized scale of scene" << endl; + normalizedScale = 1.0; + } else { + normalizedScale = 1.f / normalizedScale; + normalizedScale *= normalizeFactor; + } updateModelMatrix(); } @@ -289,9 +286,17 @@ void ofxAssimpModelLoader::loadGLResources(){ meshHelper.validCache = true; meshHelper.hasChanged = false; - meshHelper.animatedPos.resize(mesh->mNumVertices); - if(mesh->HasNormals()){ - meshHelper.animatedNorm.resize(mesh->mNumVertices); + int numOfAnimations = scene->mNumAnimations; + for (int i = 0; imAnimations[i]; + animations.push_back(ofxAssimpAnimation(scene, animation)); + } + + if(hasAnimations()){ + meshHelper.animatedPos.resize(mesh->mNumVertices); + if(mesh->HasNormals()){ + meshHelper.animatedNorm.resize(mesh->mNumVertices); + } } @@ -335,11 +340,7 @@ void ofxAssimpModelLoader::loadGLResources(){ //modelMeshes.push_back(meshHelper); } - int numOfAnimations = scene->mNumAnimations; - for(int i=0; imAnimations[i]; - animations.push_back(ofxAssimpAnimation(scene, animation)); - } + ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): finished"; } @@ -370,7 +371,6 @@ void ofxAssimpModelLoader::clear(){ textures.clear(); updateModelMatrix(); - ofRemoveListener(ofEvents().exit,this,&ofxAssimpModelLoader::onAppExit); } //------------------------------------------- update. @@ -413,6 +413,9 @@ void ofxAssimpModelLoader::updateMeshes(aiNode * node, ofMatrix4x4 parentMatrix) } void ofxAssimpModelLoader::updateBones() { + if (!hasAnimations()){ + return; + } // update mesh position for the animation for(unsigned int i=0; imNumVertices); - if(mesh->HasNormals()){ - modelMeshes[i].vbo.updateNormalData(&modelMeshes[i].animatedNorm[0].x,mesh->mNumVertices); + if(hasAnimations()){ + modelMeshes[i].vbo.updateVertexData(&modelMeshes[i].animatedPos[0].x,mesh->mNumVertices); + if(mesh->HasNormals()){ + modelMeshes[i].vbo.updateNormalData(&modelMeshes[i].animatedNorm[0].x,mesh->mNumVertices); + } } modelMeshes[i].hasChanged = false; } @@ -604,7 +609,7 @@ ofxAssimpMeshHelper & ofxAssimpModelLoader::getMeshHelper(int meshIndex) { } //------------------------------------------- -void ofxAssimpModelLoader::getBoundingBoxWithMinVector( aiVector3D* min, aiVector3D* max) +void ofxAssimpModelLoader::getBoundingBoxWithMinVector( aiVector3D* min, aiVector3D* max ) { aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); @@ -612,40 +617,39 @@ void ofxAssimpModelLoader::getBoundingBoxWithMinVector( aiVector3D* min, aiVecto min->x = min->y = min->z = 1e10f; max->x = max->y = max->z = -1e10f; - this->getBoundingBoxForNode(scene->mRootNode, min, max, &trafo); + for(auto & mesh: modelMeshes){ + this->getBoundingBoxForNode(mesh, min, max); + } } //------------------------------------------- -void ofxAssimpModelLoader::getBoundingBoxForNode(const aiNode* nd, aiVector3D* min, aiVector3D* max, aiMatrix4x4* trafo) -{ - aiMatrix4x4 prev; - unsigned int n = 0, t; - - prev = *trafo; - aiMultiplyMatrix4(trafo,&nd->mTransformation); - - for (; n < nd->mNumMeshes; ++n){ - const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; - for (t = 0; t < mesh->mNumVertices; ++t){ - aiVector3D tmp = mesh->mVertices[t]; - aiTransformVecByMatrix4(&tmp,trafo); - - - min->x = MIN(min->x,tmp.x); - min->y = MIN(min->y,tmp.y); - min->z = MIN(min->z,tmp.z); - - max->x = MAX(max->x,tmp.x); - max->y = MAX(max->y,tmp.y); - max->z = MAX(max->z,tmp.z); - } - } - - for (n = 0; n < nd->mNumChildren; ++n){ - this->getBoundingBoxForNode(nd->mChildren[n], min, max, trafo); - } +void ofxAssimpModelLoader::getBoundingBoxForNode(const ofxAssimpMeshHelper & mesh, aiVector3D* min, aiVector3D* max){ + if (!hasAnimations()){ + for (size_t i=0; imNumVertices; i++){ + auto vertex = mesh.mesh->mVertices[i]; + auto tmp = ofVec3f(vertex.x,vertex.y,vertex.z) * mesh.matrix; + + min->x = MIN(min->x,tmp.x); + min->y = MIN(min->y,tmp.y); + min->z = MIN(min->z,tmp.z); + + max->x = MAX(max->x,tmp.x); + max->y = MAX(max->y,tmp.y); + max->z = MAX(max->z,tmp.z); + } + } else { + for (auto & animPos: mesh.animatedPos){ + auto tmp = ofVec3f(animPos.x,animPos.y,animPos.z) * mesh.matrix; + + min->x = MIN(min->x,tmp.x); + min->y = MIN(min->y,tmp.y); + min->z = MIN(min->z,tmp.z); - *trafo = prev; + max->x = MAX(max->x,tmp.x); + max->y = MAX(max->y,tmp.y); + max->z = MAX(max->z,tmp.z); + } + } } //------------------------------------------- @@ -718,6 +722,10 @@ void ofxAssimpModelLoader::draw(ofPolyRenderMode renderType) { ofPushMatrix(); ofMultMatrix(modelMatrix); +#ifndef TARGET_OPENGLES + glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType)); +#endif + for(unsigned int i=0; i1 || (__EMSCRIPTEN_major__==1 && __EMSCRIPTEN_minor__>22) emscripten_async_wget2_data(url.c_str(), "GET", "", req, true, &onload_cb, &onerror_cb, NULL); #endif - return req->getID(); + return req->getId(); } -ofHttpResponse ofxEmscriptenURLFileLoader::saveTo(string url, string path){ +ofHttpResponse ofxEmscriptenURLFileLoader::saveTo(const string & url, const string & path){ saveAsync(url,path); return ofHttpResponse(); } -int ofxEmscriptenURLFileLoader::saveAsync(string url, string path){ +int ofxEmscriptenURLFileLoader::saveAsync(const string & url, const string & path){ ofHttpRequest * req = new ofHttpRequest(url,url,true); #if __EMSCRIPTEN_major__>1 || (__EMSCRIPTEN_major__==1 && __EMSCRIPTEN_minor__>22) emscripten_async_wget2(url.c_str(), path.c_str(), "GET", "", req, &onload_file_cb, &onerror_file_cb, NULL); diff --git a/addons/ofxEmscripten/src/ofxEmscriptenURLFileLoader.h b/addons/ofxEmscripten/src/ofxEmscriptenURLFileLoader.h index e6cfb2a4deb..e678741f5e8 100644 --- a/addons/ofxEmscripten/src/ofxEmscriptenURLFileLoader.h +++ b/addons/ofxEmscripten/src/ofxEmscriptenURLFileLoader.h @@ -12,10 +12,10 @@ class ofxEmscriptenURLFileLoader: public ofBaseURLFileLoader { public: ofxEmscriptenURLFileLoader(); virtual ~ofxEmscriptenURLFileLoader(); - ofHttpResponse get(string url); - int getAsync(string url, string name=""); // returns id - ofHttpResponse saveTo(string url, string path); - int saveAsync(string url, string path); + ofHttpResponse get(const string & url); + int getAsync(const string & url, const string & name=""); // returns id + ofHttpResponse saveTo(const string & url, const string & path); + int saveAsync(const string & url, const string & path); ofHttpResponse handleRequest(ofHttpRequest request); void remove(int id); void clear(); diff --git a/addons/ofxEmscripten/src/ofxEmscriptenVideoPlayer.cpp b/addons/ofxEmscripten/src/ofxEmscriptenVideoPlayer.cpp index 74a8575635c..1b8af09730e 100644 --- a/addons/ofxEmscripten/src/ofxEmscriptenVideoPlayer.cpp +++ b/addons/ofxEmscripten/src/ofxEmscriptenVideoPlayer.cpp @@ -42,7 +42,7 @@ void ofxEmscriptenVideoPlayer::close(){ void ofxEmscriptenVideoPlayer::update(){ gotFirstFrame = pixels.isAllocated(); - if(html5video_player_update(id,pixels.isAllocated() && usePixels,pixels.getPixels())){ + if(html5video_player_update(id,pixels.isAllocated() && usePixels,pixels.getData())){ if(texture.texData.width!=html5video_player_width(id) || texture.texData.height!=html5video_player_height(id)){ texture.texData.width = html5video_player_width(id); texture.texData.height = html5video_player_height(id); @@ -67,13 +67,13 @@ void ofxEmscriptenVideoPlayer::update(){ texture.texData.bFlipTexture = false; switch(getPixelFormat()){ case OF_PIXELS_RGBA: - texture.texData.glTypeInternal = GL_RGBA; + texture.texData.glInternalFormat = GL_RGBA; break; case OF_PIXELS_RGB: - texture.texData.glTypeInternal = GL_RGB; + texture.texData.glInternalFormat = GL_RGB; break; case OF_PIXELS_MONO: - texture.texData.glTypeInternal = GL_LUMINANCE; + texture.texData.glInternalFormat = GL_LUMINANCE; break; default: ofLogError() << "unknown pixel format, can't allocating texture"; diff --git a/addons/ofxGui/src/ofxBaseGui.cpp b/addons/ofxGui/src/ofxBaseGui.cpp index ac988107688..1b1182f672a 100644 --- a/addons/ofxGui/src/ofxBaseGui.cpp +++ b/addons/ofxGui/src/ofxBaseGui.cpp @@ -1,7 +1,9 @@ #include "ofxBaseGui.h" -#include "ofXml.h" #include "ofImage.h" #include "ofBitmapFont.h" +#ifndef TARGET_EMSCRIPTEN +#include "ofXml.h" +#endif using namespace std; @@ -64,7 +66,9 @@ ofBitmapFont ofxBaseGui::bitmapFont; ofxBaseGui::ofxBaseGui() :b(Config().shape) -,serializer(new ofXml) +#ifndef TARGET_EMSCRIPTEN + ,serializer(std::make_shared()) +#endif ,thisHeaderBackgroundColor(Config().headerBackgroundColor) ,thisBackgroundColor(Config().backgroundColor) ,thisBorderColor(Config().borderColor) @@ -72,6 +76,8 @@ ofxBaseGui::ofxBaseGui() ,thisFillColor(Config().fillColor) ,inContainer(Config().inContainer) ,layout(Config().layout) +,textLayout(Config().textLayout) +,bShowName(Config().showName) ,needsRedraw(true) ,currentFrame(ofGetFrameNum()) ,bRegisteredForMouseEvents(false){ @@ -80,7 +86,9 @@ ofxBaseGui::ofxBaseGui() ofxBaseGui::ofxBaseGui(const Config & config) :b(config.shape) -,serializer(new ofXml) +#ifndef TARGET_EMSCRIPTEN + ,serializer(std::make_shared()) +#endif ,thisHeaderBackgroundColor(config.headerBackgroundColor) ,thisBackgroundColor(config.backgroundColor) ,thisBorderColor(config.borderColor) @@ -88,6 +96,8 @@ ofxBaseGui::ofxBaseGui(const Config & config) ,thisFillColor(config.fillColor) ,inContainer(config.inContainer) ,layout(config.layout) +,textLayout(config.textLayout) +,bShowName(config.showName) ,needsRedraw(true) ,currentFrame(ofGetFrameNum()) ,bRegisteredForMouseEvents(false){ @@ -103,10 +113,11 @@ void ofxBaseGui::setup(const Config & config){ thisFillColor = config.fillColor; inContainer = config.inContainer; layout = config.layout; + textLayout = config.textLayout; } void ofxBaseGui::loadFont(const std::string& filename, int fontsize, bool _bAntiAliased, bool _bFullCharacterSet, int dpi){ - font.load(filename, fontsize, _bAntiAliased, _bFullCharacterSet, dpi); + font.load(filename, fontsize, _bAntiAliased, _bFullCharacterSet, false, 0, dpi); fontLoaded = true; useTTF = true; } @@ -122,19 +133,19 @@ ofxBaseGui::~ofxBaseGui(){ unregisterMouseEvents(); } -void ofxBaseGui::registerMouseEvents(){ +void ofxBaseGui::registerMouseEvents(int priority){ if(bRegisteredForMouseEvents == true){ return; // already registered. } bRegisteredForMouseEvents = true; - ofRegisterMouseEvents(this, OF_EVENT_ORDER_BEFORE_APP); + ofRegisterMouseEvents(this, priority); } -void ofxBaseGui::unregisterMouseEvents(){ +void ofxBaseGui::unregisterMouseEvents(int priority){ if(bRegisteredForMouseEvents == false){ return; // not registered. } - ofUnregisterMouseEvents(this, OF_EVENT_ORDER_BEFORE_APP); + ofUnregisterMouseEvents(this, priority); bRegisteredForMouseEvents = false; } @@ -189,14 +200,22 @@ ofRectangle ofxBaseGui::getTextBoundingBox(const string & text, float x, float y } void ofxBaseGui::saveToFile(const std::string& filename){ - serializer->load(filename); - saveTo(*serializer); - serializer->save(filename); + if(serializer){ + serializer->load(filename); + saveTo(*serializer); + serializer->save(filename); + }else{ + ofLogError("ofxGui") << "element has no serializer to save to"; + } } void ofxBaseGui::loadFromFile(const std::string& filename){ - serializer->load(filename); - loadFrom(*serializer); + if(serializer){ + serializer->load(filename); + loadFrom(*serializer); + }else{ + ofLogError("ofxGui") << "element has no serializer to load from"; + } } @@ -221,7 +240,7 @@ void ofxBaseGui::setName(const std::string& _name){ getParameter().setName(_name); } -void ofxBaseGui::setPosition(ofPoint p){ +void ofxBaseGui::setPosition(const ofPoint & p){ setPosition(p.x, p.y); } @@ -258,6 +277,10 @@ void ofxBaseGui::setLayout(Layout layout){ this->layout = layout; } +void ofxBaseGui::setTextLayout(TextLayout textLayout){ + this->textLayout = textLayout; +} + ofPoint ofxBaseGui::getPosition() const { return ofPoint(b.x, b.y); } @@ -274,6 +297,14 @@ float ofxBaseGui::getHeight() const { return b.height; } +ofxBaseGui::Layout ofxBaseGui::getLayout() const { + return layout; +} + +ofxBaseGui::TextLayout ofxBaseGui::getTextLayout() const { + return textLayout; +} + ofColor ofxBaseGui::getHeaderBackgroundColor() const { return thisHeaderBackgroundColor; } @@ -355,6 +386,11 @@ void ofxBaseGui::setNeedsRedraw(){ needsRedraw = true; } +void ofxBaseGui::setShowName(bool show){ + bShowName = show; + setNeedsRedraw(); +} + string ofxBaseGui::saveStencilToHex(const ofImage & img){ stringstream strm; int width = img.getWidth(); @@ -400,3 +436,15 @@ void ofxBaseGui::loadStencilFromHex(ofImage & img, unsigned char * data){ } img.update(); } + +float ofxBaseGui::getTextWidth(const std::string & text, float _height){ + float _width = 0; + ofVboMesh mesh = getTextMesh(text, 0, _height / 2 + 4); + for(unsigned int i = 0; i < mesh.getVertices().size(); i++){ + if(mesh.getVertex(i).x > _width){ + _width = mesh.getVertex(i).x; + } + } + _width += textPadding * 2; + return _width; +} diff --git a/addons/ofxGui/src/ofxBaseGui.h b/addons/ofxGui/src/ofxBaseGui.h index fcbd002fa59..b222969fcc4 100644 --- a/addons/ofxGui/src/ofxBaseGui.h +++ b/addons/ofxGui/src/ofxBaseGui.h @@ -12,15 +12,22 @@ class ofxBaseGui { Horizontal, Vertical }; + enum TextLayout{ + Left, + Right, + Centered + }; struct Config{ ofColor headerBackgroundColor = ofxBaseGui::headerBackgroundColor; ofColor backgroundColor = ofxBaseGui::backgroundColor; ofColor borderColor = ofxBaseGui::borderColor; ofColor textColor = ofxBaseGui::textColor; ofColor fillColor = ofxBaseGui::fillColor; - Layout layout = Vertical; + Layout layout = Horizontal; + TextLayout textLayout = Left; bool inContainer = false; ofRectangle shape{0.0f, 0.0f, (float)defaultWidth, (float)defaultHeight}; + bool showName = true; }; ofxBaseGui(); ofxBaseGui(const Config & config); @@ -42,13 +49,18 @@ class ofxBaseGui { std::string getName(); void setName(const std::string& name); - virtual void setPosition(ofPoint p); + + virtual void setPosition(const ofPoint & p); virtual void setPosition(float x, float y); + virtual void setSize(float w, float h); virtual void setShape(ofRectangle r); virtual void setShape(float x, float y, float w, float h); virtual void setInContainer(bool inContainer=true); virtual void setLayout(Layout layout=Vertical); + virtual void setTextLayout(TextLayout textLayout=Left); + Layout getLayout() const; + TextLayout getTextLayout() const; ofPoint getPosition() const; ofRectangle getShape() const; @@ -77,12 +89,14 @@ class ofxBaseGui { static void setDefaultWidth(int width); static void setDefaultHeight(int height); + void setShowName(bool show); + virtual ofAbstractParameter & getParameter() = 0; static void loadFont(const std::string& filename, int fontsize, bool _bAntiAliased = true, bool _bFullCharacterSet = false, int dpi = 0); static void setUseTTF(bool bUseTTF); - void registerMouseEvents(); - void unregisterMouseEvents(); + void registerMouseEvents(int priority = OF_EVENT_ORDER_BEFORE_APP); + void unregisterMouseEvents(int priority = OF_EVENT_ORDER_BEFORE_APP); virtual bool mouseMoved(ofMouseEventArgs & args) = 0; virtual bool mousePressed(ofMouseEventArgs & args) = 0; @@ -104,6 +118,7 @@ class ofxBaseGui { void unbindFontTexture(); ofMesh getTextMesh(const std::string & text, float x, float y); ofRectangle getTextBoundingBox(const std::string & text, float x, float y); + float getTextWidth(const std::string & text, float height); ofRectangle b; static ofTrueTypeFont font; @@ -125,11 +140,14 @@ class ofxBaseGui { ofColor thisFillColor; bool inContainer; Layout layout; + TextLayout textLayout; static int textPadding; static int defaultWidth; static int defaultHeight; + bool bShowName; + static std::string saveStencilToHex(const ofImage & img); static void loadStencilFromHex(ofImage & img, unsigned char * data); diff --git a/addons/ofxGui/src/ofxButton.cpp b/addons/ofxGui/src/ofxButton.cpp index fd2bcdac3e1..d9f28c7a8ae 100644 --- a/addons/ofxGui/src/ofxButton.cpp +++ b/addons/ofxGui/src/ofxButton.cpp @@ -1,34 +1,89 @@ #include "ofxButton.h" using namespace std; -ofxButton::ofxButton(const Config & config) -:ofxToggle(ofParameter{config.name,false}, config){ - value.setSerializable(false); - registerMouseEvents(); - value.addListener(this,&ofxButton::valueChanged); +ofxButton::ofxButton():ofxToggle(){} + +ofxButton::ofxButton(ofParameter _val, const Config & config) +:ofxToggle(value, config){ + //value.setSerializable(false); + voidvalue.makeReferenceTo(_val); + useVoidValue = true; +} + +ofxButton::ofxButton(ofParameter _val, const Config & config) +:ofxToggle(_val, config){ } ofxButton::~ofxButton(){ - // } -ofxButton & ofxButton::setup(const std::string& toggleName, float width, float height){ - setName(toggleName); - b.x = 0; - b.y = 0; - b.width = width; - b.height = height; - bGuiActive = false; - value = false; - checkboxRect.set(1, 1, b.height - 2, b.height - 2); +ofxButton & ofxButton::setup(ofParameter& _val, const Config & config){ + ofxToggle::setup(value, config); + voidvalue.makeReferenceTo(_val); + useVoidValue = true; + return *this; +} - registerMouseEvents(); +ofxButton & ofxButton::setup(ofParameter &_val, const Config & config){ + ofxToggle::setup(_val, config); + return *this; +} - value.addListener(this,&ofxButton::valueChanged); +ofxButton & ofxButton::setup(const std::string& buttonName, const Config & config){ + value.setName(buttonName); + return setup(value, config); +} + +ofxButton & ofxButton::setup(ofParameter& _val, float width, float height){ + ofxToggle::setup(value, width, height); + voidvalue.makeReferenceTo(_val); + useVoidValue = true; + return *this; +} +ofxButton & ofxButton::setup(ofParameter& _val, float width, float height){ + ofxToggle::setup(_val, width, height); return *this; } +bool ofxButton::setValue(float mx, float my, bool bCheck){ + + if( !isGuiDrawing() ){ + bGuiActive = false; + return false; + } + if( bCheck ){ + ofRectangle checkRect = checkboxRect; + checkRect.x += b.x; + checkRect.y += b.y; + + if( checkRect.inside(mx, my) ){ + bGuiActive = true; + }else{ + bGuiActive = false; + + } + } + if( bGuiActive ){ + value = !value; + voidvalue.trigger(); + return true; + } + return false; +} + +ofxButton & ofxButton::setup(const std::string& buttonName, float width, float height){ + value.setName(buttonName); + return setup(value, width, height); +} + +void ofxButton::generateDraw(){ + if(useVoidValue){ + value.setName(voidvalue.getName()); + } + ofxToggle::generateDraw(); +} + bool ofxButton::mouseReleased(ofMouseEventArgs & args){ bool attended = setValue(args.x, args.y, false); bGuiActive = false; @@ -51,8 +106,3 @@ bool ofxButton::mouseDragged(ofMouseEventArgs & args){ return ofxToggle::mouseDragged(args); } -void ofxButton::valueChanged(bool & v){ - if(!v){ - ofNotifyEvent(triggerEvent, this); - } -} diff --git a/addons/ofxGui/src/ofxButton.h b/addons/ofxGui/src/ofxButton.h index 01267854364..09666456a89 100644 --- a/addons/ofxGui/src/ofxButton.h +++ b/addons/ofxGui/src/ofxButton.h @@ -11,12 +11,18 @@ class ofxButton : public ofxToggle{ :ofxToggle::Config(c){} Config(const ofxBaseGui::Config & c) :ofxToggle::Config(c){} - std::string name; }; - ofxButton(const Config & config = Config()); + ofxButton(); + ofxButton(ofParameter _val, const Config & config); + ofxButton(ofParameter _bVal, const Config & config); ~ofxButton(); - ofxButton & setup(const std::string& toggleName, float width = defaultWidth, float height = defaultHeight); + ofxButton & setup(const std::string& buttonName, const Config & config); + ofxButton & setup(ofParameter& _val, const Config & config); + ofxButton & setup(ofParameter& _bVal, const Config & config); + ofxButton & setup(const std::string& buttonName, float width = defaultWidth, float height = defaultHeight); + ofxButton & setup(ofParameter& _val, float width = defaultWidth, float height = defaultHeight); + ofxButton & setup(ofParameter& _bVal, float width = defaultWidth, float height = defaultHeight); virtual bool mouseReleased(ofMouseEventArgs & args); virtual bool mouseMoved(ofMouseEventArgs & args); @@ -25,16 +31,18 @@ class ofxButton : public ofxToggle{ template void addListener(ListenerClass * listener, ListenerMethod method){ - ofAddListener(triggerEvent,listener,method); + voidvalue.addListener(listener,method); } template void removeListener(ListenerClass * listener, ListenerMethod method){ - ofRemoveListener(triggerEvent,listener,method); + voidvalue.removeListener(listener,method); } -private: - ofEvent triggerEvent; - void valueChanged(bool & v); +protected: + virtual void generateDraw(); + bool setValue(float mx, float my, bool bCheck); + ofParameter voidvalue; + bool useVoidValue {false}; }; diff --git a/addons/ofxGui/src/ofxFpsPlotter.cpp b/addons/ofxGui/src/ofxFpsPlotter.cpp new file mode 100644 index 00000000000..21c156c6d48 --- /dev/null +++ b/addons/ofxGui/src/ofxFpsPlotter.cpp @@ -0,0 +1,40 @@ +#include "ofxFpsPlotter.h" +#include "ofAppRunner.h" + +ofxFpsPlotter::ofxFpsPlotter(){ +} + +ofxFpsPlotter::ofxFpsPlotter(const ofxValuePlotter::Config & config) +:ofxValuePlotter(ofParameter("fps",0),config){ + if(minVal == maxVal) { + if(ofGetTargetFrameRate() > 0) { + minVal = 0; + maxVal = ofGetTargetFrameRate(); + } + } + setDecimalPlace(0); + ofAddListener(ofEvents().update,this,&ofxFpsPlotter::update); +} + +ofxFpsPlotter::~ofxFpsPlotter(){ + ofRemoveListener(ofEvents().update,this,&ofxFpsPlotter::update); +} + +ofxFpsPlotter & ofxFpsPlotter::setup(string label, float minValue, float maxValue, int plotSize, float width, float height){ + ofxValuePlotter::setup(label, minValue, maxValue, plotSize, width, height); + if(minVal == maxVal) { + if(ofGetTargetFrameRate() > 0) { + minVal = 0; + maxVal = ofGetTargetFrameRate(); + } + } + setDecimalPlace(0); + ofAddListener(ofEvents().update,this,&ofxFpsPlotter::update); + return *this; +} + +void ofxFpsPlotter::update(ofEventArgs &){ + value = ofGetFrameRate(); + setNeedsRedraw(); +} + diff --git a/addons/ofxGui/src/ofxFpsPlotter.h b/addons/ofxGui/src/ofxFpsPlotter.h new file mode 100644 index 00000000000..4c3acecb41d --- /dev/null +++ b/addons/ofxGui/src/ofxFpsPlotter.h @@ -0,0 +1,17 @@ +#pragma once + +#include "ofxValuePlotter.h" + +class ofxFpsPlotter : public ofxValuePlotter { + public: + ofxFpsPlotter(); + ofxFpsPlotter(const ofxValuePlotter::Config & config); + virtual ~ofxFpsPlotter(); + + ofxFpsPlotter & setup(string label = "", float minValue = Config().minValue, float maxValue = Config().maxValue, int plotSize = Config().plotSize, float width = defaultWidth, float height = defaultHeight); + + void update(ofEventArgs &); + + protected: + +}; diff --git a/addons/ofxGui/src/ofxGui.h b/addons/ofxGui/src/ofxGui.h index 5c554773260..4ceae9d5eab 100644 --- a/addons/ofxGui/src/ofxGui.h +++ b/addons/ofxGui/src/ofxGui.h @@ -6,6 +6,15 @@ #include "ofxPanel.h" #include "ofxButton.h" #include "ofxLabel.h" +#include "ofxMinimalButton.h" +#include "ofxMinimalToggle.h" +#include "ofxRotarySlider.h" +#include "ofxGuiSpacer.h" +#include "ofxGuiMatrix.h" +#include "ofxGuiPage.h" +#include "ofxTabbedPages.h" +#include "ofxValuePlotter.h" +#include "ofxFpsPlotter.h" void ofxGuiSetFont(const string & fontPath,int fontsize, bool _bAntiAliased=true, bool _bFullCharacterSet=false, int dpi=0); void ofxGuiSetBitmapFont(); diff --git a/addons/ofxGui/src/ofxGuiGroup.cpp b/addons/ofxGui/src/ofxGuiGroup.cpp index 42dcc1a471f..e3ad67eb02e 100644 --- a/addons/ofxGui/src/ofxGuiGroup.cpp +++ b/addons/ofxGui/src/ofxGuiGroup.cpp @@ -2,57 +2,19 @@ #include "ofxPanel.h" #include "ofGraphics.h" #include "ofxSliderGroup.h" +#include "ofxGuiSpacer.h" using namespace std; -ofxGuiGroup::ofxGuiGroup() -:ofxBaseGui(Config()) -,spacing(Config().spacing) -,spacingNextElement(Config().spacingNextElement) -,spacingFirstElement(Config().spacingFirstElement) -,header(Config().header) -,filename(Config().filename) -,minimized(Config().minimized) -,bGuiActive(false){ -} - -ofxGuiGroup::ofxGuiGroup(const ofParameterGroup & _parameters) -:ofxBaseGui(Config()) -,spacing(Config().spacing) -,spacingNextElement(Config().spacingNextElement) -,spacingFirstElement(Config().spacingFirstElement) -,header(Config().header) -,filename(Config().filename) -,minimized(Config().minimized) -,bGuiActive(false){ - addParametersFrom(_parameters); - parameters = _parameters; - registerMouseEvents(); - setNeedsRedraw(); +ofxGuiGroup::ofxGuiGroup(){ } -ofxGuiGroup::ofxGuiGroup(const ofParameterGroup & _parameters, const Config & config) -:ofxBaseGui(config) -,spacing(config.spacing) -,spacingNextElement(config.spacingNextElement) -,spacingFirstElement(config.spacingFirstElement) -,header(config.header) -,filename(config.filename) -,minimized(config.minimized) -,bGuiActive(false) -,config(config){ - addParametersFrom(_parameters); - parameters = _parameters; - registerMouseEvents(); - setNeedsRedraw(); +ofxGuiGroup::ofxGuiGroup(const ofParameterGroup & _parameters, const Config & groupConfig, const Config & itemConfig) +:ofxBaseGui(groupConfig){ + setup(_parameters, groupConfig, itemConfig); } -ofxGuiGroup::ofxGuiGroup(const ofParameterGroup & parameters, const std::string& filename, float x, float y){ - minimized = false; - spacing = 1; - spacingNextElement = 3; - spacingFirstElement = 0; - header = defaultHeight; - setup(parameters, filename, x, y); +ofxGuiGroup::ofxGuiGroup(const Config & config){ + setup(config); } ofxGuiGroup::~ofxGuiGroup(){ @@ -61,7 +23,7 @@ ofxGuiGroup::~ofxGuiGroup(){ } } -ofxGuiGroup & ofxGuiGroup::setup(const ofParameterGroup & parameters, const Config & config){ +ofxGuiGroup & ofxGuiGroup::setup(const Config & config){ ofxBaseGui::setup(config); spacing = config.spacing; spacingNextElement = config.spacingNextElement; @@ -69,30 +31,62 @@ ofxGuiGroup & ofxGuiGroup::setup(const ofParameterGroup & parameters, const Conf header = config.header; filename = config.filename; minimized = config.minimized; + bShowHeader = config.showHeader; + bExclusiveToggles = config.exclusiveToggles; + bDistributeEvenly = config.distributeEvenly; bGuiActive = false; this->config = config; - addParametersFrom(parameters); - this->parameters = parameters; registerMouseEvents(); setNeedsRedraw(); return *this; } +ofxGuiGroup & ofxGuiGroup::setup(const std::string& collectionName, const Config & config){ + setup(config); + setName(collectionName); + return *this; +} + + +ofxGuiGroup & ofxGuiGroup::setup(const ofParameterGroup & parameters, const Config & groupConfig, const Config & itemConfig){ + setup(groupConfig); + addParametersFrom(parameters, itemConfig); + this->parameters = parameters; + if(layout == ofxBaseGui::Horizontal){ + for(auto e: collection){ + e->sizeChangedE.disable(); + e->setSize(getWidth()/collection.size()-spacingNextElement, e->getHeight()); + e->sizeChangedE.enable(); + } + setNeedsRedraw(); + } + return *this; +} + ofxGuiGroup & ofxGuiGroup::setup(const std::string& collectionName, const std::string& filename, float x, float y){ - parameters.setName(collectionName); + setName(collectionName); return setup(parameters, filename, x, y); } ofxGuiGroup & ofxGuiGroup::setup(const ofParameterGroup & _parameters, const std::string& _filename, float x, float y){ b.x = x; b.y = y; - spacing = 1; + spacing = Config().spacing; + spacingNextElement = Config().spacingNextElement; + spacingFirstElement = Config().spacingFirstElement; + header = Config().header; + minimized = Config().minimized; + bShowHeader = Config().showHeader; b.width = defaultWidth; + layout = Config().layout; + bExclusiveToggles = Config().exclusiveToggles; + bDistributeEvenly = Config().distributeEvenly; clear(); filename = _filename; bGuiActive = false; addParametersFrom(_parameters); + parameters = _parameters; registerMouseEvents(); setNeedsRedraw(); @@ -100,18 +94,35 @@ ofxGuiGroup & ofxGuiGroup::setup(const ofParameterGroup & _parameters, const std return *this; } - -void ofxGuiGroup::addParametersFrom(const ofParameterGroup & parameters){ +void ofxGuiGroup::addParametersFrom(const ofParameterGroup & parameters, const Config & config){ for(auto & p: parameters){ if(p->isReadOnly()){ ofLogWarning("ofxGui") << "Trying to add " << p->getName() << ": read only parameters not supported yet in ofxGui"; continue; } string type = p->type(); - if(type == typeid(ofParameter).name()){ + if(type == typeid(ofParameter ).name()){ add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); }else if(type == typeid(ofParameter).name()){ add(p->cast(), config); + }else if(type == typeid(ofParameter ).name()){ + add(p->cast(), config); + }else if(type == typeid(ofParameter).name()){ + add(p->cast(), config); }else if(type == typeid(ofParameter).name()){ add(p->cast(), config); }else if(type == typeid(ofParameter).name()){ @@ -132,6 +143,7 @@ void ofxGuiGroup::addParametersFrom(const ofParameterGroup & parameters){ add(p->castGroup(), config); }else{ ofLogWarning("ofxGui") << "Trying to add " << p->getName() << ": ofxBaseGroup; no control for parameter of type " << type; + } } } @@ -145,62 +157,90 @@ void ofxGuiGroup::add(ofxGuiGroup & element){ add(&element); } -void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); -} - -void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); +void ofxGuiGroup::add(ofParameter & parameter){ + add(parameter, ofxButton::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxToggle::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxLabel::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxVec2Slider::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxVec3Slider::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxVec4Slider::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxColorSlider::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxShortColorSlider::Config()); } void ofxGuiGroup::add(ofParameter & parameter){ - add(parameter, this->config); + add(parameter, ofxFloatColorSlider::Config()); } void ofxGuiGroup::add(ofxBaseGui * element){ collection.push_back(element); - element->setPosition(b.x, b.y + b.height + spacing); - element->setSize(getWidth(), element->getHeight()); - b.height += element->getHeight() + spacing; + + if(layout == ofxBaseGui::Vertical || collection.size() == 1) { + if(layout == ofxBaseGui::Vertical){ + if(element->getWidth() < b.width-1) { + element->sizeChangedE.disable(); + element->setSize(b.width-1, element->getHeight()); + element->sizeChangedE.enable(); + } + } + if(collection.size() == 1) { + if(bShowHeader){ + element->setPosition(b.x, b.y + header + spacing + spacingFirstElement); + }else{ + element->setPosition(b.x, b.y + spacing + spacingFirstElement); + } + }else{ + ofxBaseGui* last = collection.at(collection.size()-2); + element->setPosition(b.x, last->getShape().getBottom()+spacing); + } + + }else{ + ofRectangle last_shape = collection[collection.size()-2]->getShape(); + element->setPosition(last_shape.x + last_shape.getWidth() + spacing, last_shape.y); + } + + //change size of group if element is bigger than group + b.height = max(b.height, element->getShape().getBottom() + 1 - b.y); + if(getShape().getRight()+ 1 < element->getShape().getRight() && !bDistributeEvenly) { + b.width = element->getShape().getRight() + 1 - b.x; + } element->unregisterMouseEvents(); ofAddListener(element->sizeChangedE,this,&ofxGuiGroup::sizeChangedCB); parameters.add(element->getParameter()); - setNeedsRedraw(); + sizeChangedCB(); + + if(bExclusiveToggles) { + setOneToggleActive(); + } } void ofxGuiGroup::add(ofxGuiGroup * element){ element->spacingFirstElement = 3; element->filename = filename; + element->inContainer = true; add(static_cast(element)); } @@ -214,19 +254,38 @@ void ofxGuiGroup::addOwned(ofxGuiGroup * element){ add(element); } +void ofxGuiGroup::addSpacer(float size) { + ofxGuiSpacer::Config spacer_config; + if(layout == ofxBaseGui::Vertical){ + spacer_config.shape.height = size; + }else { + spacer_config.shape.width = size; + } + add (spacer_config); +} + void ofxGuiGroup::setWidthElements(float w){ - for(auto & e: collection){ - e->setSize(w, e->getHeight()); - e->setPosition(b.x + b.width - w, e->getPosition().y); + if(layout == ofxBaseGui::Vertical){ + for(auto & e: collection){ + e->setSize(w, e->getHeight()); + e->setPosition(b.x + b.width - w, e->getPosition().y); + } + sizeChangedCB(); + setNeedsRedraw(); + } + else{ + //TODO } - sizeChangedCB(); - setNeedsRedraw(); } void ofxGuiGroup::clear(){ collection.clear(); parameters.clear(); - b.height = header + spacing + spacingNextElement; + b.height = spacing + spacingNextElement; + if(bShowHeader){ + b.height += header; + } + active_toggle_index = -1; sizeChangedCB(); } @@ -251,8 +310,13 @@ bool ofxGuiGroup::mousePressed(ofMouseEventArgs & args){ if(bGuiActive){ ofMouseEventArgs a = args; for(auto & e: collection){ - if(e->mousePressed(a)){ - return true; + ofxToggle* toggle = dynamic_cast(e); + if(toggle && bExclusiveToggles){ + if(processToggles(toggle, a)) return true; + }else{ + if(e->mousePressed(a)){ + return true; + } } } } @@ -305,38 +369,46 @@ bool ofxGuiGroup::mouseScrolled(ofMouseEventArgs & args){ void ofxGuiGroup::generateDraw(){ border.clear(); - border.setFillColor(ofColor(thisBorderColor, 180)); + border.setFillColor(thisBorderColor); border.setFilled(true); - border.rectangle(b.x, b.y + spacingNextElement, b.width + 1, b.height); - + border.rectangle(b.x, b.y, b.width, b.height); - headerBg.clear(); - headerBg.setFillColor(thisHeaderBackgroundColor); - headerBg.setFilled(true); - headerBg.rectangle(b.x, b.y + 1 + spacingNextElement, b.width, header); + if(bShowHeader){ + headerBg.clear(); + headerBg.setFillColor(thisHeaderBackgroundColor); + headerBg.setFilled(true); + headerBg.rectangle(b.x, b.y, b.width, header); - textMesh = getTextMesh(getName(), textPadding + b.x, header / 2 + 4 + b.y + spacingNextElement); - if(minimized){ - textMesh.append(getTextMesh("+", b.width - textPadding - 8 + b.x, header / 2 + 4 + b.y + spacingNextElement)); - }else{ - textMesh.append(getTextMesh("-", b.width - textPadding - 8 + b.x, header / 2 + 4 + b.y + spacingNextElement)); + textMesh.clear(); + if(bShowName){ + textMesh.append(getTextMesh(getName(), textPadding + b.x, header / 2 + 4 + b.y)); + } + if(minimized){ + textMesh.append(getTextMesh("+", b.width - textPadding - 8 + b.x, header / 2 + 4 + b.y)); + }else{ + textMesh.append(getTextMesh("-", b.width - textPadding - 8 + b.x, header / 2 + 4 + b.y)); + } } } void ofxGuiGroup::render(){ border.draw(); - headerBg.draw(); + if(bShowHeader){ + headerBg.draw(); + } ofBlendMode blendMode = ofGetStyle().blendingMode; if(blendMode != OF_BLENDMODE_ALPHA){ ofEnableAlphaBlending(); } ofColor c = ofGetStyle().color; - ofSetColor(thisTextColor); - bindFontTexture(); - textMesh.draw(); - unbindFontTexture(); + if(bShowHeader){ + ofSetColor(thisTextColor); + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); + } if(!minimized){ for(std::size_t i = 0; i < collection.size(); i++){ @@ -398,15 +470,17 @@ bool ofxGuiGroup::setValue(float mx, float my, bool bCheck){ if(b.inside(mx, my)){ bGuiActive = true; - ofRectangle minButton(b.x + b.width - textPadding * 3, b.y, textPadding * 3, header); - if(minButton.inside(mx, my)){ - minimized = !minimized; - if(minimized){ - minimize(); - }else{ - maximize(); + if(bShowHeader){ + ofRectangle minButton(b.x + b.width - textPadding * 3, b.y, textPadding * 3, header); + if(minButton.inside(mx, my)){ + minimized = !minimized; + if(minimized){ + minimize(); + }else{ + maximize(); + } + return true; } - return true; } } } @@ -416,15 +490,29 @@ bool ofxGuiGroup::setValue(float mx, float my, bool bCheck){ void ofxGuiGroup::minimize(){ minimized = true; - b.height = header + spacing + spacingNextElement + 1 /*border*/; + b.height = spacing + spacingNextElement + 1 /*border*/; + if(bShowHeader){ + b.height += header; + } sizeChangedE.notify(this); setNeedsRedraw(); } void ofxGuiGroup::maximize(){ minimized = false; - for(auto & e: collection){ - b.height += e->getHeight() + spacing; + if(layout == ofxBaseGui::Vertical) { + if(collection.size() > 0){ + b.height = collection.at(collection.size()-1)->getShape().getBottom() + 1 - b.y; + } + } + else { + auto max_h = 0; + for(auto & e: collection){ + if(max_h < e->getShape().getBottom()) { + max_h = e->getShape().getBottom(); + } + } + b.height = max_h + 1 - b.y; } sizeChangedE.notify(this); setNeedsRedraw(); @@ -449,16 +537,67 @@ void ofxGuiGroup::maximizeAll(){ } void ofxGuiGroup::sizeChangedCB(){ - float y = b.y + header + spacing + spacingFirstElement; - for(auto & e: collection){ - e->setPosition(e->getPosition().x, y + spacing); - y += e->getHeight() + spacing; + float x = b.x; + float y = b.y + spacingFirstElement; + if(bShowHeader){ + y += header; + } + + if(!minimized){ + if(layout == ofxBaseGui::Vertical){ + for(auto & e: collection){ + e->sizeChangedE.disable(); + e->setSize((b.width-1)*.98, e->getHeight()); + e->sizeChangedE.enable(); + e->setPosition(b.getRight()-e->getWidth()-1,y + spacing); + y += e->getHeight()+spacing; + } + b.height = y - b.y; + }else{ + float max_h = 0; + if(bDistributeEvenly){ + float e_width = (b.getRight()-x-1)/collection.size()-spacing; + for(auto & e: collection){ + e->sizeChangedE.disable(); + e->setSize(e_width, e->getHeight()); + e->sizeChangedE.enable(); + e->setPosition(x,y + spacing); + x+=e_width+spacing; + if(max_h < e->getHeight()){ + max_h = e->getHeight(); + } + } + + }else { + for(auto & e: collection){ + e->setPosition(x,y + spacing); + x += e->getWidth() + spacing; + if(max_h < e->getHeight()){ + max_h = e->getHeight(); + } + } + } + b.width = max(b.width, x - b.x); + y += max_h+spacing; + b.height = y - b.y; + } + } + else { + b.height = y - b.y; } - b.height = y - b.y; sizeChangedE.notify(this); setNeedsRedraw(); } +void ofxGuiGroup::setShowHeader(bool show) { + if(show == false){ + if(minimized) + maximize(); + } + bShowHeader = show; + sizeChangedCB(); + setNeedsRedraw(); + } std::size_t ofxGuiGroup::getNumControls() const { return collection.size(); @@ -468,7 +607,7 @@ ofxBaseGui * ofxGuiGroup::getControl(std::size_t num){ if(num < collection.size()){ return collection[num]; }else{ - return NULL; + return nullptr; } } @@ -493,15 +632,97 @@ void ofxGuiGroup::setPosition(float x, float y){ void ofxGuiGroup::setSize(float w, float h){ ofxBaseGui::setSize(w,h); - setWidthElements(w * .98); + if(layout == ofxBaseGui::Vertical){ + setWidthElements(w * .98); + }else{ + sizeChangedCB(); + } } void ofxGuiGroup::setShape(ofRectangle r){ - ofxBaseGui::setShape(r); + setSize(r.width, r.height); + setPosition(r.x, r.y); setWidthElements(r.width * .98); } void ofxGuiGroup::setShape(float x, float y, float w, float h){ - ofxBaseGui::setShape(x,y,w,h); + setSize(w, h); + setPosition(x, y); setWidthElements(w * .98); } + +bool ofxGuiGroup::processToggles(ofxToggle* toggle, ofMouseEventArgs a) { + if(bExclusiveToggles) { + if(!toggle->getParameter().cast().get()) { + if(toggle->mousePressed(a)) { + deactivateAllOtherToggles(toggle); + return true; + } + } + } + return false; +} + +void ofxGuiGroup::setExclusiveToggles(bool exclusive) { + bExclusiveToggles = exclusive; + if(bExclusiveToggles) { + setOneToggleActive(); + } +} + +bool ofxGuiGroup::setActiveToggle(ofxToggle* toggle) { + if(!(*toggle)) { + *toggle = true; + deactivateAllOtherToggles(toggle); + return true; + } + return false; +} + +bool ofxGuiGroup::setActiveToggle(int index) { + if(index >= 0 && index < (int)collection.size()){ + if(ofxToggle* toggle = dynamic_cast(collection[index])) { + return setActiveToggle(toggle); + } + else { + ofLogError("ofxGuiGroup", "cannot activate control " + ofToString(index) + " because it's no ofxToggle."); + return false; + } + } + return false; +} + +void ofxGuiGroup::deactivateAllOtherToggles(ofxToggle *toggle) { + if(bExclusiveToggles) { + for(int i = 0; i < (int)collection.size(); i++){ + if(ofxToggle* t = dynamic_cast(collection[i])) { + if(t != toggle) { + *t = false; + } + else { + active_toggle_index.set(i); + } + } + } + } +} + +void ofxGuiGroup::setOneToggleActive() { + if(active_toggle_index == -1){ + for(auto &e : collection){ + if(ofxToggle* t = dynamic_cast(e)) { + setActiveToggle(t); + return; + } + } + } +} + + +ofParameter& ofxGuiGroup::getActiveToggleIndex() { + return active_toggle_index; +} + +void ofxGuiGroup::setDistributeEvenly(bool distribute){ + bDistributeEvenly = distribute; +} diff --git a/addons/ofxGui/src/ofxGuiGroup.h b/addons/ofxGui/src/ofxGuiGroup.h index 279d2ecfb2a..18f579ffa04 100644 --- a/addons/ofxGui/src/ofxGuiGroup.h +++ b/addons/ofxGui/src/ofxGuiGroup.h @@ -5,11 +5,17 @@ #include "ofxButton.h" #include "ofxLabel.h" #include "ofParameterGroup.h" +#include "ofParameter.h" class ofxGuiGroup : public ofxBaseGui { public: + struct Config: public ofxBaseGui::Config{ - Config(){} + Config(){ + this->layout = ofxBaseGui::Vertical; + this->shape.x = 10; + this->shape.y = 10; + } Config(const ofxBaseGui::Config & c) :ofxBaseGui::Config(c){} @@ -19,23 +25,31 @@ class ofxGuiGroup : public ofxBaseGui { float spacingNextElement = 3; float spacingFirstElement = 0; float header = defaultHeight; + bool showHeader = true; + bool exclusiveToggles = false; + bool distributeEvenly = false; }; ofxGuiGroup(); - ofxGuiGroup(const ofParameterGroup & parameters); - ofxGuiGroup(const ofParameterGroup & parameters, const Config & config); - ofxGuiGroup(const ofParameterGroup & parameters, const std::string& _filename, float x = 10, float y = 10); + ofxGuiGroup(const Config & config); + ofxGuiGroup(const ofParameterGroup & parameters, const Config & groupConfig = Config(), const Config &itemConfig = ofxBaseGui::Config()); virtual ~ofxGuiGroup(); - virtual ofxGuiGroup & setup(const ofParameterGroup & parameters, const Config & config); - virtual ofxGuiGroup & setup(const std::string& collectionName = "", const std::string& filename = "settings.xml", float x = 10, float y = 10); - virtual ofxGuiGroup & setup(const ofParameterGroup & parameters, const std::string& filename = "settings.xml", float x = 10, float y = 10); + virtual ofxGuiGroup & setup(const Config & config); + virtual ofxGuiGroup & setup(const std::string& collectionName = "", const Config & config = ofxGuiGroup::Config()); + virtual ofxGuiGroup & setup(const ofParameterGroup & parameters, const Config & groupConfig = ofxGuiGroup::Config(), const Config &itemConfig = ofxBaseGui::Config()); + virtual ofxGuiGroup & setup(const std::string& collectionName, const std::string& filename, float x = 10, float y = 10); + virtual ofxGuiGroup & setup(const ofParameterGroup & parameters, const std::string& filename, float x = 10, float y = 10); void add(ofxBaseGui & element); void add(ofxGuiGroup & element); - void add(ofParameter & parameter); - void add(ofParameter & parameter); + template + typename std::enable_if::value, void>::type add(ofParameter & p){ + add(new ofxSlider(p, typename ofxSlider::Config())); + } + + void add(ofParameter & parameter); void add(ofParameter & parameter); void add(ofParameter & parameter); void add(ofParameter & parameter); @@ -51,11 +65,13 @@ class ofxGuiGroup : public ofxBaseGui { template void add(ofParameterGroup p); - template - void add(ofParameter & parameter, const Config & config); + template + typename std::enable_if::value, void>::type add(ofParameter & p, const Config & config){ + add(new ofxSlider(p, config)); + } template - void add(ofParameter & parameter, const Config & config); + void add(ofParameter & parameter, const Config & config); template void add(ofParameter & parameter, const Config & config); @@ -82,10 +98,10 @@ class ofxGuiGroup : public ofxBaseGui { void add(ofParameter & parameter, const Config & config); template - void add(ofParameter p, const Config & config); + void add(ofParameter &p, const Config & config); - template - void add(ofParameterGroup p, const Config & config); + template + void add(ofParameterGroup p, const CGroup & groupConfig, const CItem & itemConfig = ofxBaseGui::Config()); template void add(const Config & config); @@ -93,6 +109,8 @@ class ofxGuiGroup : public ofxBaseGui { template void add(); + void addSpacer(float size); + void minimize(); void maximize(); void minimizeAll(); @@ -128,6 +146,15 @@ class ofxGuiGroup : public ofxBaseGui { virtual void setSize(float w, float h); virtual void setShape(ofRectangle r); virtual void setShape(float x, float y, float w, float h); + + void setShowHeader(bool show); + void setDistributeEvenly(bool distribute); + + void setExclusiveToggles(bool exclusive); + bool setActiveToggle(int index); + bool setActiveToggle(ofxToggle* toggle); + ofParameter& getActiveToggleIndex(); + protected: virtual void render(); virtual void generateDraw(); @@ -138,8 +165,8 @@ class ofxGuiGroup : public ofxBaseGui { virtual void add(ofxGuiGroup * element); template ControlType & getControlType(const std::string& name); - void setWidthElements(float w); - void addParametersFrom(const ofParameterGroup & parameters); + virtual void setWidthElements(float w); + void addParametersFrom(const ofParameterGroup & parameters, const Config &config = ofxBaseGui::Config()); float spacing, spacingNextElement, spacingFirstElement; float header; @@ -149,7 +176,15 @@ class ofxGuiGroup : public ofxBaseGui { std::string filename; bool minimized; + bool bShowHeader; + bool bExclusiveToggles; bool bGuiActive; + bool bDistributeEvenly; + + ofParameter active_toggle_index; + bool processToggles(ofxToggle *toggle, ofMouseEventArgs a); + void setOneToggleActive(); + void deactivateAllOtherToggles(ofxToggle* toggle); ofPath border, headerBg; ofVboMesh textMesh; @@ -173,13 +208,8 @@ ControlType & ofxGuiGroup::getControlType(const std::string& name){ } template -void ofxGuiGroup::add(ofParameter & parameter, const C & config){ - add(parameter, config); -} - -template -void ofxGuiGroup::add(ofParameter & parameter, const C & config){ - add(parameter, config); +void ofxGuiGroup::add(ofParameter & parameter, const C & config){ + add(parameter, config); } template @@ -193,43 +223,40 @@ void ofxGuiGroup::add(ofParameter & parameter, const C & config){ } template -void ofxGuiGroup::add(ofParameter p, const C & config){ +void ofxGuiGroup::add(ofParameter &p, const C & config){ auto inContainerConfig = config; inContainerConfig.inContainer = true; - inContainerConfig.layout = this->layout; +// inContainerConfig.layout = this->layout; addOwned(new GuiType(p,inContainerConfig)); } -template -void ofxGuiGroup::add(ofParameterGroup p, const C & config){ - auto inContainerConfig = config; +template +void ofxGuiGroup::add(ofParameterGroup p, const CGroup & groupConfig, const CItem & itemConfig){ + auto inContainerConfig = groupConfig; inContainerConfig.inContainer = true; - inContainerConfig.layout = this->layout; - addOwned(new GuiType(p,inContainerConfig)); + addOwned(new GuiType(p,inContainerConfig, itemConfig)); } template void ofxGuiGroup::add(const C & config){ auto inContainerConfig = config; inContainerConfig.inContainer = true; - inContainerConfig.layout = this->layout; addOwned(new GuiType(inContainerConfig)); } template void ofxGuiGroup::add(){ - auto inContainerConfig = config; + typename GuiType::Config inContainerConfig; inContainerConfig.inContainer = true; - inContainerConfig.layout = this->layout; addOwned(new GuiType(inContainerConfig)); } template void ofxGuiGroup::add(ofParameter p){ - add(p,this->config); + add(p,typename GuiType::Config()); } template void ofxGuiGroup::add(ofParameterGroup p){ - add(p,this->config); + add(p,typename GuiType::Config()); } diff --git a/addons/ofxGui/src/ofxGuiMatrix.cpp b/addons/ofxGui/src/ofxGuiMatrix.cpp new file mode 100644 index 00000000000..bf006343cb1 --- /dev/null +++ b/addons/ofxGui/src/ofxGuiMatrix.cpp @@ -0,0 +1,157 @@ +#include "ofxGuiMatrix.h" +#include "ofGraphics.h" +using namespace std; + +ofxGuiMatrix::ofxGuiMatrix() : + ofxGuiGroup() + ,numCol(Config().columnCount) + ,w_matrix(Config().shape.width) + ,w_element(0) + ,h_element(Config().rowHeight){ + sizeChangedCB(); + setNeedsRedraw(); +} + +ofxGuiMatrix::ofxGuiMatrix(const ofParameterGroup & parameters, const Config & groupConfig, const Config &itemConfig) : + ofxGuiGroup(parameters, groupConfig, itemConfig) + ,numCol(groupConfig.columnCount) + ,w_matrix(groupConfig.shape.width) + ,w_element(0) + ,h_element(groupConfig.rowHeight){ + sizeChangedCB(); + setNeedsRedraw(); +} + +ofxGuiMatrix & ofxGuiMatrix::setup(const ofParameterGroup & parameters, const Config & groupConfig, const Config & itemConfig){ + ofxGuiGroup::setup(parameters, groupConfig, itemConfig); + setColNum(groupConfig.columnCount); + setElementHeight(groupConfig.rowHeight); + w_matrix = b.width; + sizeChangedCB(); + return *this; +} + +ofxGuiMatrix & ofxGuiMatrix::setup(const std::string & collectionName, const Config & config){ + ofxGuiGroup::setup(collectionName, config); + setColNum(config.columnCount); + setElementHeight(config.rowHeight); + w_matrix = b.width; + sizeChangedCB(); + return *this; +} + +ofxGuiMatrix & ofxGuiMatrix::setup(const std::string & collectionName, int cols, const std::string & filename, float x, float y){ + setColNum(cols); + ofxGuiGroup::setup(collectionName, filename, x, y); + w_matrix = b.width; + sizeChangedCB(); + return *this; +} + +ofxGuiMatrix & ofxGuiMatrix::setup(const ofParameterGroup & _parameters, int cols, const std::string & filename, float x, float y){ + setColNum(cols); + ofxGuiGroup::setup(_parameters, filename, x, y); + w_matrix = b.width; + return *this; +} + +void ofxGuiMatrix::add(ofxBaseGui * element){ + collection.push_back(element); + + element->unregisterMouseEvents(); + + parameters.add(element->getParameter()); + sizeChangedCB(); +} + +void ofxGuiMatrix::setWidthElements(float w){ + if((int)b.width != (int)w){ + scaleWidthElements(w / b.width); + } +} + +void ofxGuiMatrix::scaleWidthElements(float factor){ + + w_matrix = this->b.getWidth() * factor; + + sizeChangedCB(); + setNeedsRedraw(); + +} + +void ofxGuiMatrix::maximize(){ + minimized = false; + b.height += (h_element + spacing) * getRowNum(); + ofNotifyEvent(sizeChangedE, this); + setNeedsRedraw(); +} + +void ofxGuiMatrix::sizeChangedCB(){ + updateElementWidth(); + float x, y; + x = b.x; + y = b.y + spacing + spacingFirstElement; + if(bShowHeader){ + y += header; + } + + x += b.width - w_matrix; + + for(unsigned int i = 0; i < collection.size(); i++){ + int x_e = i; + if(numCol > 0){ + x_e = x_e % numCol; + } + int y_e = 0; + if(numCol > 0){ + y_e = (int)(i / numCol); + } + + collection[i]->sizeChangedE.disable(); + collection[i]->setSize(w_element, h_element); + collection[i]->sizeChangedE.enable(); + + if(i == 0){ + collection[i]->setPosition(x, y); + }else{ + ofRectangle first_shape = collection[0]->getShape(); + collection[i]->setPosition(first_shape.x + (w_element + spacing) * x_e, first_shape.y + (h_element + spacing) * y_e); + } + + } + + b.height = y + (h_element + spacing) * getRowNum() + spacing - b.y; + + ofNotifyEvent(sizeChangedE,this); + setNeedsRedraw(); +} + +void ofxGuiMatrix::updateElementWidth(){ + w_element = w_matrix / numCol - spacing; +} + +void ofxGuiMatrix::setColNum(int num){ + numCol = num; +} + +int ofxGuiMatrix::getColNum(){ + return numCol; +} + +int ofxGuiMatrix::getRowNum(){ + if(collection.size() > 0){ + if(numCol == 0){ + return 1; + }else{ + return (int)((collection.size() - 1) / numCol + 1); + } + }else{ + return 0; + } + +} + +void ofxGuiMatrix::setElementHeight(float h){ + h_element = h; +} + diff --git a/addons/ofxGui/src/ofxGuiMatrix.h b/addons/ofxGui/src/ofxGuiMatrix.h new file mode 100644 index 00000000000..0cd62557196 --- /dev/null +++ b/addons/ofxGui/src/ofxGuiMatrix.h @@ -0,0 +1,51 @@ +#pragma once +#include "ofxGuiGroup.h" + +class ofxGuiMatrix : public ofxGuiGroup { + public: + struct Config : public ofxGuiGroup::Config { + Config(){ + } + Config(const ofxGuiGroup::Config & c) : ofxGuiGroup::Config(c){ + } + Config(const ofxBaseGui::Config & c) : ofxGuiGroup::Config(c){ + } + + int columnCount = 0; + float rowHeight = 20; + }; + + ofxGuiMatrix(); + ofxGuiMatrix(const ofParameterGroup & parameters, const Config & groupConfig = ofxGuiMatrix::Config(), const Config &itemConfig = ofxBaseGui::Config()); + virtual ~ofxGuiMatrix(){ + } + virtual ofxGuiMatrix & setup(const ofParameterGroup & parameters, const Config & groupConfig = ofxGuiMatrix::Config(), const Config &itemConfig = ofxBaseGui::Config()); + virtual ofxGuiMatrix & setup(const std::string & collectionName, const Config & config = ofxGuiMatrix::Config()); + virtual ofxGuiMatrix & setup(const std::string & collectionName = "", int cols = 0, const std::string & filename = "settings.xml", float x = 10, float y = 10); + virtual ofxGuiMatrix & setup(const ofParameterGroup & parameters, int cols = 0, const std::string & filename = "settings.xml", float x = 10, float y = 10); + + using ofxGuiGroup::add; + + void maximize(); + + virtual void setWidthElements(float w); + virtual void scaleWidthElements(float factor); + + void setColNum(int num); + int getColNum(); + int getRowNum(); + + float getElementWidth(); + float getElementHeight(); + + void setElementHeight(float h); + + protected: + virtual void add(ofxBaseGui * element); + void updateElementWidth(); + virtual void sizeChangedCB(); + + int numCol; + float w_matrix, w_element, h_element; + +}; diff --git a/addons/ofxGui/src/ofxGuiPage.cpp b/addons/ofxGui/src/ofxGuiPage.cpp new file mode 100644 index 00000000000..94d6763383d --- /dev/null +++ b/addons/ofxGui/src/ofxGuiPage.cpp @@ -0,0 +1,90 @@ +#include "ofxGuiPage.h" +#include "ofGraphics.h" +using namespace std; + +ofxGuiPage::ofxGuiPage() : ofxPanel(){ +} + +ofxGuiPage::~ofxGuiPage(){ + for(auto e: collection){ + ofRemoveListener(e->sizeChangedE,this,&ofxGuiPage::sizeChangedCB); + } +} + +void ofxGuiPage::add(ofxBaseGui * element){ + collection.push_back(element); + + ofPoint newpos = element->getPosition() + this->getPosition(); + if(bShowHeader){ + newpos.y += header + spacing; + } + element->setPosition(newpos); + b.width = max(element->getShape().getRight() - b.x + 1, b.width); + b.height = max(element->getShape().getBottom() - b.y + 1, b.height); + element->unregisterMouseEvents(); + ofAddListener(element->sizeChangedE, this, &ofxGuiPage::sizeChangedCB); + + parameters.add(element->getParameter()); + setNeedsRedraw(); +} + +bool ofxGuiPage::mouseDragged(ofMouseEventArgs & args){ + if(setValue(args.x, args.y, false)){ + return true; + } + if(bGuiActive){ + ofMouseEventArgs a = args; + for(auto & e: collection){ + if(e->mouseDragged(a)){ + //collection is only allowed to be moved within page boundaries + float tmp_header = 0; + if(bShowHeader){ + tmp_header += header + spacing; + } + ofPoint pos = e->getPosition(); + if(e->getShape().getLeft() < b.getLeft()){ + pos.x = b.getLeft(); + }else { + if(e->getShape().getRight() > b.getRight()-1){ + pos.x = b.getRight()-1 - e->getWidth(); + } + } + if(e->getShape().getTop() < b.getTop()+tmp_header){ + pos.y = b.getTop()+tmp_header; + }else { + if(e->getShape().getBottom() > b.getBottom()-1){ + pos.y = b.getBottom()-1 - e->getHeight(); + } + } + e->setPosition(pos); + return true; + } + } + } + return false; +} + +void ofxGuiPage::setWidthElements(float w){ +} + +void ofxGuiPage::scaleWidthElements(float factor){ +} + +void ofxGuiPage::clear(){ + collection.clear(); + parameters.clear(); + b.height = spacing + spacingNextElement; + if(bShowHeader){ + b.height += header; + } + sizeChangedCB(); +} + +void ofxGuiPage::sizeChangedCB(){ + for(auto & e : collection){ + b.width = max(e->getShape().getRight() - b.x + 1, b.width); + b.height = max(e->getShape().getBottom() - b.y + 1, b.height); + } + sizeChangedE.notify(this); + setNeedsRedraw(); +} diff --git a/addons/ofxGui/src/ofxGuiPage.h b/addons/ofxGui/src/ofxGuiPage.h new file mode 100644 index 00000000000..2e89aa04b96 --- /dev/null +++ b/addons/ofxGui/src/ofxGuiPage.h @@ -0,0 +1,24 @@ +#pragma once +#include "ofxPanel.h" + +class ofxGuiPage : public ofxPanel { + + public: + + ofxGuiPage(); + virtual ~ofxGuiPage(); + + using ofxPanel::add; + + void clear(); + + virtual bool mouseDragged(ofMouseEventArgs & args); + + virtual void setWidthElements(float w); + virtual void scaleWidthElements(float factor); + + protected: + virtual void add(ofxBaseGui * element); + virtual void sizeChangedCB(); + +}; diff --git a/addons/ofxGui/src/ofxGuiSpacer.cpp b/addons/ofxGui/src/ofxGuiSpacer.cpp new file mode 100644 index 00000000000..bdab81f0934 --- /dev/null +++ b/addons/ofxGui/src/ofxGuiSpacer.cpp @@ -0,0 +1,37 @@ +#include "ofxGuiSpacer.h" +#include "ofGraphics.h" +using namespace std; + +ofxGuiSpacer::ofxGuiSpacer(const Config & config) : + ofxBaseGui(config){ +} + +ofxGuiSpacer & ofxGuiSpacer::setup(float size, float x, float y){ + return setup("", size, x, y); +} + +ofxGuiSpacer & ofxGuiSpacer::setup(string name, float size, float x, float y){ + this->setName(name); + this->setPosition(x, y); + spacing_size = size; + return *this; +} + +void ofxGuiSpacer::generateDraw(){ + bg.clear(); + bg.setFillColor(thisBackgroundColor); + bg.setFilled(true); + bg.rectangle(b.x, b.y, b.width, b.height); +} + +void ofxGuiSpacer::render(){ + bg.draw(); +} + +void ofxGuiSpacer::sizeChangedCB(){ + setNeedsRedraw(); +} + +ofAbstractParameter & ofxGuiSpacer::getParameter(){ + return parameter; +} diff --git a/addons/ofxGui/src/ofxGuiSpacer.h b/addons/ofxGui/src/ofxGuiSpacer.h new file mode 100644 index 00000000000..ae9ec1991e4 --- /dev/null +++ b/addons/ofxGui/src/ofxGuiSpacer.h @@ -0,0 +1,56 @@ +#pragma once + +#include "ofxBaseGui.h" + +class ofxGuiSpacer : public ofxBaseGui { + public: + struct Config : public ofxBaseGui::Config { + Config(){ + this->backgroundColor = ofColor(0, 0, 0, 0); + } + Config(const ofxBaseGui::Config & c) : ofxBaseGui::Config(c){ + this->backgroundColor = ofColor(0, 0, 0, 0); + } + }; + + ofxGuiSpacer(const Config & config = Config()); + + virtual ~ofxGuiSpacer(){ + } + virtual ofxGuiSpacer & setup(float size, float x, float y); + virtual ofxGuiSpacer & setup(string name, float size, float x, float y); + + virtual ofAbstractParameter & getParameter(); + + virtual bool mouseMoved(ofMouseEventArgs & args){ + return false; + } + virtual bool mousePressed(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseDragged(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseReleased(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseScrolled(ofMouseEventArgs & args){ + return false; + } + + protected: + virtual void render(); + virtual bool setValue(float mx, float my, bool bCheckBounds){ + return false; + } + virtual void generateDraw(); + + void sizeChangedCB(); + + ofPath bg; + float spacing_size; + + // not needed, but has be be there + ofParameter parameter; + +}; diff --git a/addons/ofxGui/src/ofxInputField.cpp b/addons/ofxGui/src/ofxInputField.cpp new file mode 100644 index 00000000000..8db4aa78d9a --- /dev/null +++ b/addons/ofxGui/src/ofxInputField.cpp @@ -0,0 +1,489 @@ +#include "ofxInputField.h" + +#include "ofGraphics.h" + +template +ofxInputField::ofxInputField(){ + bChangedInternally = false; + bGuiActive = false; + bMousePressed = false; + mouseInside = false; + bRegisteredForKeyEvents = false; + mousePressedPos = -1; + selectStartX = -1; + selectStartPos = -1; + selectEndPos = -1; + pressCounter = 0; + inputWidth = 0; + selectionWidth = 0; +} + +template +ofxInputField::~ofxInputField(){ + value.removeListener(this,&ofxInputField::valueChanged); +} + +template +ofxInputField::ofxInputField(ofParameter _val, const Config &config) + :ofxBaseGui(config) + ,bGuiActive(false) + ,mouseInside(false){ + + value.makeReferenceTo(_val); + value.addListener(this,&ofxInputField::valueChanged); + input = ofToString(value); + inputWidth = getTextBoundingBox(input,0,0).width; + setNeedsRedraw(); + registerMouseEvents(); + registerKeyEvents(); +} + + +template +ofxInputField & ofxInputField::setup(ofParameter _val, const Config &config){ + ofxBaseGui::setup(config); + value.makeReferenceTo(_val); + + input = ofToString(value); + inputWidth = getTextBoundingBox(input,0,0).width; + + bGuiActive = false; + setNeedsRedraw(); + + value.addListener(this,&ofxInputField::valueChanged); + registerMouseEvents(); + registerKeyEvents(); + pressCounter = 0; + return *this; +} + +template +ofxInputField & ofxInputField::setup(ofParameter _val, float width, float height){ + value.makeReferenceTo(_val); + input = ofToString(value); + inputWidth = getTextBoundingBox(input,0,0).width; + b.x = 0; + b.y = 0; + b.width = width; + b.height = height; + bGuiActive = false; + setNeedsRedraw(); + + value.addListener(this,&ofxInputField::valueChanged); + registerMouseEvents(); + registerKeyEvents(); + pressCounter = 0; + return *this; +} + +template +ofxInputField & ofxInputField::setup(const std::string& _name, Type _val, Type _min, Type _max, float width, float height){ + value.set(_name,_val,_min,_max); + return setup(value,width,height); +} + +template +void ofxInputField::setMin(Type min){ + value.setMin(min); +} + +template +Type ofxInputField::getMin(){ + return value.getMin(); +} + +template +void ofxInputField::setMax(Type max){ + value.setMax(max); +} + +template +Type ofxInputField::getMax(){ + return value.getMax(); +} + +template +void ofxInputField::calculateSelectionArea(int selectIdx1, int selectIdx2){ + std::string preSelectStr, selectStr; + + if(selectIdx1 <= selectIdx2){ + selectStartPos = selectIdx1; + selectEndPos = selectIdx2; + }else{ + selectStartPos = selectIdx2; + selectEndPos = selectIdx1; + } + + float preSelectWidth = 0; + if(selectStartPos > 0){ + preSelectStr.assign(input,0,selectStartPos); + preSelectWidth = getTextBoundingBox(preSelectStr,0,0).width; + } + selectStartX = b.width - textPadding - inputWidth + preSelectWidth; + + if(hasSelectedText()){ + selectStr.assign(input,selectStartPos,selectEndPos-selectStartPos); + selectionWidth = getTextBoundingBox(selectStr,0,0).width; + } +} + +template +bool ofxInputField::mouseMoved(ofMouseEventArgs & args){ + mouseInside = isGuiDrawing() && b.inside(ofPoint(args.x,args.y)); + return mouseInside; +} + +template +bool ofxInputField::mousePressed(ofMouseEventArgs & args){ + if(b.inside(args.x,args.y)){ + bMousePressed = true; + if(!bGuiActive){ + bGuiActive = true; + } + + float cursorX = args.x - (b.x + b.width - textPadding - inputWidth); + int cursorPos = ofMap(cursorX,0,inputWidth,0,input.size(),true); + mousePressedPos = cursorPos; + + calculateSelectionArea(cursorPos, cursorPos); + + pressCounter++; + + }else{ + if(bGuiActive){ + leaveFocus(); + } + } + return false; +} + +template +bool ofxInputField::mouseDragged(ofMouseEventArgs & args){ + if(!bGuiActive || !bMousePressed) + return false; + + float cursorX = args.x - (b.x + b.width - textPadding - inputWidth); + int cursorPos = ofMap(cursorX,0,inputWidth,0,input.size(),true); + calculateSelectionArea(mousePressedPos,cursorPos); + return false; +} + +template +bool ofxInputField::mouseReleased(ofMouseEventArgs & args){ + // if(bUpdateOnEnterOnly){ //TODO not implemented yet + // value.enableEvents(); + // } + + if(bGuiActive){ + if(pressCounter == 1 && !hasSelectedText()){ + //activated panel without selecting an area => select all + calculateSelectionArea(0, input.size()); + } + } + + bMousePressed = false; + return false; +} + +template +void ofxInputField::registerKeyEvents(){ + if(bRegisteredForKeyEvents == true){ + return; // already registered. + } + bRegisteredForKeyEvents = true; + ofRegisterKeyEvents(this, OF_EVENT_ORDER_BEFORE_APP); +} + +template +void ofxInputField::unregisterKeyEvents(){ + if(bRegisteredForKeyEvents == false){ + return; // not registered. + } + ofUnregisterKeyEvents(this, OF_EVENT_ORDER_BEFORE_APP); + bRegisteredForKeyEvents = false; +} + +template +bool ofxInputField::keyPressed(ofKeyEventArgs & args){ + if(bGuiActive && !bMousePressed){ + + int newCursorIdx = -1; + if(args.key >= '0' && args.key <= '9'){ + int digit = args.key - '0'; + newCursorIdx = insertKeystroke(ofToString(digit)); + }else if(args.key == '.' ){ + newCursorIdx = insertKeystroke("."); + }else if(args.key == OF_KEY_BACKSPACE || args.key == OF_KEY_DEL){ + if(hasSelectedText()){ + input.erase(selectStartPos,selectEndPos-selectStartPos); + newCursorIdx = selectStartPos; + parseInput(); + }else{ + int deleteIdx = -1; + if(args.key == OF_KEY_BACKSPACE){ + deleteIdx = selectStartPos-1; + }else if(args.key == OF_KEY_DEL){ + deleteIdx = selectStartPos; + } + + //erase char if valid deleteIdx + if(deleteIdx >= 0 && deleteIdx < input.size()){ + input.erase(deleteIdx,1); + newCursorIdx = deleteIdx; + parseInput(); + } + } + }else if(args.key == OF_KEY_LEFT){ + if(hasSelectedText()){ + newCursorIdx = selectStartPos; + }else{ + newCursorIdx = selectStartPos == 0 ? 0 : selectStartPos-1; + } + }else if(args.key == OF_KEY_RIGHT){ + if(hasSelectedText()){ + newCursorIdx = selectEndPos; + }else{ + newCursorIdx = selectStartPos == input.size() ? input.size() : selectStartPos+1; + } + }else if(args.key == OF_KEY_RETURN){ + leaveFocus(); + }else if(args.key >= '!' && args.key <= '~'){ + newCursorIdx = insertAlphabetic(ofToString((char)args.key)); + } + + if(newCursorIdx != -1){ + //set cursor + calculateSelectionArea(newCursorIdx,newCursorIdx); + } + return true; + } + return false; +} + +template +bool ofxInputField::keyReleased(ofKeyEventArgs & args){ + return bGuiActive && !bMousePressed; +} + + +template +int ofxInputField::insertKeystroke(const std::string & character){ + if(hasSelectedText()){ + input.erase(selectStartPos,selectEndPos-selectStartPos); + } + input.insert(selectStartPos,character); + parseInput(); + return selectStartPos + 1; +} + +template +int ofxInputField::insertAlphabetic(const std::string &){ + return -1; //do nothing for numeric types, cursor/selection area stays the same +} + +template<> +int ofxInputField::insertAlphabetic(const std::string & character){ + return insertKeystroke(character); +} + + +template +typename std::enable_if::value, Type>::type +getRange(Type min, Type max, float width){ + double range = max - min; + range /= width*4; + return std::max(range,1.0); +} + +template +typename std::enable_if::value, Type>::type +getRange(Type min, Type max, float width){ + double range = max - min; + range /= width*4; + return range; +} + +template +bool ofxInputField::mouseScrolled(ofMouseEventArgs & args){ + if(mouseInside || bGuiActive){ + if(args.y>0 || args.y<0){ + double range = getRange(value.getMin(),value.getMax(),b.width); + Type newValue = value + ofMap(args.y,-1,1,-range, range); + newValue = ofClamp(newValue,value.getMin(),value.getMax()); + value = newValue; + } + return true; + }else{ + return false; + } +} + +template<> +bool ofxInputField::mouseScrolled(ofMouseEventArgs & args){ + if(mouseInside || bGuiActive){ + return true; + }else{ + return false; + } +} + +template +Type ofxInputField::operator=(Type v){ + value = v; + return v; +} + +template +ofxInputField::operator const Type & (){ + return value; +} + +template +void ofxInputField::generateDraw(){ + bg.clear(); + + bg.setFillColor(thisBackgroundColor); + bg.setFilled(true); + bg.rectangle(b); + + generateText(); +} + + +template +void ofxInputField::generateText(){ + string valStr = input; + textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); + textMesh.append(getTextMesh(valStr, b.x + b.width - textPadding - getTextBoundingBox(valStr,0,0).width, b.y + b.height / 2 + 4)); +} + +template +void ofxInputField::render(){ + bg.draw(); + + if(bGuiActive){ + drawFocusedBB(); + + if(hasSelectedText()){ + drawSelectedArea(); + }else{ + drawCursor(); + } + } + + drawMesh(); +} + +template +bool ofxInputField::hasSelectedText(){ + return selectStartPos != selectEndPos; +} + +template +void ofxInputField::drawMesh(){ + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(thisTextColor); + + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); + + ofColor c = ofGetStyle().color; + ofSetColor(c); + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } +} + +template +void ofxInputField::drawSelectedArea(){ + ofPushStyle(); + ofSetColor(thisFillColor); + ofFill(); + ofDrawRectangle( selectStartX+b.x, b.y+1, selectionWidth, b.height-2 ); + ofPopStyle(); +} + +template +void ofxInputField::drawCursor(){ + ofPushStyle(); + ofSetColor(thisTextColor); + ofDrawLine( selectStartX+b.x, b.y, selectStartX+b.x, b.y+b.height ); + ofPopStyle(); +} + +template +void ofxInputField::drawFocusedBB(){ + ofPushStyle(); + ofSetColor(thisTextColor); + ofDrawLine( selectStartX+b.x, b.y, selectStartX+b.x, b.y+b.height ); + ofPopStyle(); +} + +template +bool ofxInputField::setValue(float mx, float my, bool bCheck){ + return false; +} + +template +ofAbstractParameter & ofxInputField::getParameter(){ + return value; +} + +template +void ofxInputField::parseInput(){ + bChangedInternally = true; + Type tmpVal = ofToFloat(input); + if(tmpVal < getMin()){ + tmpVal = getMin(); + }else if(tmpVal > getMax()){ + tmpVal = getMax(); + } + value = tmpVal; +} + +template<> +void ofxInputField::parseInput(){ + bChangedInternally = true; + value = input; +} + +template +void ofxInputField::valueChanged(Type & value){ + if(bChangedInternally){ + bChangedInternally = false; + inputWidth = getTextBoundingBox(input,0,0).width; + }else{ + input = ofToString(value); + inputWidth = getTextBoundingBox(input,0,0).width; + if(bGuiActive){ + int cursorPos = input.size(); + calculateSelectionArea(cursorPos,cursorPos); + } + } + setNeedsRedraw(); +} + +template +void ofxInputField::leaveFocus(){ + bGuiActive = false; + pressCounter = 0; + input = ofToString(value); + inputWidth = getTextBoundingBox(input,0,0).width; + setNeedsRedraw(); +} + +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; +template class ofxInputField; diff --git a/addons/ofxGui/src/ofxInputField.h b/addons/ofxGui/src/ofxInputField.h new file mode 100644 index 00000000000..a266244ea95 --- /dev/null +++ b/addons/ofxGui/src/ofxInputField.h @@ -0,0 +1,88 @@ +#pragma once + +#include "ofxBaseGui.h" + +template +class ofxInputField : public ofxBaseGui{ +public: + ofxInputField(); + ~ofxInputField(); + ofxInputField(ofParameter _val, const Config & config = Config()); + ofxInputField & setup(ofParameter _val, const Config & config); + ofxInputField & setup(ofParameter _val, float width = defaultWidth, float height = defaultHeight); + ofxInputField & setup(const std::string& _name, Type _val, Type _min, Type _max, float width = defaultWidth, float height = defaultHeight); + //TODO the setup non-ofParameter setup is a pain for the Type string (because of the forced min and max) + + void setMin(Type min); + Type getMin(); + void setMax(Type max); + Type getMax(); + + virtual bool mouseMoved(ofMouseEventArgs & args); + virtual bool mousePressed(ofMouseEventArgs & args); + virtual bool mouseDragged(ofMouseEventArgs & args); + virtual bool mouseReleased(ofMouseEventArgs & args); + virtual bool mouseScrolled(ofMouseEventArgs & args); + + void registerKeyEvents(); + void unregisterKeyEvents(); + + virtual bool keyPressed(ofKeyEventArgs & args); + virtual bool keyReleased(ofKeyEventArgs & args); + + template + void addListener(ListenerClass * listener, ListenerMethod method){ + value.addListener(listener,method); + } + + template + void removeListener(ListenerClass * listener, ListenerMethod method){ + value.removeListener(listener,method); + } + + Type operator=(Type v); + operator const Type & (); + + ofAbstractParameter & getParameter(); + +protected: + virtual void render(); + ofParameter value; + bool bGuiActive, bMousePressed; + bool mouseInside; + bool setValue(float mx, float my, bool bCheck); + virtual void generateDraw(); + virtual void generateText(); + void valueChanged(Type & value); + ofPath bg; + ofVboMesh textMesh; + + bool bRegisteredForKeyEvents; + + std::string input; + float inputWidth; + bool bChangedInternally; + void parseInput(); + int insertKeystroke(const std::string & character); + int insertAlphabetic(const std::string & character); + + int mousePressedPos; //set by mouse interaction + bool hasSelectedText(); + + float selectStartX, selectionWidth; //calculated from select indices + int selectStartPos, selectEndPos; + void calculateSelectionArea(int selectIdx1, int selectIdx2); + + virtual void drawSelectedArea(); + virtual void drawCursor(); + virtual void drawFocusedBB(); + virtual void drawMesh(); + + int pressCounter; + + void leaveFocus(); +}; + +typedef ofxInputField ofxFloatInputField; +typedef ofxInputField ofxIntInputField; +typedef ofxInputField ofxTextField; diff --git a/addons/ofxGui/src/ofxLabel.cpp b/addons/ofxGui/src/ofxLabel.cpp index e9fcbeef3d0..fd99c732574 100644 --- a/addons/ofxGui/src/ofxLabel.cpp +++ b/addons/ofxGui/src/ofxLabel.cpp @@ -2,57 +2,74 @@ #include "ofGraphics.h" using namespace std; -ofxLabel::ofxLabel() +template +ofxValueLabel::ofxValueLabel() :ofxBaseGui(Config()){ } -ofxLabel::ofxLabel(ofParameter _label, const Config & config) +template +ofxValueLabel::ofxValueLabel(ofParameter _label, const Config & config) :ofxBaseGui(config){ - label.makeReferenceTo(_label); - setNeedsRedraw(); - label.addListener(this,&ofxLabel::valueChanged); + label.makeReferenceTo(_label); + setNeedsRedraw(); + label.addListener(this,&ofxValueLabel::valueChanged); } -ofxLabel::ofxLabel(ofParameter _label, float width, float height) -:ofxBaseGui(Config()){ - setup(_label,width,height); +template +ofxValueLabel::~ofxValueLabel(){ + label.removeListener(this,&ofxValueLabel::valueChanged); +} + +template +ofxValueLabel & ofxValueLabel::setup(ofParameter _label, const Config & config){ + ofxBaseGui::setup(config); + return setup(_label, config.shape.width, config.shape.height); } -ofxLabel::~ofxLabel(){ - label.removeListener(this,&ofxLabel::valueChanged); +template +ofxValueLabel & ofxValueLabel::setup(ofParameter _label, float width, float height) { + label.makeReferenceTo(_label); + b.width = width; + b.height = height; + setNeedsRedraw(); + label.addListener(this,&ofxValueLabel::valueChanged); + return *this; } -ofxLabel & ofxLabel::setup(ofParameter _label, float width, float height) { - label.makeReferenceTo(_label); - b.width = width; - b.height = height; - setNeedsRedraw(); - label.addListener(this,&ofxLabel::valueChanged); - return *this; +template +ofxValueLabel & ofxValueLabel::setup(const string& labelName, const Type& _label, const Config & config) { + label.set(labelName,_label); + return setup(label,config); } -ofxLabel & ofxLabel::setup(const std::string& labelName, string _label, float width, float height) { - label.set(labelName,_label); - return setup(label,width,height); +template +ofxValueLabel & ofxValueLabel::setup(const string& labelName, const Type& _label, float width, float height) { + label.set(labelName,_label); + return setup(label,width,height); } -void ofxLabel::generateDraw(){ +template +void ofxValueLabel::generateDraw(){ bg.clear(); bg.setFillColor(thisBackgroundColor); bg.setFilled(true); bg.rectangle(b); - string name; - if(!getName().empty()){ - name = getName() + ": "; - } - - textMesh = getTextMesh(name + (string)label, b.x + textPadding, b.y + b.height / 2 + 4); + if(bShowName){ + string name; + if(!getName().empty()){ + name = getName() + ": "; + } + textMesh = getTextMesh(name + label.toString(), b.x + textPadding, b.y + b.height / 2 + 4); + }else { + textMesh = getTextMesh(label.toString(), b.x + textPadding, b.y + b.height / 2 + 4); + } } -void ofxLabel::render() { +template +void ofxValueLabel::render() { ofColor c = ofGetStyle().color; bg.draw(); @@ -61,22 +78,29 @@ void ofxLabel::render() { if(blendMode!=OF_BLENDMODE_ALPHA){ ofEnableAlphaBlending(); } - ofSetColor(textColor); + ofSetColor(thisTextColor); - bindFontTexture(); - textMesh.draw(); - unbindFontTexture(); + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); - ofSetColor(c); + ofSetColor(c); if(blendMode!=OF_BLENDMODE_ALPHA){ ofEnableBlendMode(blendMode); } } -ofAbstractParameter & ofxLabel::getParameter(){ +template +ofAbstractParameter & ofxValueLabel::getParameter(){ return label; } -void ofxLabel::valueChanged(string & value){ - setNeedsRedraw(); +template +void ofxValueLabel::valueChanged(Type & value){ + setNeedsRedraw(); } + +template class ofxValueLabel; +template class ofxValueLabel; +template class ofxValueLabel; +template class ofxValueLabel; diff --git a/addons/ofxGui/src/ofxLabel.h b/addons/ofxGui/src/ofxLabel.h index 62a0552b42f..6b71bab0ec1 100644 --- a/addons/ofxGui/src/ofxLabel.h +++ b/addons/ofxGui/src/ofxLabel.h @@ -3,7 +3,8 @@ #include "ofxBaseGui.h" #include "ofParameter.h" -class ofxLabel: public ofxBaseGui { +template +class ofxValueLabel: public ofxBaseGui { public: struct Config: public ofxBaseGui::Config{ Config(){} @@ -11,23 +12,25 @@ class ofxLabel: public ofxBaseGui { :ofxBaseGui::Config(c){} }; - ofxLabel(); - ofxLabel(ofParameter _label, const Config & config = Config()); - ofxLabel(ofParameter _label, float width, float height = defaultHeight); - virtual ~ofxLabel(); + ofxValueLabel(); - ofxLabel & setup(ofParameter _label, float width = defaultWidth, float height = defaultHeight); - ofxLabel & setup(const std::string& labelName, std::string label, float width = defaultWidth, float height = defaultHeight); + ofxValueLabel(ofParameter _label, const Config & config = Config()); + virtual ~ofxValueLabel(); - // Abstract methods we must implement, but have no need for! - virtual bool mouseMoved(ofMouseEventArgs & args){return false;} - virtual bool mousePressed(ofMouseEventArgs & args){return false;} - virtual bool mouseDragged(ofMouseEventArgs & args){return false;} - virtual bool mouseReleased(ofMouseEventArgs & args){return false;} - virtual bool mouseScrolled(ofMouseEventArgs & args){return false;} + ofxValueLabel & setup(ofParameter _label, const Config & config); + ofxValueLabel & setup(ofParameter _label, float width = defaultWidth, float height = defaultHeight); + ofxValueLabel & setup(const std::string& labelName, const Type & label, const Config & config); + ofxValueLabel & setup(const std::string& labelName, const Type & label, float width = defaultWidth, float height = defaultHeight); - virtual void saveTo(ofBaseSerializer& serializer){}; - virtual void loadFrom(ofBaseSerializer& serializer){}; + // Abstract methods we must implement, but have no need for! + virtual bool mouseMoved(ofMouseEventArgs & args){return false;} + virtual bool mousePressed(ofMouseEventArgs & args){return false;} + virtual bool mouseDragged(ofMouseEventArgs & args){return false;} + virtual bool mouseReleased(ofMouseEventArgs & args){return false;} + virtual bool mouseScrolled(ofMouseEventArgs & args){return false;} + + virtual void saveTo(ofBaseSerializer& serializer){} + virtual void loadFrom(ofBaseSerializer& serializer){} template @@ -41,17 +44,22 @@ class ofxLabel: public ofxBaseGui { } - std::string operator=(std::string v) { label = v; return v; } - operator const std::string & () { return label; } + Type operator=(Type v) { label = v; return v; } + operator const Type & () { return label; } - ofAbstractParameter & getParameter(); + ofAbstractParameter & getParameter(); protected: - void render(); - ofParameter label; - void generateDraw(); - void valueChanged(std::string & value); - bool setValue(float mx, float my, bool bCheckBounds){return false;} - ofPath bg; - ofVboMesh textMesh; + void render(); + ofParameter label; + void generateDraw(); + void valueChanged(Type & value); + bool setValue(float mx, float my, bool bCheckBounds){return false;} + ofPath bg; + ofVboMesh textMesh; }; + +typedef ofxValueLabel ofxLabel; +typedef ofxValueLabel ofxIntLabel; +typedef ofxValueLabel ofxFloatLabel; +typedef ofxValueLabel ofxBoolLabel; diff --git a/addons/ofxGui/src/ofxMinimalButton.cpp b/addons/ofxGui/src/ofxMinimalButton.cpp new file mode 100644 index 00000000000..4922515aa3a --- /dev/null +++ b/addons/ofxGui/src/ofxMinimalButton.cpp @@ -0,0 +1,69 @@ +#include "ofxMinimalButton.h" +#include "ofGraphics.h" +using namespace std; + +ofxMinimalButton::ofxMinimalButton(){} + +ofxMinimalButton::ofxMinimalButton(const Config & config) : + ofxMinimalToggle(value, config){ + value.setName(config.name); + value.set(false); + value.setSerializable(false); + registerMouseEvents(); + value.addListener(this, &ofxMinimalButton::valueChanged); +} +ofxMinimalButton::~ofxMinimalButton(){ + value.removeListener(this, &ofxMinimalButton::valueChanged); +} + +ofxMinimalButton & ofxMinimalButton::setup(const std::string& buttonName, const Config & config){ + setName(buttonName); + ofxBaseGui::setup(config); + if(b.width == 0){ + b.width = ofxBaseGui::getTextWidth(buttonName, b.height); + } + bGuiActive = false; + value = false; + checkboxRect.set(1, 1, b.width - 2, b.height - 2); + registerMouseEvents(); + value.addListener(this,&ofxMinimalButton::valueChanged); + + return *this; +} + +ofxMinimalButton & ofxMinimalButton::setup(const string & toggleName, float width, float height){ + if(width == 0){ + width = ofxBaseGui::getTextWidth(toggleName, height); + } + setName(toggleName); + b.x = 0; + b.y = 0; + b.width = width; + b.height = height; + bGuiActive = false; + value = false; + checkboxRect.set(1, 1, b.width - 2, b.height - 2); + + registerMouseEvents(); + + value.addListener(this, &ofxMinimalButton::valueChanged); + + return *this; +} + +bool ofxMinimalButton::mouseReleased(ofMouseEventArgs & args){ + bool attended = setValue(args.x, args.y, false); + bGuiActive = false; + if(attended){ + return true; + }else{ + return false; + } +} + +void ofxMinimalButton::valueChanged(bool & value){ + ofxMinimalToggle::valueChanged(value); + if(!value){ + ofNotifyEvent(triggerEvent, this); + } +} diff --git a/addons/ofxGui/src/ofxMinimalButton.h b/addons/ofxGui/src/ofxMinimalButton.h new file mode 100644 index 00000000000..469c200bd33 --- /dev/null +++ b/addons/ofxGui/src/ofxMinimalButton.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ofxMinimalToggle.h" +#include "ofParameter.h" + +class ofxMinimalButton : public ofxMinimalToggle { + + public: + struct Config : public ofxMinimalToggle::Config { + Config(){ + } + Config(const ofxMinimalToggle::Config & c) : ofxMinimalToggle::Config(c){ + } + Config(const ofxBaseGui::Config & c) : ofxMinimalToggle::Config(c){ + } + std::string name; + }; + + ofxMinimalButton(); + ofxMinimalButton(const Config & config); + ~ofxMinimalButton(); + ofxMinimalButton & setup(const std::string& buttonName, const Config & config); + ofxMinimalButton & setup(const std::string& buttonName, float width = defaultWidth, float height = defaultHeight); + + virtual bool mouseReleased(ofMouseEventArgs & args); + + template + void addListener(ListenerClass * listener, ListenerMethod method){ + ofAddListener(triggerEvent, listener, method); + } + + template + void removeListener(ListenerClass * listener, ListenerMethod method){ + ofRemoveListener(triggerEvent, listener, method); + } + + private: + + ofEvent triggerEvent; + void valueChanged(bool & v); + +}; diff --git a/addons/ofxGui/src/ofxMinimalToggle.cpp b/addons/ofxGui/src/ofxMinimalToggle.cpp new file mode 100644 index 00000000000..9dc2cf7bcea --- /dev/null +++ b/addons/ofxGui/src/ofxMinimalToggle.cpp @@ -0,0 +1,110 @@ +#include "ofxMinimalToggle.h" +#include "ofGraphics.h" +using namespace std; + +ofxMinimalToggle::ofxMinimalToggle() : + ofxToggle(){ + thisBorderColor = thisFillColor; +} + +ofxMinimalToggle::ofxMinimalToggle(ofParameter &val, const Config & config) +:ofxToggle(val,config){ + if(b.width == 0) { + b.width = ofxBaseGui::getTextWidth(val.getName(), config.shape.height); + } +} + +ofxMinimalToggle::~ofxMinimalToggle(){ +} + +ofxMinimalToggle & ofxMinimalToggle::setup(ofParameter &val, const Config & config){ + ofxToggle::setup(val, config); + thisBorderColor = thisFillColor; + if(b.width == 0) { + b.width = ofxBaseGui::getTextWidth(val.getName(), config.shape.height); + } + return *this; +} + +ofxMinimalToggle & ofxMinimalToggle::setup(ofParameter &val, float width, float height){ + ofxToggle::setup(val,width,height); + if(b.width == 0){ + b.width = ofxBaseGui::getTextWidth(val.getName(), height); + } + + return *this; + +} + +ofxMinimalToggle & ofxMinimalToggle::setup(const string & toggleName, bool val, float width, float height){ + value.set(toggleName, val); + return setup(value, width, height); +} + +void ofxMinimalToggle::generateDraw(){ + checkboxRect.set(1, 1, b.width - 2, b.height - 2); + + bg.clear(); + bg.setFillColor(thisBackgroundColor); + bg.rectangle(b.getPosition() + checkboxRect.getTopLeft()+ofPoint(1,1), checkboxRect.width-2, checkboxRect.height-2); + + fg.clear(); + fg.setFilled(true); + fg.setFillColor(thisFillColor); + fg.rectangle(b.getPosition() + checkboxRect.getTopLeft()+ofPoint(1,1), checkboxRect.width-2, checkboxRect.height-2); + + border.clear(); + border.setFilled(false); + border.setStrokeWidth(1); + border.setStrokeColor(thisBorderColor); + border.rectangle(b.getPosition() + checkboxRect.getTopLeft(), checkboxRect.width, checkboxRect.height); + + if(bShowName){ + float textWidth = ofxBaseGui::getTextWidth(getName(), b.height); + switch(textLayout){ + default: + case ofxBaseGui::Centered: + if(b.getCenter().x - textWidth/2 > b.x+textPadding){ + textMesh = getTextMesh(getName(), b.getCenter().x - textWidth/2, b.y + b.height / 2 + 4); + break; + } + case ofxBaseGui::Left: + textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); + break; + case ofxBaseGui::Right: + textMesh = getTextMesh(getName(), b.getRight() - textWidth - textPadding, b.y + b.height / 2 + 4); + break; + + } + + } +} + +void ofxMinimalToggle::render(){ + + bg.draw(); + if(value){ + fg.draw(); + } + border.draw(); + + if(bShowName){ + ofColor c = ofGetStyle().color; + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(thisTextColor); + + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); + + ofSetColor(c); + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } + } +} + + diff --git a/addons/ofxGui/src/ofxMinimalToggle.h b/addons/ofxGui/src/ofxMinimalToggle.h new file mode 100644 index 00000000000..9463fa0b706 --- /dev/null +++ b/addons/ofxGui/src/ofxMinimalToggle.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ofParameter.h" +#include "ofxToggle.h" + +class ofxMinimalToggle : public ofxToggle { + + public: + ofxMinimalToggle(); + virtual ~ofxMinimalToggle(); + ofxMinimalToggle(ofParameter &val, const Config & config = Config()); + + ofxMinimalToggle & setup(ofParameter &val, const Config & config = Config()); + ofxMinimalToggle & setup(ofParameter &val, float width = defaultWidth, float height = defaultHeight); + ofxMinimalToggle & setup(const std::string & toggleName, bool val, float width = defaultWidth, float height = defaultHeight); + + protected: + virtual void render(); + void generateDraw(); + + float getTextWidth(std::string text, float height); + + ofPath border; +}; + diff --git a/addons/ofxGui/src/ofxPanel.cpp b/addons/ofxGui/src/ofxPanel.cpp index e207f0f336d..dd907ffa29f 100644 --- a/addons/ofxGui/src/ofxPanel.cpp +++ b/addons/ofxGui/src/ofxPanel.cpp @@ -16,8 +16,8 @@ ofImage ofxPanel::saveIcon; ofxPanel::ofxPanel() :bGrabbed(false){} -ofxPanel::ofxPanel(const ofParameterGroup & parameters, const Config & config) -:ofxGuiGroup(parameters,config) +ofxPanel::ofxPanel(const ofParameterGroup & parameters, const Config & groupConfig, const Config &itemConfig) +:ofxGuiGroup(parameters,groupConfig,itemConfig) ,bGrabbed(false){ if(!loadIcon.isAllocated() || !saveIcon.isAllocated()){ loadIcons(); @@ -26,42 +26,43 @@ ofxPanel::ofxPanel(const ofParameterGroup & parameters, const Config & config) setNeedsRedraw(); } -ofxPanel::ofxPanel(const ofParameterGroup & parameters, const std::string& filename, float x, float y) -: ofxGuiGroup(parameters, filename, x, y) -, bGrabbed(false){ +ofxPanel::~ofxPanel(){ + // +} + +ofxPanel & ofxPanel::setup(const Config & config){ if(!loadIcon.isAllocated() || !saveIcon.isAllocated()){ loadIcons(); } - registerMouseEvents(); - setNeedsRedraw(); + return (ofxPanel&)ofxGuiGroup::setup(config); } -ofxPanel::~ofxPanel(){ - // +ofxPanel & ofxPanel::setup(const std::string& collectionName, const Config & config){ + setName(collectionName); + return setup(config); } -ofxPanel & ofxPanel::setup(const ofParameterGroup & parameters, const Config & config){ +ofxPanel & ofxPanel::setup(const ofParameterGroup & parameters, const Config & groupConfig, const Config &itemConfig){ if(!loadIcon.isAllocated() || !saveIcon.isAllocated()){ loadIcons(); } - registerMouseEvents(); - return (ofxPanel&)ofxGuiGroup::setup(parameters, config); + return (ofxPanel&)ofxGuiGroup::setup(parameters, groupConfig, itemConfig); } ofxPanel & ofxPanel::setup(const std::string& collectionName, const std::string& filename, float x, float y){ - if(!loadIcon.isAllocated() || !saveIcon.isAllocated()){ - loadIcons(); - } - registerMouseEvents(); - return (ofxPanel&)ofxGuiGroup::setup(collectionName,filename,x,y); + ofxPanel::Config config; + config.filename = filename; + config.shape.x = x; + config.shape.y = y; + return setup(collectionName, config); } ofxPanel & ofxPanel::setup(const ofParameterGroup & parameters, const std::string& filename, float x, float y){ - if(!loadIcon.isAllocated() || !saveIcon.isAllocated()){ - loadIcons(); - } - registerMouseEvents(); - return (ofxPanel&)ofxGuiGroup::setup(parameters,filename,x,y); + ofxPanel::Config config; + config.filename = filename; + config.shape.x = x; + config.shape.y = y; + return setup(parameters, config); } void ofxPanel::loadIcons(){ @@ -78,14 +79,18 @@ void ofxPanel::loadIcons(){ void ofxPanel::generateDraw(){ border.clear(); - border.setStrokeColor(thisBorderColor); - border.setStrokeWidth(1); - border.setFilled(false); - border.rectangle(b.x,b.y,b.width+1,b.height-spacingNextElement); + border.setFillColor(thisBorderColor); + border.setFilled(true); + border.rectangle(b.x,b.y,b.width+1,b.height); + if(bShowHeader){ + generateDrawHeader(); + } +} +void ofxPanel::generateDrawHeader(){ headerBg.clear(); - headerBg.setFillColor(ofColor(thisHeaderBackgroundColor,180)); + headerBg.setFillColor(thisHeaderBackgroundColor); headerBg.setFilled(true); headerBg.rectangle(b.x,b.y+1,b.width,header); @@ -100,30 +105,25 @@ void ofxPanel::generateDraw(){ saveBox.set(loadBox); saveBox.x += iconWidth + iconSpacing; - textMesh = getTextMesh(getName(), textPadding + b.x, header / 2 + 4 + b.y); + if(bShowName){ + textMesh = getTextMesh(getName(), textPadding + b.x, header / 2 + 4 + b.y); + } } void ofxPanel::render(){ border.draw(); - headerBg.draw(); + if(bShowHeader){ + headerBg.draw(); + } ofBlendMode blendMode = ofGetStyle().blendingMode; if(blendMode!=OF_BLENDMODE_ALPHA){ ofEnableAlphaBlending(); } ofColor c = ofGetStyle().color; - ofSetColor(thisTextColor); - bindFontTexture(); - textMesh.draw(); - unbindFontTexture(); - - bool texHackEnabled = ofIsTextureEdgeHackEnabled(); - ofDisableTextureEdgeHack(); - loadIcon.draw(loadBox); - saveIcon.draw(saveBox); - if(texHackEnabled){ - ofEnableTextureEdgeHack(); + if(bShowHeader){ + renderHeader(); } for(std::size_t i = 0; i < collection.size(); i++){ @@ -136,14 +136,32 @@ void ofxPanel::render(){ } } +void ofxPanel::renderHeader() { + ofSetColor(thisTextColor); + + if(bShowName){ + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); + } + + bool texHackEnabled = ofIsTextureEdgeHackEnabled(); + ofDisableTextureEdgeHack(); + loadIcon.draw(loadBox); + saveIcon.draw(saveBox); + if(texHackEnabled){ + ofEnableTextureEdgeHack(); + } +} + bool ofxPanel::mouseReleased(ofMouseEventArgs & args){ - this->bGrabbed = false; - if(ofxGuiGroup::mouseReleased(args)) return true; - if(isGuiDrawing() && b.inside(ofPoint(args.x,args.y))){ - return true; - }else{ - return false; - } + this->bGrabbed = false; + if(ofxGuiGroup::mouseReleased(args)) return true; + if(isGuiDrawing() && b.inside(ofPoint(args.x,args.y))){ + return true; + }else{ + return false; + } } bool ofxPanel::setValue(float mx, float my, bool bCheck){ @@ -157,22 +175,24 @@ bool ofxPanel::setValue(float mx, float my, bool bCheck){ if( b.inside(mx, my) ){ bGuiActive = true; - if( my > b.y && my <= b.y + header ){ - bGrabbed = true; - grabPt.set(mx-b.x, my-b.y); - } else{ - bGrabbed = false; - } - - if(loadBox.inside(mx, my)) { - loadFromFile(filename); - ofNotifyEvent(loadPressedE,this); - return true; - } - if(saveBox.inside(mx, my)) { - saveToFile(filename); - ofNotifyEvent(savePressedE,this); - return true; + if(bShowHeader){ + if( my > b.y && my <= b.y + header ){ + bGrabbed = true; + grabPt.set(mx-b.x, my-b.y); + } else{ + bGrabbed = false; + } + + if(loadBox.inside(mx, my)) { + loadFromFile(filename); + ofNotifyEvent(loadPressedE,this); + return true; + } + if(saveBox.inside(mx, my)) { + saveToFile(filename); + ofNotifyEvent(savePressedE,this); + return true; + } } } } else if( bGrabbed ){ @@ -181,3 +201,48 @@ bool ofxPanel::setValue(float mx, float my, bool bCheck){ } return false; } + +void ofxPanel::sizeChangedCB(){ + float x = b.x; + float y = b.y + spacingFirstElement; + if(bShowHeader){ + y += header; + } + + if(layout == ofxBaseGui::Vertical){ + for(auto & e: collection){ + e->setPosition(e->getPosition().x,y + spacing); + e->sizeChangedE.disable(); + e->setSize(b.width-1, e->getHeight()); + e->sizeChangedE.enable(); + y += e->getHeight()+spacing; + } + b.height = y - b.y; + }else{ + float max_h = 0; + for(auto & e: collection){ + e->setPosition(x,y + spacing); + x += e->getWidth() + spacing; + if(max_h < e->getHeight()){ + max_h = e->getHeight(); + } + } + y += max_h+spacing; + b.width = x - b.x; + b.height = y - b.y; + } + sizeChangedE.notify(this); + setNeedsRedraw(); +} + +void ofxPanel::setSize(float w, float h){ + ofxBaseGui::setSize(w,h); +} + +void ofxPanel::setShape(ofRectangle r){ + ofxBaseGui::setShape(r); +} + +void ofxPanel::setShape(float x, float y, float w, float h){ + ofxBaseGui::setShape(x,y,w,h); +} diff --git a/addons/ofxGui/src/ofxPanel.h b/addons/ofxGui/src/ofxPanel.h index 72759f06d24..8c236833b7a 100644 --- a/addons/ofxGui/src/ofxPanel.h +++ b/addons/ofxGui/src/ofxPanel.h @@ -7,36 +7,44 @@ class ofxGuiGroup; class ofxPanel : public ofxGuiGroup { public: struct Config: public ofxGuiGroup::Config{ - Config(){ + Config():ofxGuiGroup::Config(){ shape.x = 10; shape.y = 10; } - Config(const ofxGuiGroup::Config & config){} - Config(const ofxBaseGui::Config & config){} + Config(const ofxGuiGroup::Config & config):ofxGuiGroup::Config(config){} + Config(const ofxBaseGui::Config & config):ofxGuiGroup::Config(config){} }; ofxPanel(); - ofxPanel(const ofParameterGroup & parameters, const Config & config); - ofxPanel(const ofParameterGroup & parameters, const std::string& filename="settings.xml", float x = 10, float y = 10); + ofxPanel(const ofParameterGroup & parameters, const Config & groupConfig = ofxPanel::Config(), const Config &itemConfig = ofxBaseGui::Config()); ~ofxPanel(); - ofxPanel & setup(const ofParameterGroup & parameters, const Config & config); - ofxPanel & setup(const std::string& collectionName="", const std::string& filename="settings.xml", float x = 10, float y = 10); - ofxPanel & setup(const ofParameterGroup & parameters, const std::string& filename="settings.xml", float x = 10, float y = 10); + ofxPanel & setup(const Config & config = ofxPanel::Config()); + ofxPanel & setup(const std::string& collectionName, const Config & config = ofxPanel::Config()); + ofxPanel & setup(const ofParameterGroup & parameters, const Config & groupConfig = ofxPanel::Config(), const Config &itemConfig = ofxBaseGui::Config()); + ofxPanel & setup(const std::string& collectionName, const std::string& filename, float x = 10, float y = 10); + ofxPanel & setup(const ofParameterGroup & parameters, const std::string& filename, float x = 10, float y = 10); + + virtual void setSize(float w, float h); + virtual void setShape(ofRectangle r); + virtual void setShape(float x, float y, float w, float h); bool mouseReleased(ofMouseEventArgs & args); ofEvent loadPressedE; ofEvent savePressedE; protected: - void render(); - bool setValue(float mx, float my, bool bCheck); - void generateDraw(); - void loadIcons(); + virtual void sizeChangedCB(); + virtual void render(); + virtual void renderHeader(); + virtual bool setValue(float mx, float my, bool bCheck); + virtual void generateDraw(); + virtual void generateDrawHeader(); + virtual void loadIcons(); private: ofRectangle loadBox, saveBox; static ofImage loadIcon, saveIcon; - - ofPoint grabPt; + + ofPoint grabPt; bool bGrabbed; }; diff --git a/addons/ofxGui/src/ofxRotarySlider.cpp b/addons/ofxGui/src/ofxRotarySlider.cpp new file mode 100644 index 00000000000..884bf72effc --- /dev/null +++ b/addons/ofxGui/src/ofxRotarySlider.cpp @@ -0,0 +1,168 @@ +#include "ofxRotarySlider.h" +#include "ofGraphics.h" +#include "ofAppRunner.h" +using namespace std; + +template ofxRotarySlider ::ofxRotarySlider(){ + this->setSize(this->getWidth(), Config().shape.height); +} + +template ofxRotarySlider ::~ofxRotarySlider(){ +} + +template ofxRotarySlider ::ofxRotarySlider(ofParameter _val, const Config & config) : + ofxSlider (_val, config){ +} + +template +void ofxRotarySlider ::generateDraw(){ + + float inner_r = min(this->b.width, this->b.height) / 6; + float outer_r = min(this->b.width, this->b.height) / 2-1; + + this->bg.clear(); + this->bar.clear(); + this->border.clear(); + + this->border.setStrokeColor(this->thisBorderColor); + this->border.setStrokeWidth(1); + this->border.setFilled(false); + arcStrip(this->border, this->b.getCenter(), outer_r, inner_r, 1); + + this->bg.setFillColor(this->thisBackgroundColor); + this->bg.setFilled(true); + arcStrip(this->bg, this->b.getCenter(), outer_r-1, inner_r+1, 1); + + float val = ofMap(this->value, this->value.getMin(), this->value.getMax(), 0, 1); + this->bar.setFillColor(this->thisFillColor); + this->bar.setFilled(true); + arcStrip(this->bar, this->b.getCenter(), outer_r - 1, inner_r + 1, val); + + generateText(); +} + + +template +void ofxRotarySlider ::generateText(){ + string valStr = ofToString(this->value.get(), this->precision); + this->textMesh.clear(); + if(this->bShowName){ + this->textMesh.append(this->getTextMesh(this->getName(), this->b.x + this->textPadding, this->b.y + this->b.height - this->textPadding)); + } + this->textMesh.append(this->getTextMesh(valStr, this->b.x + this->b.width - this->textPadding - this->getTextBoundingBox(valStr, 0, 0).width, this->b.y + this->b.height - this->textPadding)); +} + +template <> +void ofxRotarySlider ::generateText(){ + string valStr = ofToString(this->value.get(), precision); + this->textMesh.clear(); + if(this->bShowName){ + this->textMesh.append(this->getTextMesh(this->getName(), this->b.x + this->textPadding, this->b.y + this->b.height - this->textPadding)); + } + this->textMesh.append(this->getTextMesh(valStr, this->b.x + this->b.width - this->textPadding - this->getTextBoundingBox(valStr, 0, 0).width, this->b.y + this->b.height - this->textPadding)); +} + +template +void ofxRotarySlider ::render(){ + ofColor c = ofGetStyle().color; + + this->bg.draw(); + this->bar.draw(); + this->border.draw(); + + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(this->thisTextColor); + + this->bindFontTexture(); + this->textMesh.draw(); + this->unbindFontTexture(); + + ofSetColor(c); + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } +} + +/* + * adapted from ofxUI by Reza Ali (www.syedrezaali.com || syed.reza.ali@gmail.com || @rezaali) + * + */ +template +void ofxRotarySlider ::arcStrip(ofPath & path, ofPoint center, float outer_radius, float inner_radius, float percent){ + float theta = ofMap(percent, 0, 1, 0, 360.0, true); + + { + float x = sin(-ofDegToRad(0)); + float y = cos(-ofDegToRad(0)); + path.moveTo(center.x + outer_radius * x, center.y + outer_radius * y); + } + + for(int i = 0; i <= theta; i += 10){ + float x = sin(-ofDegToRad(i)); + float y = cos(-ofDegToRad(i)); + + path.lineTo(center.x + outer_radius * x, center.y + outer_radius * y); + } + + { + float x = sin(-ofDegToRad(theta)); + float y = cos(-ofDegToRad(theta)); + path.lineTo(center.x + outer_radius * x, center.y + outer_radius * y); + path.lineTo(center.x + inner_radius * x, center.y + inner_radius * y); + } + + for(int i = theta; i >= 0; i -= 10){ + float x = sin(-ofDegToRad(i)); + float y = cos(-ofDegToRad(i)); + + path.lineTo(center.x + inner_radius * x, center.y + inner_radius * y); + } + + { + float x = sin(-ofDegToRad(0)); + float y = cos(-ofDegToRad(0)); + path.lineTo(center.x + inner_radius * x, center.y + inner_radius * y); + } + + path.close(); +} + +template +bool ofxRotarySlider ::mousePressed(ofMouseEventArgs & args){ + Type firstClickVal = ofMap(args.y, this->b.getBottom(), this->b.getTop(), 0, 1, true); + Type lastVal = ofMap(this->value, this->value.getMin(), this->value.getMax(), 0, 1, true); + _mouseOffset = (firstClickVal - lastVal) * this->b.height; + return ofxSlider ::mousePressed(args); +} + +template +bool ofxRotarySlider ::setValue(float mx, float my, bool bCheck){ + if(!this->isGuiDrawing()){ + this->bGuiActive = false; + return false; + } + if(bCheck){ + if(this->b.inside(mx, my)){ + this->bGuiActive = true; + }else{ + this->bGuiActive = false; + } + } + if(this->bGuiActive){ + this->value = ofMap(my, this->b.getBottom() - _mouseOffset, this->b.getTop() - _mouseOffset, this->value.getMin(), this->value.getMax(), true); + return true; + } + return false; +} + +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; +template class ofxRotarySlider ; diff --git a/addons/ofxGui/src/ofxRotarySlider.h b/addons/ofxGui/src/ofxRotarySlider.h new file mode 100644 index 00000000000..e702b2bb4d2 --- /dev/null +++ b/addons/ofxGui/src/ofxRotarySlider.h @@ -0,0 +1,36 @@ +#pragma once + +#include "ofxSlider.h" +#include "ofParameter.h" + +template +class ofxRotarySlider : public ofxSlider { + public: + struct Config : public ofxSlider ::Config { + Config(){ + this->shape.height = 60; + } + Config(const typename ofxSlider ::Config & c) : ofxSlider ::Config(c){ + } + Config(const ofxBaseGui::Config & c) : ofxSlider ::Config(c){ + } + }; + + ofxRotarySlider(); + ~ofxRotarySlider(); + ofxRotarySlider(ofParameter _val, const Config & config = Config()); + + virtual bool mousePressed(ofMouseEventArgs & args); + + protected: + virtual void render(); + bool setValue(float mx, float my, bool bCheck); + void generateDraw(); + void generateText(); + void valueChanged(Type & value); + void arcStrip(ofPath & path, ofPoint center, float outer_radius, float inner_radius, float percent); + float _mouseOffset; +}; + +typedef ofxRotarySlider ofxFloatRotarySlider; +typedef ofxRotarySlider ofxIntRotarySlider; diff --git a/addons/ofxGui/src/ofxSlider.cpp b/addons/ofxGui/src/ofxSlider.cpp index b7be7287e8c..af229bbba2a 100644 --- a/addons/ofxGui/src/ofxSlider.cpp +++ b/addons/ofxGui/src/ofxSlider.cpp @@ -17,10 +17,16 @@ ofxSlider::~ofxSlider(){ template ofxSlider::ofxSlider(ofParameter _val, const Config & config) :ofxBaseGui(config) +,precision(config.precision) ,bUpdateOnReleaseOnly(config.updateOnReleaseOnly) ,bGuiActive(false) -,mouseInside(false) -{ +,mouseInside(false){ + if(layout == ofxBaseGui::Vertical){ + float _w = b.width; + float _h = b.height; + b.height = _w; + b.width = _h; + } value.makeReferenceTo(_val); value.addListener(this,&ofxSlider::valueChanged); setNeedsRedraw(); @@ -28,8 +34,17 @@ ofxSlider::ofxSlider(ofParameter _val, const Config & config) } template -ofxSlider::ofxSlider(ofParameter _val, float width, float height){ - setup(_val,width,height); +ofxSlider & ofxSlider::setup(ofParameter _val, const Config & config){ + ofxBaseGui::setup(config); + bUpdateOnReleaseOnly = config.updateOnReleaseOnly; + value.makeReferenceTo(_val); + precision = config.precision; + bGuiActive = false; + setNeedsRedraw(); + + value.addListener(this,&ofxSlider::valueChanged); + registerMouseEvents(); + return *this; } template @@ -40,6 +55,7 @@ ofxSlider & ofxSlider::setup(ofParameter _val, float width, fl b.y = 0; b.width = width; b.height = height; + precision = Config().precision; bGuiActive = false; setNeedsRedraw(); @@ -56,22 +72,27 @@ ofxSlider & ofxSlider::setup(const std::string& sliderName, Type _va template void ofxSlider::setMin(Type min){ - value.setMin(min); + value.setMin(min); } template Type ofxSlider::getMin(){ - return value.getMin(); + return value.getMin(); } template void ofxSlider::setMax(Type max){ - value.setMax(max); + value.setMax(max); } template Type ofxSlider::getMax(){ - return value.getMax(); + return value.getMax(); +} + +template +void ofxSlider::setPrecision(int precision){ + this->precision = precision; } template @@ -117,29 +138,27 @@ bool ofxSlider::mouseReleased(ofMouseEventArgs & args){ } template -bool ofxSlider::mouseScrolled(ofMouseEventArgs & args){ - if(mouseInside){ - if(args.y>0 || args.y<0){ - double range = value.getMax() - value.getMin(); - range /= b.width*4; - Type newValue = value + ofMap(args.y,-1,1,-range, range); - newValue = ofClamp(newValue,value.getMin(),value.getMax()); - value = newValue; - } - return true; - }else{ - return false; - } +typename std::enable_if::value, Type>::type +getRange(Type min, Type max, float width){ + double range = max - min; + range /= width*4; + return std::max(range,1.0); } -template<> -bool ofxSlider::mouseScrolled(ofMouseEventArgs & args){ +template +typename std::enable_if::value, Type>::type +getRange(Type min, Type max, float width){ + double range = max - min; + range /= width*4; + return range; +} + +template +bool ofxSlider::mouseScrolled(ofMouseEventArgs & args){ if(mouseInside){ - if(args.y>0 || args.y<0){ - double range = value.getMax() - value.getMin(); - range /= b.width*4; - range = max(range, 1.0); - int newValue = value + ofMap(args.y,-1,1,-range, range); + if(args.scrollY>0 || args.scrollY<0){ + double range = getRange(value.getMin(),value.getMax(),b.width); + Type newValue = value + ofMap(args.scrollY,-1,1,-range, range); newValue = ofClamp(newValue,value.getMin(),value.getMax()); value = newValue; } @@ -164,54 +183,106 @@ template void ofxSlider::generateDraw(){ bg.clear(); bar.clear(); + border.clear(); bg.setFillColor(thisBackgroundColor); bg.setFilled(true); - bg.rectangle(b); + bg.rectangle(b.x+1, b.y+1, b.width-2, b.height-2); - float valAsPct = ofMap( value, value.getMin(), value.getMax(), 0, b.width-2, true ); + border.setStrokeColor(thisBorderColor); + border.setFilled(false); + border.setStrokeWidth(1); + border.rectangle(b); + + float valAsPct; + if(layout == ofxBaseGui::Horizontal){ + valAsPct = ofMap( value, value.getMin(), value.getMax(), 0, b.width-2, true ); + }else{ + valAsPct = ofMap( value, value.getMin(), value.getMax(), 0, b.height-2, true ); + } bar.setFillColor(thisFillColor); bar.setFilled(true); - bar.rectangle(b.x+1, b.y+1, valAsPct, b.height-2); + if(layout == ofxBaseGui::Horizontal){ + bar.rectangle(b.x+1, b.y+1, valAsPct, b.height-2); + }else{ + bar.rectangle(b.x + 1, b.y + b.height - 1 - valAsPct, b.width - 2, valAsPct); + } - generateText(); + if(bShowName){ + generateText(); + } } template void ofxSlider::generateText(){ - string valStr = ofToString(value); - textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); - textMesh.append(getTextMesh(valStr, b.x + b.width - textPadding - getTextBoundingBox(valStr,0,0).width, b.y + b.height / 2 + 4)); + if(layout == ofxBaseGui::Horizontal){ + string valStr = ofToString(value.get(), precision); + textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); + textMesh.append(getTextMesh(valStr, b.x + b.width - textPadding - getTextBoundingBox(valStr,0,0).width, b.y + b.height / 2 + 4)); + }else{ + textMesh.clear(); + if(bShowName){ + string nameStr = getName(); + while(getTextBoundingBox(nameStr, 0, 0).getWidth() + textPadding * 2 > b.getWidth() && nameStr.length() > 1){ + nameStr = nameStr.substr(0, nameStr.size() - 1); + } + textMesh.append(getTextMesh(nameStr, b.x + textPadding, b.y + textPadding + getTextBoundingBox(nameStr, 0, 0).height)); + } + string valStr = ofToString(value.get(), precision); + while(getTextBoundingBox(valStr, 0, 0).getWidth() + textPadding * 2 > b.getWidth() && valStr.length() > 1){ + valStr = valStr.substr(0, valStr.size() - 1); + } + textMesh.append(getTextMesh(valStr, b.x + textPadding, b.y + b.height - textPadding)); + } } template<> void ofxSlider::generateText(){ - string valStr = ofToString((int)value); - textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); - textMesh.append(getTextMesh(valStr, b.x + b.width - textPadding - getTextBoundingBox(valStr,0,0).width, b.y + b.height / 2 + 4)); + if(layout == ofxBaseGui::Horizontal){ + string valStr = ofToString((int)value, precision); + textMesh = getTextMesh(getName(), b.x + textPadding, b.y + b.height / 2 + 4); + textMesh.append(getTextMesh(valStr, b.x + b.width - textPadding - getTextBoundingBox(valStr,0,0).width, b.y + b.height / 2 + 4)); + }else{ + textMesh.clear(); + if(bShowName){ + string nameStr = getName(); + while(getTextBoundingBox(nameStr, 0, 0).getWidth() + textPadding * 2 > b.getWidth() && nameStr.length() > 1){ + nameStr = nameStr.substr(0, nameStr.size() - 1); + } + textMesh.append(getTextMesh(nameStr, b.x + textPadding, b.y + textPadding + getTextBoundingBox(nameStr, 0, 0).height)); + } + string valStr = ofToString((int)value, precision); + while(getTextBoundingBox(valStr, 0, 0).getWidth() + textPadding * 2 > b.getWidth() && valStr.length() > 1){ + valStr = valStr.substr(0, valStr.size() - 1); + } + textMesh.append(getTextMesh(valStr, b.x + textPadding, b.y + b.height - textPadding)); + } } template void ofxSlider::render(){ ofColor c = ofGetStyle().color; + border.draw(); bg.draw(); bar.draw(); - ofBlendMode blendMode = ofGetStyle().blendingMode; - if(blendMode!=OF_BLENDMODE_ALPHA){ - ofEnableAlphaBlending(); - } - ofSetColor(thisTextColor); + if(bShowName){ + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(thisTextColor); - bindFontTexture(); - textMesh.draw(); - unbindFontTexture(); + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); - ofSetColor(c); - if(blendMode!=OF_BLENDMODE_ALPHA){ - ofEnableBlendMode(blendMode); + ofSetColor(c); + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } } } @@ -230,7 +301,11 @@ bool ofxSlider::setValue(float mx, float my, bool bCheck){ } } if( bGuiActive ){ - value = ofMap(mx, b.x, b.x + b.width, value.getMin(), value.getMax(), true); + if(layout == ofxBaseGui::Horizontal){ + value = ofMap(mx, b.x, b.x + b.width, value.getMin(), value.getMax(), true); + }else{ + value = ofMap(my, b.y + b.height, b.y, value.getMin(), value.getMax(), true); + } return true; } return false; @@ -249,14 +324,16 @@ void ofxSlider::setUpdateOnReleaseOnly(bool _bUpdateOnReleaseOnly){ template void ofxSlider::valueChanged(Type & value){ - setNeedsRedraw(); + setNeedsRedraw(); } -template class ofxSlider; -template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; +template class ofxSlider; template class ofxSlider; template class ofxSlider; -template class ofxSlider; -template class ofxSlider; -template class ofxSlider; -template class ofxSlider; diff --git a/addons/ofxGui/src/ofxSlider.h b/addons/ofxGui/src/ofxSlider.h index 93b4d861ae2..8afb2d862d6 100644 --- a/addons/ofxGui/src/ofxSlider.h +++ b/addons/ofxGui/src/ofxSlider.h @@ -5,31 +5,34 @@ template class ofxSlider : public ofxBaseGui{ -public: +public: struct Config: public ofxBaseGui::Config{ Config(){} Config(const ofxBaseGui::Config & c) :ofxBaseGui::Config(c){} bool updateOnReleaseOnly = false; + unsigned int precision = 6; }; ofxSlider(); ~ofxSlider(); ofxSlider(ofParameter _val, const Config & config = Config()); - ofxSlider(ofParameter _val, float width, float height = defaultHeight); + ofxSlider & setup(ofParameter _val, const Config & config); ofxSlider & setup(ofParameter _val, float width = defaultWidth, float height = defaultHeight); ofxSlider & setup(const std::string& sliderName, Type _val, Type _min, Type _max, float width = defaultWidth, float height = defaultHeight); - + void setMin(Type min); Type getMin(); void setMax(Type max); Type getMax(); + void setPrecision(int precision); + virtual bool mouseMoved(ofMouseEventArgs & args); virtual bool mousePressed(ofMouseEventArgs & args); virtual bool mouseDragged(ofMouseEventArgs & args); virtual bool mouseReleased(ofMouseEventArgs & args); - virtual bool mouseScrolled(ofMouseEventArgs & args); + virtual bool mouseScrolled(ofMouseEventArgs & args); void setUpdateOnReleaseOnly(bool bUpdateOnReleaseOnly); @@ -45,17 +48,17 @@ class ofxSlider : public ofxBaseGui{ } - double operator=(Type v); operator const Type & (); - + ofAbstractParameter & getParameter(); protected: virtual void render(); ofParameter value; + unsigned int precision; bool bUpdateOnReleaseOnly; bool bGuiActive; bool mouseInside; @@ -63,7 +66,7 @@ class ofxSlider : public ofxBaseGui{ virtual void generateDraw(); virtual void generateText(); void valueChanged(Type & value); - ofPath bg, bar; + ofPath bg, bar, border; ofVboMesh textMesh; }; diff --git a/addons/ofxGui/src/ofxSliderGroup.cpp b/addons/ofxGui/src/ofxSliderGroup.cpp index 001fc6643e3..b064dce46ee 100644 --- a/addons/ofxGui/src/ofxSliderGroup.cpp +++ b/addons/ofxGui/src/ofxSliderGroup.cpp @@ -10,38 +10,47 @@ template ofxVecSlider_::ofxVecSlider_(ofParameter value, const Config & config) :ofxGuiGroup(ofParameterGroup(), config) ,sliderChanging(false){ - setup(value, config.shape.width, config.shape.height); + setup(value, config); } template ofxVecSlider_::ofxVecSlider_(ofParameter value, float width, float height){ sliderChanging = false; - setup(value, width, height); + setup(value, width, height); } template ofxVecSlider_ & ofxVecSlider_::setup(ofParameter value, float width, float height){ - ofxGuiGroup::setup(value.getName(), "", 0, 0); - - parameters.clear(); - - const string names[4] = {"x", "y", "z", "w"}; - - this->value.makeReferenceTo(value); - this->value.addListener(this, & ofxVecSlider_::changeValue); - - VecType val = value; - VecType min = value.getMin(); - VecType max = value.getMax(); - ofxFloatSlider::Config config = this->config; - for (int i=0; i p(names[i], val[i], min[i], max[i]); - add(p,config); - p.addListener(this, & ofxVecSlider_::changeSlider); - } - - sliderChanging = false; - return *this; + ofxGuiGroup::Config config; + config.shape.width = width; + config.shape.height= height; + return setup(value, config); +} + +template +ofxVecSlider_ & ofxVecSlider_::setup(ofParameter value, const Config & config){ + ofxGuiGroup::setup(config); + setName(value.getName()); + + parameters.clear(); + + const string names[4] = {"x", "y", "z", "w"}; + + this->value.makeReferenceTo(value); + this->value.addListener(this, & ofxVecSlider_::changeValue); + + VecType val = value; + VecType min = value.getMin(); + VecType max = value.getMax(); + ofxFloatSlider::Config sliderconfig = ofxFloatSlider::Config(); + for (int i=0; i p(names[i], val[i], min[i], max[i]); + add(p,sliderconfig); + p.addListener(this, & ofxVecSlider_::changeSlider); + } + + sliderChanging = false; + return *this; } @@ -53,23 +62,23 @@ ofxVecSlider_ & ofxVecSlider_::setup(const std::string& contro template void ofxVecSlider_::changeSlider(const void * parameter, float & _value){ - sliderChanging = true; - ofParameter & param = *(ofParameter*)parameter; - int i = parameters.getPosition(param.getName()); - VecType data = value; - data[i] = _value; - value = data; - sliderChanging = false; + sliderChanging = true; + ofParameter & param = *(ofParameter*)parameter; + int i = parameters.getPosition(param.getName()); + VecType data = value; + data[i] = _value; + value = data; + sliderChanging = false; } template void ofxVecSlider_::changeValue(VecType & value){ - if (sliderChanging){ - return; - } - for (int i=0; i() = value[i]; - } + if (sliderChanging){ + return; + } + for (int i=0; i() = value[i]; + } } template @@ -108,72 +117,86 @@ template ofxColorSlider_::ofxColorSlider_(ofParameter> value, const Config & config) :ofxGuiGroup(ofParameterGroup(), config) ,sliderChanging(false){ - setup(value, config.shape.width, config.shape.height); + setup(value, config); } template ofxColorSlider_::ofxColorSlider_(ofParameter > value, float width, float height){ sliderChanging = false; - setup(value, width, height); + setup(value, width, height); } template ofxColorSlider_ & ofxColorSlider_::setup(ofParameter > value, float width, float height){ - ofxGuiGroup::setup(value.getName(), "", 0, 0); - parameters.clear(); - - const string names[4] = {"r", "g", "b", "a"}; - - this->value.makeReferenceTo(value); - this->value.addListener(this, & ofxColorSlider_::changeValue); + ofxGuiGroup::Config config; + config.shape.width = width; + config.shape.height= height; + return setup(value, config); +} - ofColor_ val = value; - ofColor_ min = value.getMin(); - ofColor_ max = value.getMax(); - typename ofxSlider::Config config = this->config; - for (int i=0; i<4; i++) { - ofParameter p(names[i], val[i], min[i], max[i]); - add>(p,config); - p.addListener(this, & ofxColorSlider_::changeSlider); - collection[i]->setFillColor(value.get()); - } +template +ofxColorSlider_ & ofxColorSlider_::setup(ofParameter > value, const Config & config){ + ofxGuiGroup::setup(config); + setName(value.getName()); + parameters.clear(); + + const string names[4] = {"r", "g", "b", "a"}; + + this->value.makeReferenceTo(value); + this->value.addListener(this, & ofxColorSlider_::changeValue); + + ofColor_ val = value; + ofColor_ min = value.getMin(); + ofColor_ max = value.getMax(); + typename ofxSlider::Config sliderconfig = typename ofxSlider::Config(); + if(config.layout == ofxBaseGui::Vertical){ + sliderconfig.layout = ofxBaseGui::Horizontal; + }else{ + sliderconfig.layout = ofxBaseGui::Vertical; + } + for (int i=0; i<4; i++) { + ofParameter p(names[i], val[i], min[i], max[i]); + add>(p,sliderconfig); + p.addListener(this, & ofxColorSlider_::changeSlider); + collection[i]->setFillColor(value.get()); + } - sliderChanging = false; - return *this; + sliderChanging = false; + return *this; } template ofxColorSlider_ & ofxColorSlider_::setup(const std::string& controlName, const ofColor_ & v, const ofColor_ & min, const ofColor_ & max, float width, float height){ - value.set(controlName, v, min, max); + value.set(controlName, v, min, max); return setup(value,width,height); } template void ofxColorSlider_::changeSlider(const void * parameter, ColorType & _value){ - sliderChanging = true; - ofParameter & param = *(ofParameter*)parameter; - int i = parameters.getPosition(param.getName()); - ofColor_ data = value; - data[i] = _value; - value = data; + sliderChanging = true; + ofParameter & param = *(ofParameter*)parameter; + int i = parameters.getPosition(param.getName()); + ofColor_ data = value; + data[i] = _value; + value = data; - for (int i=0; i<4; i++){ - collection[i]->setFillColor(value.get()); - } - sliderChanging = false; + for (int i=0; i<4; i++){ + collection[i]->setFillColor(value.get()); + } + sliderChanging = false; } template void ofxColorSlider_::changeValue(ofColor_ & value){ - if (sliderChanging){ - return; - } - for (int i=0; i<4; i++){ - parameters[i].template cast() = value[i]; - collection[i]->setFillColor(value); - } + if (sliderChanging){ + return; + } + for (int i=0; i<4; i++){ + parameters[i].template cast() = value[i]; + collection[i]->setFillColor(value); + } } template diff --git a/addons/ofxGui/src/ofxSliderGroup.h b/addons/ofxGui/src/ofxSliderGroup.h index 006381fd4d8..6d15e6b832c 100644 --- a/addons/ofxGui/src/ofxSliderGroup.h +++ b/addons/ofxGui/src/ofxSliderGroup.h @@ -14,22 +14,23 @@ class ofxVecSlider_ : public ofxGuiGroup { :ofxGuiGroup::Config(c){} }; ofxVecSlider_(); - ofxVecSlider_(ofParameter value, const Config & config = Config()); - ofxVecSlider_(ofParameter value, float width, float height = defaultHeight); + ofxVecSlider_(ofParameter value, const Config & config = Config()); + ofxVecSlider_(ofParameter value, float width, float height = defaultHeight); - ofxVecSlider_ & setup(ofParameter value, float width = defaultWidth, float height = defaultHeight); - ofxVecSlider_ & setup(const std::string& controlName, const VecType & value, const VecType & min, const VecType & max, float width = defaultWidth, float height = defaultHeight); + ofxVecSlider_ & setup(ofParameter value, float width = defaultWidth, float height = defaultHeight); + ofxVecSlider_ & setup(ofParameter value, const Config & config = Config()); + ofxVecSlider_ & setup(const std::string& controlName, const VecType & value, const VecType & min, const VecType & max, float width = defaultWidth, float height = defaultHeight); - ofAbstractParameter & getParameter(); + ofAbstractParameter & getParameter(); - VecType operator=(const VecType & v); + VecType operator=(const VecType & v); operator const VecType & (); const VecType * operator->(); protected: - void changeSlider(const void * parameter, float & value); - void changeValue(VecType & value); - ofParameter value; - bool sliderChanging; + void changeSlider(const void * parameter, float & value); + void changeValue(VecType & value); + ofParameter value; + bool sliderChanging; }; typedef ofxVecSlider_ ofxVec3Slider; @@ -54,6 +55,7 @@ class ofxColorSlider_: public ofxGuiGroup{ ofxColorSlider_(ofParameter > value, float width = defaultWidth, float height = defaultHeight); ofxColorSlider_ & setup(ofParameter > value, float width = defaultWidth, float height = defaultHeight); + ofxColorSlider_ & setup(ofParameter > value, const Config & config = Config()); ofxColorSlider_ & setup(const std::string& controlName, const ofColor_ & value, const ofColor_ & min, const ofColor_ & max, float width = defaultWidth, float height = defaultHeight); ofAbstractParameter & getParameter(); @@ -61,10 +63,10 @@ class ofxColorSlider_: public ofxGuiGroup{ ofColor_ operator=(const ofColor_ & v); operator const ofColor_ & (); protected: - void changeSlider(const void * parameter, ColorType & value); - void changeValue(ofColor_ & value); - ofParameter > value; - bool sliderChanging; + void changeSlider(const void * parameter, ColorType & value); + void changeValue(ofColor_ & value); + ofParameter > value; + bool sliderChanging; }; typedef ofxColorSlider_ ofxColorSlider; diff --git a/addons/ofxGui/src/ofxTabbedPages.cpp b/addons/ofxGui/src/ofxTabbedPages.cpp new file mode 100644 index 00000000000..9eb66bcddde --- /dev/null +++ b/addons/ofxGui/src/ofxTabbedPages.cpp @@ -0,0 +1,230 @@ +#include "ofxTabbedPages.h" +#include "ofGraphics.h" +#include "ofxMinimalToggle.h" +using namespace std; + +ofxTabbedPages::ofxTabbedPages() : + ofxGuiPage(){ +} + +ofxTabbedPages::~ofxTabbedPages(){ + // +} + +ofxTabbedPages & ofxTabbedPages::setup(string collectionName, string filename, float x, float y){ + ofxGuiPage::setup(collectionName, filename, x, y); + tabs.setup("tabs"); + tabs.setShowHeader(false); + tabs.setExclusiveToggles(true); + tabs.setLayout(ofxBaseGui::Horizontal); + tabs.setBorderColor(ofColor(0, 0, 0, 0)); + tabs.setDefaultBackgroundColor(thisBorderColor); + tabs.setDefaultBorderColor(thisBorderColor); + tabs.setDefaultFillColor(thisBackgroundColor); + tabHeight = 20; + tabWidth = 0; + sizeChangedCB(); + collection.push_back(&tabs); + tabs.unregisterMouseEvents(); + parameters.add(tabs.getParameter()); + updateContentShapes(); + return *this; +} + +void ofxTabbedPages::add(ofxGuiGroup *element){ + collection.push_back(element); + + parameters_tabs.push_back(ofParameter (element->getName(), false)); + ofxMinimalToggle::Config config; + config.shape.setSize(tabWidth, tabHeight); + config.textLayout = ofxBaseGui::Centered; + if(element->getBackgroundColor() != thisBackgroundColor){ + config.backgroundColor = element->getBackgroundColor(); + config.borderColor = element->getBackgroundColor(); + } + tabs.add (parameters_tabs.at(parameters_tabs.size() - 1), config); + + element->setPosition(pagesShape.getPosition()); + element->setShowHeader(false); + element->setBorderColor(ofColor(0, 0, 0, 0)); + setSizeToElement(element); + + element->setSize(pagesShape.width, pagesShape.height); + + element->unregisterMouseEvents(); + ofAddListener(element->sizeChangedE, this, &ofxTabbedPages::sizeChangedCB); + + parameters.add(element->getParameter()); + + if(collection.size() == 2){ + setActiveTab(0); + } + + setNeedsRedraw(); +} + +void ofxTabbedPages::clear(){ + collection.resize(1); + parameters.clear(); + parameters.add(tabs.getParameter()); + b.height = spacing + spacingNextElement; + if(bShowHeader){ + b.height += header; + } + tabs.clear(); + sizeChangedCB(); +} + +void ofxTabbedPages::generateDraw(){ + + updateContentShapes(); + + bg.clear(); + bg.setFillColor(thisBackgroundColor); + bg.setFilled(true); + bg.rectangle(pagesShape.x, pagesShape.y, pagesShape.width + 1, pagesShape.height); + + border.clear(); + border.setStrokeColor(thisBorderColor); + border.setStrokeWidth(1); + border.setFilled(false); + border.rectangle(pagesShape.x, pagesShape.y + 1, pagesShape.width + 1, pagesShape.height); + + if(bShowHeader){ + generateDrawHeader(); + } +} + +void ofxTabbedPages::render(){ + + /* + * TODO: call the first part when a tab toggle is clicked + * in this case call needsRedraw + * move the second part to generateDraw + */ + for(int i = 1; i < (int)collection.size(); i++){ + if(parameters_tabs.at(i - 1).get()){ + activePage = collection[i]; + activeToggle = tabs.getControl(i - 1); + } + } + + tabBorder.clear(); + if(activePage){ + tabBorder.setStrokeWidth(3); + tabBorder.setFilled(false); + tabBorder.setStrokeColor(thisBackgroundColor); + tabBorder.moveTo(activeToggle->getShape().getBottomLeft() - ofPoint(-1, 1)); + tabBorder.lineTo(activeToggle->getShape().getBottomRight() - ofPoint(1, 1)); + + this->setBorderColor(activeToggle->getBorderColor()); + } + /* + * end TODO + */ + + bg.draw(); + tabs.draw(); + border.draw(); + tabBorder.draw(); + if(bShowHeader){ + headerBg.draw(); + } + + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofColor c = ofGetStyle().color; + + if(bShowHeader){ + renderHeader(); + } + + if(activePage){ + activePage->draw(); + } + + ofSetColor(c); + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } + +} + +void ofxTabbedPages::updateContentShapes(){ + ofPoint newpos = b.getPosition(); + if(bShowHeader){ + newpos.y += header + spacing; + } + + tabShape.setPosition(newpos); + tabShape.setWidth(b.width); + tabShape.setHeight(tabHeight); + + newpos.y += tabHeight; + pagesShape.setPosition(newpos); + pagesShape.setWidth(b.width - 1 /*border*/); + pagesShape.setHeight(b.getBottom() - newpos.y - 1 /*border*/); +} + +void ofxTabbedPages::setSizeToElement(ofxBaseGui * element){ + updateContentShapes(); + if(element->getWidth() > pagesShape.width){ + b.width = element->getWidth() + 1 /*border*/; + } + if(element->getHeight() > pagesShape.getHeight()){ + b.height = element->getHeight() + tabHeight + 1 /*border*/; + if(bShowHeader){ + b.height += spacing + header; + } + } + sizeChangedCB(); +} + +void ofxTabbedPages::sizeChangedCB(){ + updateContentShapes(); + tabs.setShape(tabShape); + + for(int i = 1; i < (int)collection.size(); i++){ + collection[i]->sizeChangedE.disable(); + collection[i]->setShape(pagesShape); + collection[i]->sizeChangedE.enable(); + } + ofNotifyEvent(sizeChangedE,this); + setNeedsRedraw(); +} + +void ofxTabbedPages::setActiveTab(int index){ + tabs.setActiveToggle(index); + activeToggle = tabs.getControl(index); +} + +int ofxTabbedPages::getActiveTabIndex(){ + return tabs.getActiveToggleIndex(); +} + +ofxGuiPage * ofxTabbedPages::getActiveTab(){ + return (ofxGuiPage *)collection.at(tabs.getActiveToggleIndex() + 1); +} + +void ofxTabbedPages::setTabHeight(int h){ + tabHeight = h; + sizeChangedCB(); +} + +void ofxTabbedPages::setTabWidth(int w){ + tabWidth = w; + sizeChangedCB(); +} + +void ofxTabbedPages::setBorderColor(const ofColor &color){ + ofxGuiPage::setBorderColor(color); + tabs.setDefaultBackgroundColor(color); + tabs.setDefaultBorderColor(thisBorderColor); +} + +void ofxTabbedPages::setBackgroundColor(const ofColor &color){ + ofxGuiPage::setBackgroundColor(color); + tabs.setDefaultFillColor(color); +} diff --git a/addons/ofxGui/src/ofxTabbedPages.h b/addons/ofxGui/src/ofxTabbedPages.h new file mode 100644 index 00000000000..75fe60c75ec --- /dev/null +++ b/addons/ofxGui/src/ofxTabbedPages.h @@ -0,0 +1,60 @@ +#pragma once + +#include "ofxGuiPage.h" + +class ofxTabbedPages : public ofxGuiPage { + + public: + + struct Config: public ofxGuiPage::Config{ + Config(){} + Config(const ofxGuiPage::Config & c) + :ofxGuiPage::Config(c){} + Config(const ofxGuiGroup::Config & c) + :ofxGuiPage::Config(c){} + Config(const ofxBaseGui::Config & c) + :ofxGuiPage::Config(c){} + + float tabWidth = 100; + float tabHeight = defaultHeight; + }; + + ofxTabbedPages(); + ofxTabbedPages(const Config & config); + ~ofxTabbedPages(); + + ofxTabbedPages & setup(std::string collectionName = "", std::string filename = "settings.xml", float x = 10, float y = 10); + + using ofxGuiGroup::add; + + void clear(); + + void setActiveTab(int index); + int getActiveTabIndex(); + ofxGuiPage * getActiveTab(); + + void setTabHeight(int h); + void setTabWidth(int w); + + void setBorderColor(const ofColor &color); + void setBackgroundColor(const ofColor &color); + + protected: + void render(); + void generateDraw(); + void updateContentShapes(); + void setSizeToElement(ofxBaseGui * element); + virtual void sizeChangedCB(); + virtual void add(ofxGuiGroup * element); + + private: + + ofxGuiGroup tabs; + std::vector > parameters_tabs; + float tabHeight, tabWidth; + ofRectangle pagesShape, tabShape; + ofPath bg; + ofPath tabBorder; + ofxBaseGui * activePage; + ofxBaseGui * activeToggle; +}; diff --git a/addons/ofxGui/src/ofxToggle.cpp b/addons/ofxGui/src/ofxToggle.cpp index 4b28bff8223..e04dc6f5e72 100644 --- a/addons/ofxGui/src/ofxToggle.cpp +++ b/addons/ofxGui/src/ofxToggle.cpp @@ -2,34 +2,40 @@ #include "ofGraphics.h" using namespace std; -ofxToggle::ofxToggle() -:ofxBaseGui(Config()) +ofxToggle::ofxToggle():ofxBaseGui(){} + +ofxToggle::ofxToggle(ofParameter &_bVal, const Config & config) +:ofxBaseGui(config) ,bGuiActive(false){ + value.makeReferenceTo(_bVal); checkboxRect.set(1, 1, b.height - 2, b.height - 2); value.addListener(this,&ofxToggle::valueChanged); registerMouseEvents(); setNeedsRedraw(); } -ofxToggle::ofxToggle(ofParameter _bVal, const Config & config) -:ofxBaseGui(config) -,bGuiActive(false){ +ofxToggle::~ofxToggle(){ + value.removeListener(this,&ofxToggle::valueChanged); +} + +ofxToggle & ofxToggle::setup(ofParameter &_bVal, const Config & config){ + ofxBaseGui::setup(config); + bGuiActive = false; value.makeReferenceTo(_bVal); checkboxRect.set(1, 1, b.height - 2, b.height - 2); value.addListener(this,&ofxToggle::valueChanged); registerMouseEvents(); setNeedsRedraw(); -} -ofxToggle::ofxToggle(ofParameter _bVal, float width, float height){ - setup(_bVal,width,height); + return *this; } -ofxToggle::~ofxToggle(){ - value.removeListener(this,&ofxToggle::valueChanged); +ofxToggle & ofxToggle::setup(const std::string& toggleName, const Config & config){ + value.setName(toggleName); + return setup(value, config); } -ofxToggle & ofxToggle::setup(ofParameter _bVal, float width, float height){ +ofxToggle & ofxToggle::setup(ofParameter &_bVal, float width, float height){ b.x = 0; b.y = 0; b.width = width; @@ -98,7 +104,7 @@ void ofxToggle::generateDraw(){ }else{ fg.setFilled(false); fg.setStrokeWidth(1); - fg.setStrokeColor(thisFillColor); + fg.setStrokeColor(thisBorderColor); } fg.rectangle(b.getPosition()+checkboxRect.getTopLeft(),checkboxRect.width,checkboxRect.height); @@ -111,7 +117,9 @@ void ofxToggle::generateDraw(){ cross.moveTo(b.getPosition()+checkboxRect.getTopRight()); cross.lineTo(b.getPosition()+checkboxRect.getBottomLeft()); - textMesh = getTextMesh(getName(), b.x+textPadding + checkboxRect.width, b.y+b.height / 2 + 4); + if(bShowName){ + textMesh = getTextMesh(getName(), b.x+textPadding + checkboxRect.width, b.y+b.height / 2 + 4); + } } void ofxToggle::render(){ @@ -122,20 +130,22 @@ void ofxToggle::render(){ cross.draw(); } - ofColor c = ofGetStyle().color; - ofBlendMode blendMode = ofGetStyle().blendingMode; - if(blendMode!=OF_BLENDMODE_ALPHA){ - ofEnableAlphaBlending(); - } - ofSetColor(thisTextColor); + if(bShowName){ + ofColor c = ofGetStyle().color; + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(thisTextColor); - bindFontTexture(); - textMesh.draw(); - unbindFontTexture(); + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); - ofSetColor(c); - if(blendMode!=OF_BLENDMODE_ALPHA){ - ofEnableBlendMode(blendMode); + ofSetColor(c); + if(blendMode!=OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } } } @@ -178,5 +188,5 @@ ofAbstractParameter & ofxToggle::getParameter(){ } void ofxToggle::valueChanged(bool & value){ - setNeedsRedraw(); + setNeedsRedraw(); } diff --git a/addons/ofxGui/src/ofxToggle.h b/addons/ofxGui/src/ofxToggle.h index 01ade2b9993..049c36c72b6 100644 --- a/addons/ofxGui/src/ofxToggle.h +++ b/addons/ofxGui/src/ofxToggle.h @@ -12,19 +12,19 @@ class ofxToggle : public ofxBaseGui{ }; ofxToggle(); - ofxToggle(ofParameter _bVal, const Config & config = Config()); + ofxToggle(ofParameter& _bVal, const Config & config = Config()); ~ofxToggle(); - ofxToggle(ofParameter _bVal, float width, float height = defaultHeight); - ofxToggle & setup(ofParameter _bVal, float width = defaultWidth, float height = defaultHeight); + ofxToggle & setup(const std::string& toggleName, const Config & config); + ofxToggle & setup(ofParameter& _bVal, const Config & config); + ofxToggle & setup(ofParameter& _bVal, float width = defaultWidth, float height = defaultHeight); ofxToggle & setup(const std::string& toggleName, bool _bVal, float width = defaultWidth, float height = defaultHeight); - virtual bool mouseMoved(ofMouseEventArgs & args); virtual bool mousePressed(ofMouseEventArgs & args); virtual bool mouseDragged(ofMouseEventArgs & args); virtual bool mouseReleased(ofMouseEventArgs & args); virtual bool mouseScrolled(ofMouseEventArgs & args){return false;} - + template void addListener(ListenerClass * listener, ListenerMethod method){ @@ -48,9 +48,9 @@ class ofxToggle : public ofxBaseGui{ ofRectangle checkboxRect; ofParameter value; bool bGuiActive; - - bool setValue(float mx, float my, bool bCheck); - void generateDraw(); + + virtual bool setValue(float mx, float my, bool bCheck); + virtual void generateDraw(); void valueChanged(bool & value); ofPath bg,fg,cross; ofVboMesh textMesh; diff --git a/addons/ofxGui/src/ofxValuePlotter.cpp b/addons/ofxGui/src/ofxValuePlotter.cpp new file mode 100644 index 00000000000..486aa815b4b --- /dev/null +++ b/addons/ofxGui/src/ofxValuePlotter.cpp @@ -0,0 +1,119 @@ +#include "ofxValuePlotter.h" +#include "ofGraphics.h" +using namespace std; + +ofxValuePlotter::ofxValuePlotter(){ +} + +ofxValuePlotter::ofxValuePlotter(ofParameter value, const Config & config = Config()) : + ofxBaseGui(config){ + setup(config); + setName(value.getName()); +} + +ofxValuePlotter::~ofxValuePlotter(){ + value.removeListener(this,&ofxValuePlotter::valueChanged); +} + +ofxValuePlotter & ofxValuePlotter::setup(const Config & config){ + return setup("", config.minValue, config.maxValue, config.plotSize, config.shape.width, config.shape.height); +} + +ofxValuePlotter & ofxValuePlotter::setup(string label, float minValue, float maxValue, int plotSize, float width, float height){ + b.width = width; + b.height = height; + minVal = minValue; + maxVal = maxValue; + autoscale = minVal == maxVal; + buffer.clear(); + this->plotSize = plotSize; + value.addListener(this,&ofxValuePlotter::valueChanged); + setName(label); + setNeedsRedraw(); + return *this; +} + +void ofxValuePlotter::setDecimalPlace(int place){ + decimalPlace = place; +} + +void ofxValuePlotter::generateDraw(){ + + bg.clear(); + + bg.setFillColor(thisBackgroundColor); + bg.setFilled(true); + bg.rectangle(b); + + label = ofToString(value.get(), decimalPlace); + if(bShowName){ + label += " " + this->getName(); + } + + textMesh = getTextMesh(label, b.x + textPadding, b.y + b.height / 2 + 4); + + if(plotSize > 0){ + + plot.clear(); + if(minVal != maxVal && buffer.size() > 1){ + plot.moveTo(b.x, b.y + b.height); + unsigned int i; + for(i = 0; i < buffer.size(); i++){ + float x = ofMap(i, 0, buffer.size() - 1, b.x, b.x + b.width); + float y = ofMap(buffer[i], minVal, maxVal, b.y + b.height, b.y); + plot.lineTo(x, y); + } + plot.lineTo(b.x + b.width, b.y + b.height); + plot.close(); + plot.setFilled(true); + plot.setFillColor(thisFillColor); + } + } +} + +void ofxValuePlotter::render(){ + ofColor c = ofGetStyle().color; + + bg.draw(); + if(plotSize > 0){ + plot.draw(); + } + + ofBlendMode blendMode = ofGetStyle().blendingMode; + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableAlphaBlending(); + } + ofSetColor(textColor); + + bindFontTexture(); + textMesh.draw(); + unbindFontTexture(); + + ofSetColor(c); + if(blendMode != OF_BLENDMODE_ALPHA){ + ofEnableBlendMode(blendMode); + } +} + +ofAbstractParameter & ofxValuePlotter::getParameter(){ + return label; +} + +void ofxValuePlotter::valueChanged(float & value){ + if(plotSize > 0){ + buffer.push_back(value); + + if((int)buffer.size() > plotSize){ + buffer.erase(buffer.begin(), buffer.begin() + 1); + } + if(autoscale){ + if(value < minVal){ + minVal = value; + } + if(value > maxVal){ + maxVal = value; + } + } + } + setNeedsRedraw(); +} diff --git a/addons/ofxGui/src/ofxValuePlotter.h b/addons/ofxGui/src/ofxValuePlotter.h new file mode 100644 index 00000000000..f00dc375be5 --- /dev/null +++ b/addons/ofxGui/src/ofxValuePlotter.h @@ -0,0 +1,66 @@ +#pragma once + +#include "ofxBaseGui.h" + +class ofxValuePlotter : public ofxBaseGui { + public: + struct Config : public ofxBaseGui::Config { + Config(){ + } + Config(const typename ofxBaseGui::Config & c) : ofxBaseGui::Config(c){ + } + int decimalPlace = 3; + float minValue = 0; + float maxValue = 0; + int plotSize = 100; + }; + + ofxValuePlotter(); + ofxValuePlotter(ofParameter value, const Config & config); + virtual ~ofxValuePlotter(); + + ofxValuePlotter & setup(const Config & config); + ofxValuePlotter & setup(string label = "", float minValue = Config().minValue, float maxValue = Config().maxValue, int plotSize = Config().plotSize, float width = defaultWidth, float height = defaultHeight); + + void setDecimalPlace(int place); + + // Abstract methods we must implement, but have no need for! + virtual bool mouseMoved(ofMouseEventArgs & args){ + return false; + } + virtual bool mousePressed(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseDragged(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseReleased(ofMouseEventArgs & args){ + return false; + } + virtual bool mouseScrolled(ofMouseEventArgs & args){ + return false; + } + + virtual ofAbstractParameter & getParameter(); + + protected: + + bool setValue(float mx, float my, bool bCheckBounds){ + return false; + } + void render(); + void generateDraw(); + ofPath bg; + ofVboMesh textMesh; + vector buffer; + int plotSize; + ofPath plot; + float minVal, maxVal; + bool autoscale; + int decimalPlace; + ofParameter label; + ofParameter value; + + void valueChanged(float & value); + +}; diff --git a/addons/ofxKinect/README.md b/addons/ofxKinect/README.md index dd5ed50a27b..9779d55db6d 100644 --- a/addons/ofxKinect/README.md +++ b/addons/ofxKinect/README.md @@ -67,6 +67,13 @@ Also, you can add a set of udev rules which allow you to run a Kinect app withou Precompiled libfreenect drivers and libusb-win32 libs are included for Windows. +New install instructions: +However on some new Windows OS it might be a struggle to install + +The easiest way to add the drivers is to use the Free USB Driver tool: http://zadig.akeo.ie/ +Select your Xbox Camera, Xbox Audio and Xbox Motor in the drop down and then select the libusb-win32( v1.2.6.0 ) driver from the driver menu and click install. ( you will need to do this three times, once for the camera, then motor, then audio ). This advice comes from the https://github.com/OpenKinect/libfreenect#windows ReadMe. + +Old install instructions: Make sure to install or update the libfreenect Kinect camera, motor, and audio drivers through Windows Device Manager by pointing it to the driver folder:
 ofxKinect/libs/libfreenect/platform/windows/inf
@@ -160,35 +167,13 @@ Edit the Makefile config files:
 	
* repeat for the "Release" configuration -#### Windows (Codeblocks): +#### Windows (Msys2): -* add the ofxPd sources to the project: - * right-click on your project in the project tree - * select "Add Files Recursively ..." - * navigate and choose the ofxKinect/src folder -* add search paths and libraries to link: - * right-click on your project in the project tree - * select "Build options..." - * make sure the project name is selected in the tree (not release or debug) - * select the "Search directories" tab, click add the search paths: -
-	..\\..\\..\addons\ofxKinect\src
-	..\\..\\..\addons\ofxKinect\libs\libfreenect\src
-	..\\..\\..\addons\ofxKinect\libs\libfreenect\include
-	..\\..\\..\addons\ofxKinect\libs\libfreenect\platform\windows
-	..\\..\\..\addons\ofxKinect\libs\libfreenect\platform\windows\libusb10emu\libusb-1.0
-	..\\..\\..\addons\ofxKinect\libs\libusb-win32\include
-	
- * select the "Linker settings" tab, add the following to Link libraries: -
-	m
-	pthread
-	
- * select the "Linker settings" tab, add the following to Other liker options: -
-	..\..\..\addons\ofxKinect\libs\libusb-win32\lib\win_cb\libusb.lib
-	
+Install libusb using + pacman --needed -Sy mingw-w64-i686-libusb + + Notes ----- diff --git a/addons/ofxKinect/addon_config.mk b/addons/ofxKinect/addon_config.mk index d57ba48eb0c..adaae765b75 100644 --- a/addons/ofxKinect/addon_config.mk +++ b/addons/ofxKinect/addon_config.mk @@ -100,23 +100,22 @@ linux: ADDON_INCLUDES_EXCLUDE += libs/libusb-win32/% ADDON_INCLUDES_EXCLUDE += libs/libusb-1.0/% -win_cb: - # source files, these will be usually parsed from the file system looking - # in the src folders in libs and the root of the addon. if your addon needs - # to include files in different places or a different set of files per platform - # they can be specified here - ADDON_SOURCES += libs/libfreenect/platform/windows/libusb10emu/libusb-1.0/failguard.cpp - ADDON_SOURCES += libs/libfreenect/platform/windows/libusb10emu/libusb-1.0/libusbemu.cpp +msys2: + # any library that should be included in the project using pkg-config + ADDON_PKG_CONFIG_LIBRARIES = libusb-1.0 + + # when parsing the file system looking for sources exclude this for all or + # a specific platform + ADDON_SOURCES_EXCLUDE = libs/libfreenect/platform/% + ADDON_SOURCES_EXCLUDE += libs/libusb-win32/% - # include search paths, this will be usually parsed from the file system - # but if the addon or addon libraries need special search paths they can be - # specified here separated by spaces or one per line using += - ADDON_INCLUDES += libs/libfreenect/platform/windows - # when parsing the file system looking for include paths exclude this for all or # a specific platform + ADDON_INCLUDES_EXCLUDE = libs/libfreenect/platform/% + ADDON_INCLUDES_EXCLUDE += libs/libusb-win32/% ADDON_INCLUDES_EXCLUDE += libs/libusb-1.0/% + vs: # source files, these will be usually parsed from the file system looking # in the src folders in libs and the root of the addon. if your addon needs diff --git a/addons/ofxKinect/libs/libusb-win32/lib/vs/libusb.lib b/addons/ofxKinect/libs/libusb-win32/lib/msys2/libusb.lib similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/lib/vs/libusb.lib rename to addons/ofxKinect/libs/libusb-win32/lib/msys2/libusb.lib diff --git a/addons/ofxKinect/libs/libusb-win32/lib/vs/libusbd.lib b/addons/ofxKinect/libs/libusb-win32/lib/msys2/libusbd.lib similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/lib/vs/libusbd.lib rename to addons/ofxKinect/libs/libusb-win32/lib/msys2/libusbd.lib diff --git a/addons/ofxKinect/libs/libusb-win32/lib/win_cb/libusb.lib b/addons/ofxKinect/libs/libusb-win32/lib/vs/Win32/libusb.lib similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/lib/win_cb/libusb.lib rename to addons/ofxKinect/libs/libusb-win32/lib/vs/Win32/libusb.lib diff --git a/addons/ofxKinect/libs/libusb-win32/lib/win_cb/libusbd.lib b/addons/ofxKinect/libs/libusb-win32/lib/vs/Win32/libusbd.lib similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/lib/win_cb/libusbd.lib rename to addons/ofxKinect/libs/libusb-win32/lib/vs/Win32/libusbd.lib diff --git a/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusb.lib b/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusb.lib new file mode 100644 index 00000000000..dfdaad05d14 Binary files /dev/null and b/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusb.lib differ diff --git a/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusbd.lib b/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusbd.lib new file mode 100644 index 00000000000..39750184a24 Binary files /dev/null and b/addons/ofxKinect/libs/libusb-win32/lib/vs/x64/libusbd.lib differ diff --git a/addons/ofxKinect/libs/libusb-win32/AUTHORS.txt b/addons/ofxKinect/libs/libusb-win32/license/AUTHORS.txt similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/AUTHORS.txt rename to addons/ofxKinect/libs/libusb-win32/license/AUTHORS.txt diff --git a/addons/ofxKinect/libs/libusb-win32/COPYING_LGPL.txt b/addons/ofxKinect/libs/libusb-win32/license/COPYING_LGPL.txt similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/COPYING_LGPL.txt rename to addons/ofxKinect/libs/libusb-win32/license/COPYING_LGPL.txt diff --git a/addons/ofxKinect/libs/libusb-win32/README.txt b/addons/ofxKinect/libs/libusb-win32/license/README.txt similarity index 100% rename from addons/ofxKinect/libs/libusb-win32/README.txt rename to addons/ofxKinect/libs/libusb-win32/license/README.txt diff --git a/addons/ofxKinect/scripts/libfreenect.sh b/addons/ofxKinect/scripts/libfreenect.sh new file mode 100644 index 00000000000..4a186e5ca45 --- /dev/null +++ b/addons/ofxKinect/scripts/libfreenect.sh @@ -0,0 +1,70 @@ +#! /bin/bash + + +SRC=libfreenect + +GIT_URL=https://github.com/wizgrav/libfreenect +GIT_TAG=master + +# download the source code and unpack it into LIB_NAME +function download() { + # get latest source + + curl -Lk $GIT_URL/archive/master.tar.gz -o libfreenect-$GIT_TAG.tar.gz + tar -xf libfreenect-$GIT_TAG.tar.gz + mv libfreenect-$GIT_TAG libfreenect + rm libfreenect-$GIT_TAG.tar.gz +} + +# prepare the build environment, executed inside the lib src dir +function prepare() { + echo "The current working directory: $PWD" + # remove uneeded makefiles + rm src/CMakeLists.txt + rm src/libfreenect.pc.in + + # we dont need freenect audio + rm include/libfreenect-audio.h + rm src/audio.c + rm src/loader.c + + # no python either + rm src/fwfetcher.py +} + +# executed inside the lib src dir +function build() { + echo "Nothing to build for freenect" +} + +# executed inside the lib src dir, first arg $1 is the dest libs dir root +function copy() { + # make folders + mkdir -p $1/include + mkdir -p $1/src + mkdir -p $1/platform + + # copy licenses, etc + rm -rf $1/license # remove any older files if exists + mkdir -p $1/license + + cp -v APACHE20 $1/license/ + cp -v CONTRIB $1/license/ + cp -v GPL2 $1/license/ + + # copy headers + cp -Rv include/* $1/include + + # copy sources + cp -Rv src/* $1/src + + # copy platform specfic stuff + cp -Rv platform/linux $1/platform + cp -Rv platform/windows $1/platform +} + +# executed inside the lib src dir +function clean() { + # cleanup + rm -rf $SRC +} diff --git a/addons/ofxKinect/scripts/libusb.sh b/addons/ofxKinect/scripts/libusb.sh new file mode 100644 index 00000000000..c2feab8ac1a --- /dev/null +++ b/addons/ofxKinect/scripts/libusb.sh @@ -0,0 +1,78 @@ +#! /bin/bash + +VER=1.2.6.0 + +SRC=libusb-win32-bin-$VER + +### +FORMULA_TYPES=( "vs" "win-cb" ) + +# download the source code and unpack it into LIB_NAME +function download() { + ### Debug + # get source + curl -LO http://downloads.sourceforge.net/project/libusb-win32/libusb-win32-releases/$VER/libusb-win32-bin-debug-$VER.zip + unzip -oq libusb-win32-bin-debug-$VER.zip + + mv "libusb-win32-bin-$VER" libusb-debug + + # get source + curl -LO http://downloads.sourceforge.net/project/libusb-win32/libusb-win32-releases/$VER/$SRC.zip + unzip -oq $SRC.zip + + mv "libusb-win32-bin-$VER" libusb + rm "libusb-win32-bin-$VER.zip" + rm "libusb-win32-bin-debug-$VER.zip" +} + +# prepare the build environment, executed inside the lib src dir +function prepare() { + echo "Nothing to prepare for libusb" +} + +# executed inside the lib src dir +function build() { + echo "Nothing to build for libusb" +} + +# executed inside the lib src dir, first arg $1 is the dest libs dir root +function copy() { + cd .. + + # make folders + mkdir -p $1/include + mkdir -p $1/lib/vs/Win32 + mkdir -p $1/lib/vs/x64 + mkdir -p $1/lib/msys2 + + # copy libs + cp -v libusb-debug/lib/msvc/libusb.lib $1/lib/vs/Win32/libusbd.lib + cp -v libusb-debug/lib/msvc_x64/libusb.lib $1/lib/vs/x64/libusbd.lib + cp -v libusb-debug/lib/msvc/libusb.lib $1/lib/msys2/libusbd.lib + + ### Release + + # copy licenses, etc + rm -rf $1/license # remove any older files if exists + mkdir -p $1/license + + cp -v libusb/AUTHORS.txt $1/license/ + cp -v libusb/COPYING_LGPL.txt $1/license/ + cp -v libusb/README.txt $1/license/ + + # copy headers + cp -Rv libusb/include/* $1/include + + # copy libs + cp -v libusb/lib/msvc/libusb.lib $1/lib/vs/Win32 + cp -v libusb/lib/msvc_x64/libusb.lib $1/lib/vs/x64 + cp -v libusb/lib/msvc/libusb.lib $1/lib/msys2 +} + +# executed inside the lib src dir +function clean() { + + # cleanup + rm libusb + rm libusb-debug +} \ No newline at end of file diff --git a/addons/ofxKinect/scripts/update_freenect.sh b/addons/ofxKinect/scripts/update_freenect.sh deleted file mode 100755 index 87065102eac..00000000000 --- a/addons/ofxKinect/scripts/update_freenect.sh +++ /dev/null @@ -1,49 +0,0 @@ -#! /bin/bash - -WD=$(dirname $0) - -DEST=../libs/libfreenect -SRC=libfreenect - -### - -cd $WD - -# get latest source -#git clone git://github.com/OpenKinect/libfreenect.git -git clone git://github.com/wizgrav/libfreenect.git - -# remove uneeded makefiles -rm $SRC/src/CMakeLists.txt -rm $SRC/src/libfreenect.pc.in - -# we dont need freenect audio -rm $SRC/include/libfreenect-audio.h -rm $SRC/src/audio.c -rm $SRC/src/loader.c - -# no python either -rm $SRC/src/fwfetcher.py - -# make folders -mkdir -p $DEST/include -mkdir -p $DEST/src -mkdir -p $DEST/platform - -# copy licenses, etc -cp -v $SRC/APACHE20 $DEST -cp -v $SRC/CONTRIB $DEST -cp -v $SRC/GPL2 $DEST - -# copy headers -cp -Rv $SRC/include/* $DEST/include - -# copy sources -cp -Rv $SRC/src/* $DEST/src - -# copy platform specfic stuff -cp -Rv $SRC/platform/linux $DEST/platform -cp -Rv $SRC/platform/windows $DEST/platform - -# cleanup -rm -rf $SRC diff --git a/addons/ofxKinect/scripts/update_libusb-win32.sh b/addons/ofxKinect/scripts/update_libusb-win32.sh deleted file mode 100755 index f76a904c483..00000000000 --- a/addons/ofxKinect/scripts/update_libusb-win32.sh +++ /dev/null @@ -1,53 +0,0 @@ -#! /bin/bash - -WD=$(dirname $0) - -VER=1.2.6.0 - -DEST=../libs/libusb-win32 -SRC=libusb-win32-bin-$VER - -### - -cd $WD - -# make folders -mkdir -p $DEST/include -mkdir -p $DEST/lib/vs2010 -mkdir -p $DEST/lib/win_cb - -### Debug - -# get source -curl -LO http://downloads.sourceforge.net/project/libusb-win32/libusb-win32-releases/$VER/libusb-win32-bin-debug-$VER.zip -unzip -oq libusb-win32-bin-debug-$VER.zip - -# copy libs -cp -v $SRC/lib/msvc/libusb.lib $DEST/lib/vs2010/libusbd.lib -cp -v $SRC/lib/msvc/libusb.lib $DEST/lib/win_cb/libusbd.lib - -# cleanup -rm -rf libusb-win32-bin-debug-$VER -rm libusb-win32-bin-debug-$VER.zip - -### Release - -# get source -curl -LO http://downloads.sourceforge.net/project/libusb-win32/libusb-win32-releases/$VER/$SRC.zip -unzip -oq $SRC.zip - -# copy licenses, etc -cp -v $SRC/AUTHORS.txt $DEST -cp -v $SRC/COPYING_LGPL.txt $DEST -cp -v $SRC/README.txt $DEST - -# copy headers -cp -Rv $SRC/include/* $DEST/include - -# copy libs -cp -v $SRC/lib/msvc/libusb.lib $DEST/lib/vs2010 -cp -v $SRC/lib/msvc/libusb.lib $DEST/lib/win_cb - -# cleanup -rm -rf $SRC -rm $SRC.zip \ No newline at end of file diff --git a/addons/ofxKinect/src/ofxKinect.cpp b/addons/ofxKinect/src/ofxKinect.cpp index 3db2338c751..95fbdd323e6 100644 --- a/addons/ofxKinect/src/ofxKinect.cpp +++ b/addons/ofxKinect/src/ofxKinect.cpp @@ -144,8 +144,8 @@ bool ofxKinect::init(bool infrared, bool video, bool texture) { distancePixels.set(0); if(bUseTexture) { - depthTex.allocate(width, height, GL_LUMINANCE); - videoTex.allocate(width, height, infrared ? GL_LUMINANCE : GL_RGB); + depthTex.allocate(depthPixels); + videoTex.allocate(videoPixels); } if(!kinectContext.isInited()) { @@ -364,7 +364,7 @@ void ofxKinect::update() { } if(bUseTexture) { - videoTex.loadData(videoPixels.getData(), width, height, bIsVideoInfrared?GL_LUMINANCE:GL_RGB); + videoTex.loadData(videoPixels); } } else { bIsFrameNewVideo = false; @@ -383,7 +383,7 @@ void ofxKinect::update() { } if(bUseTexture) { - depthTex.loadData(depthPixels.getData(), width, height, GL_LUMINANCE); + depthTex.loadData(depthPixels); } } else { bIsFrameNewDepth = false; diff --git a/addons/ofxMultiTouch/LICENSE.txt b/addons/ofxMultiTouch/LICENSE.txt deleted file mode 100644 index f4fc80e13cc..00000000000 --- a/addons/ofxMultiTouch/LICENSE.txt +++ /dev/null @@ -1,30 +0,0 @@ -/*********************************************************************** - - Copyright (c) 2008, 2009, Memo Akten, www.memo.tv - *** The Mega Super Awesome Visuals Company *** - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of MSA Visuals nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***********************************************************************/ \ No newline at end of file diff --git a/addons/ofxMultiTouch/changelog.txt b/addons/ofxMultiTouch/changelog.txt deleted file mode 100644 index 2455bee3696..00000000000 --- a/addons/ofxMultiTouch/changelog.txt +++ /dev/null @@ -1,21 +0,0 @@ -ofxMultiTouch changelog - - -v0.4 07/04/2009 --------------------- -- changed license to revised BSD (a lot more more permissive than GPL) - - -v0.3 --------------------- -- IMPORTANT: ofxMultiTouchListener now takes (x,y) as float, NOT int - - -v0.2 --------------------- -- added custom touch info data - - -v0.1 --------------------- -- initial version diff --git a/addons/ofxMultiTouch/src/ofxMultiTouch.cpp b/addons/ofxMultiTouch/src/ofxMultiTouch.cpp deleted file mode 100644 index d370bd1f4a6..00000000000 --- a/addons/ofxMultiTouch/src/ofxMultiTouch.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*********************************************************************** - - Copyright (c) 2008, 2009, Memo Akten, www.memo.tv - *** The Mega Super Awesome Visuals Company *** - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of MSA Visuals nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***********************************************************************/ - - -#include "ofxMultiTouch.h" -#include "ofxiOSApp.h" - -ofxMultiTouchHandler ofxMultiTouch; - -void ofxRegisterMultitouch(ofxiOSApp * app){ - ofAddListener(ofEvents().touchDown, app, &ofxiOSApp::touchDown); - ofAddListener(ofEvents().touchUp, app, &ofxiOSApp::touchUp); - ofAddListener(ofEvents().touchMoved, app, &ofxiOSApp::touchMoved); - ofAddListener(ofEvents().touchDoubleTap, app, &ofxiOSApp::touchDoubleTap); - ofAddListener(ofEvents().touchCancelled, app, &ofxiOSApp::touchCancelled); -} - -void ofxUnregisterMultitouch(ofxiOSApp * app){ - ofRemoveListener(ofEvents().touchDown, app, &ofxiOSApp::touchDown); - ofRemoveListener(ofEvents().touchUp, app, &ofxiOSApp::touchUp); - ofRemoveListener(ofEvents().touchMoved, app, &ofxiOSApp::touchMoved); - ofRemoveListener(ofEvents().touchDoubleTap, app, &ofxiOSApp::touchDoubleTap); - ofRemoveListener(ofEvents().touchCancelled, app, &ofxiOSApp::touchCancelled); -} \ No newline at end of file diff --git a/addons/ofxMultiTouch/src/ofxMultiTouch.h b/addons/ofxMultiTouch/src/ofxMultiTouch.h deleted file mode 100644 index a1c87ce5454..00000000000 --- a/addons/ofxMultiTouch/src/ofxMultiTouch.h +++ /dev/null @@ -1,69 +0,0 @@ -/*********************************************************************** - - Copyright (c) 2008, 2009, Memo Akten, www.memo.tv - *** The Mega Super Awesome Visuals Company *** - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of MSA Visuals nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***********************************************************************/ - - -#pragma once - -#include "ofMain.h" -#include "ofxMultiTouchListener.h" - -class ofxMultiTouchHandler : public ofxMultiTouchListener { -public: - void addListener(ofxMultiTouchListener* o) { -// listeners.push_back(o); -// o->registerTouchEvents(); - ofAddListener(ofEvents().touchDown, o, &ofxMultiTouchListener::_touchDown); - ofAddListener(ofEvents().touchUp, o, &ofxMultiTouchListener::_touchUp); - ofAddListener(ofEvents().touchMoved, o, &ofxMultiTouchListener::_touchMoved); - ofAddListener(ofEvents().touchDoubleTap, o, &ofxMultiTouchListener::_touchDoubleTap); - ofAddListener(ofEvents().touchCancelled, o, &ofxMultiTouchListener::_touchCancelled); - } - - void removeListener(ofxMultiTouchListener* o) { -// listeners.remove(o); -// o->unregisterTouchEvents(); - ofRemoveListener(ofEvents().touchDown, o, &ofxMultiTouchListener::_touchDown); - ofRemoveListener(ofEvents().touchUp, o, &ofxMultiTouchListener::_touchUp); - ofRemoveListener(ofEvents().touchMoved, o, &ofxMultiTouchListener::_touchMoved); - ofRemoveListener(ofEvents().touchDoubleTap, o, &ofxMultiTouchListener::_touchDoubleTap); - ofRemoveListener(ofEvents().touchCancelled, o, &ofxMultiTouchListener::_touchCancelled); - } - - -}; - -class ofxiOSApp; - -void ofxRegisterMultitouch(ofxiOSApp * app); -void ofxUnregisterMultitouch(ofxiOSApp * app); - -extern ofxMultiTouchHandler ofxMultiTouch; - diff --git a/addons/ofxMultiTouch/src/ofxMultiTouchListener.h b/addons/ofxMultiTouch/src/ofxMultiTouchListener.h deleted file mode 100644 index 339c063209f..00000000000 --- a/addons/ofxMultiTouch/src/ofxMultiTouchListener.h +++ /dev/null @@ -1,69 +0,0 @@ -/*********************************************************************** - - Copyright (c) 2008, 2009, Memo Akten, www.memo.tv - *** The Mega Super Awesome Visuals Company *** - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of MSA Visuals nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***********************************************************************/ - -#pragma once - -#include "ofEvents.h" - -// contains custom data which specific implementations can override and add to -//struct ofxMultiTouchCustomData { -// int numTouches; -//}; - -#define ofxMultiTouchCustomData ofTouchEventArgs - -/****** protocol, delegate, interface, whatever you want to call it ******/ -class ofxMultiTouchListener /*: ofTouchListener*/ { -public: - virtual ~ofxMultiTouchListener() {} - - virtual void touchDown(float x, float y, int touchId) {} - virtual void touchMoved(float x, float y, int touchId) {} - virtual void touchUp(float x, float y, int touchId) {} - virtual void touchDoubleTap(float x, float y, int touchId) {} - virtual void touchCancelled(float x, float y, int touchId) {} - - virtual void _touchDown(ofTouchEventArgs & touch){ - touchDown(touch.x,touch.y,touch.id); - } - virtual void _touchMoved(ofTouchEventArgs & touch){ - touchMoved(touch.x,touch.y,touch.id); - } - virtual void _touchUp(ofTouchEventArgs & touch){ - touchUp(touch.x,touch.y,touch.id); - } - virtual void _touchDoubleTap(ofTouchEventArgs & touch){ - touchDoubleTap(touch.x,touch.y,touch.id); - } - virtual void _touchCancelled(ofTouchEventArgs & touch){ - touchCancelled(touch.x,touch.y,touch.id); - } -}; diff --git a/addons/ofxNetwork/src/ofxNetworkUtils.h b/addons/ofxNetwork/src/ofxNetworkUtils.h index 6244f6b6605..7b11be45c49 100644 --- a/addons/ofxNetwork/src/ofxNetworkUtils.h +++ b/addons/ofxNetwork/src/ofxNetworkUtils.h @@ -19,9 +19,9 @@ #endif -#define ofxNetworkCheckError() ofxNetworkCheckErrno(__FILE__,ofToString(__LINE__)) +#define ofxNetworkCheckError() ofxNetworkCheckErrno(__FILE__, __LINE__) -inline int ofxNetworkCheckErrno(const string & file, const string & line){ +inline int ofxNetworkCheckErrno(const char* file, int line) { #ifdef TARGET_WIN32 int err = WSAGetLastError(); #else @@ -36,9 +36,9 @@ inline int ofxNetworkCheckErrno(const string & file, const string & line){ case OFXNETWORK_ERROR(CONNRESET): ofLogError("ofxNetwork") << file << ": " << line << " ECONNRESET: connection closed by peer"; break; - case OFXNETWORK_ERROR(INTR): - ofLogError("ofxNetwork") << file << ": " << line << " EINTR: receive interrupted by a signal, before any data available"; - break; + case OFXNETWORK_ERROR(CONNABORTED): + ofLogError("ofxNetwork") << file << ": " << line << " ECONNABORTED: connection aborted by peer"; + break; case OFXNETWORK_ERROR(NOTCONN): ofLogError("ofxNetwork") << file << ": " << line << " ENOTCONN: trying to receive before establishing a connection"; break; @@ -80,12 +80,6 @@ inline int ofxNetworkCheckErrno(const string & file, const string & line){ case OFXNETWORK_ERROR(ADDRINUSE): ofLogError("ofxNetwork") << file << ": " << line << " EADDRINUSE: the socket address of the given addr is already in use"; break; - case OFXNETWORK_ERROR(INPROGRESS): - ofLogWarning("ofxNetwork") << file << ": " << line << " EINPROGRESS: the socket is non-blocking and the connection could not be established immediately"; - break; - case EALREADY: - ofLogError("ofxNetwork") << file << ": " << line << " EALREADY: the socket is non-blocking and already has a pending connection in progress"; - break; case ENOPROTOOPT: ofLogError("ofxNetwork") << file << ": " << line << " ENOPROTOOPT: the optname doesn't make sense for the given level"; break; @@ -115,12 +109,23 @@ inline int ofxNetworkCheckErrno(const string & file, const string & line){ ofLogError("ofxNetwork") << file << ": " << line << " EINVAL: invalid argument"; break; #if !defined(TARGET_WIN32) - case OFXNETWORK_ERROR(AGAIN): +#if !defined(EWOULDBLOCK) || EAGAIN != EWOULDBLOCK + case EAGAIN: + // Not an error worth reporting, this is normal if the socket is non-blocking //ofLogError("ofxNetwork") << file << ": " << line << " EAGAIN: try again"; break; #endif +#endif + case OFXNETWORK_ERROR(WOULDBLOCK): + case OFXNETWORK_ERROR(INPROGRESS): + case OFXNETWORK_ERROR(ALREADY): + // Not an error worth reporting, this is normal if the socket is non-blocking + break; + case OFXNETWORK_ERROR(INTR): + //ofLogError("ofxNetwork") << file << ": " << line << " EINTR: receive interrupted by a signal, before any data available"; + break; default: - ofLogError("ofxNetwork") << file << ": " << line << " unknown error: " << err << " see errno.h for description of the error"; + ofLogVerbose("ofxNetwork") << file << ": " << line << " unknown error: " << err << " see errno.h for description of the error"; break; } diff --git a/addons/ofxNetwork/src/ofxTCPClient.cpp b/addons/ofxNetwork/src/ofxTCPClient.cpp index 20e9e5c2b48..96a9523c2ec 100644 --- a/addons/ofxNetwork/src/ofxTCPClient.cpp +++ b/addons/ofxNetwork/src/ofxTCPClient.cpp @@ -51,7 +51,7 @@ bool ofxTCPClient::setup(string ip, int _port, bool blocking){ //don't use this one //for server to use internally only! //-------------------------- -bool ofxTCPClient::setup(int _index, bool blocking){ +bool ofxTCPClient::setupConnectionIdx(int _index, bool blocking){ index = _index; //this fetches the port that the server @@ -72,11 +72,11 @@ bool ofxTCPClient::setup(int _index, bool blocking){ //-------------------------- bool ofxTCPClient::close(){ if( connected ){ - if( !TCPClient.Close() ){ ofLogError("ofxTCPClient") << "close(): couldn't close client"; return false; }else{ + ofLogVerbose("ofxTCPClient") << "closing client"; connected = false; return true; } @@ -107,7 +107,9 @@ bool ofxTCPClient::send(string message){ message = partialPrevMsg + message + messageDelimiter; message += (char)0; //for flash int ret = TCPClient.SendAll( message.c_str(), message.length() ); - if( ret == 0 ){ + int errorCode = 0; + if(ret<0) errorCode = ofxNetworkCheckError(); + if( isClosingCondition(ret, errorCode) ){ ofLogWarning("ofxTCPClient") << "send(): client disconnected"; close(); return false; @@ -127,6 +129,7 @@ bool ofxTCPClient::send(string message){ } } +//-------------------------- bool ofxTCPClient::sendRawMsg(const char * msg, int size){ // tcp is a stream oriented protocol @@ -142,8 +145,10 @@ bool ofxTCPClient::sendRawMsg(const char * msg, int size){ tmpBuffSend.append(msg,size); tmpBuffSend.append(messageDelimiter.c_str(),messageDelimiter.size()); - int ret = TCPClient.SendAll( tmpBuffSend.getData(), tmpBuffSend.size() ); - if( ret == 0 ){ + int ret = TCPClient.SendAll( tmpBuffSend.getData(), tmpBuffSend.size() ); + int errorCode = 0; + if(ret<0) errorCode = ofxNetworkCheckError(); + if( isClosingCondition(ret, errorCode) ){ ofLogWarning("ofxTCPClient") << "sendRawMsg(): client disconnected"; close(); return false; @@ -166,26 +171,30 @@ bool ofxTCPClient::sendRawMsg(const char * msg, int size){ //-------------------------- bool ofxTCPClient::sendRaw(string message){ if( message.length() == 0) return false; - - if( !TCPClient.SendAll(message.c_str(), message.length()) ){ + int ret = TCPClient.SendAll(message.c_str(), message.length()); + int errorCode = 0; + if(ret<0) errorCode = ofxNetworkCheckError(); + if( isClosingCondition(ret, errorCode) ){ ofLogError("ofxTCPClient") << "sendRawBytes(): sending failed"; close(); return false; }else{ - return true; + return ret > 0; } } //-------------------------- bool ofxTCPClient::sendRawBytes(const char* rawBytes, const int numBytes){ if( numBytes <= 0) return false; - - if( !TCPClient.SendAll(rawBytes, numBytes) ){ + int ret = TCPClient.SendAll(rawBytes, numBytes); + int errorCode = 0; + if(ret<0) errorCode = ofxNetworkCheckError(); + if( isClosingCondition(ret, errorCode) ){ ofLogError("ofxTCPClient") << "sendRawBytes(): sending failed"; close(); return false; }else{ - return true; + return ret > 0; } } @@ -209,10 +218,15 @@ static void removeZeros(char * buffer, int size){ } //-------------------------- -string ofxTCPClient::receive(){ +bool ofxTCPClient::isClosingCondition(int messageSize, int errorCode){ + return (messageSize == SOCKET_ERROR && (errorCode == OFXNETWORK_ERROR(CONNRESET) || errorCode == OFXNETWORK_ERROR(CONNABORTED) || errorCode == OFXNETWORK_ERROR(CONNREFUSED) || errorCode == EPIPE || errorCode == OFXNETWORK_ERROR(NOTCONN))) + || (messageSize == 0 && !TCPClient.IsNonBlocking() && TCPClient.GetTimeoutReceive()!=NO_TIMEOUT); +} +//-------------------------- +string ofxTCPClient::receive(){ str = ""; - int length=-2; + int length=0; //only get data from the buffer if we don't have already some complete message if(tmpStr.find(messageDelimiter)==string::npos){ memset(tmpBuff, 0, TCP_MAX_MSG_SIZE+1); //one more so there's always a \0 at the end for string concat @@ -223,9 +237,10 @@ string ofxTCPClient::receive(){ } } - // check for connection reset or disconnection - int errorCode = ofxNetworkCheckError(); - if((length==-1 && ( errorCode == ECONNRESET || errorCode == ECONNABORTED )) || length == 0){ + // check for connection reset or disconnection + int errorCode = 0; + if(length<0) errorCode = ofxNetworkCheckError(); + if(isClosingCondition(length,errorCode)){ close(); if(tmpStr.length()==0) // return if there's no more data left in the buffer return ""; @@ -239,7 +254,7 @@ string ofxTCPClient::receive(){ return str; } - +//-------------------------- static int findDelimiter(char * data, int size, string delimiter){ unsigned int posInDelimiter=0; for(int i=0;i=0 && messageSizeh_addr); // set to non-blocking before connect - #ifdef TARGET_WIN32 - unsigned long iMode = 1; - if (m_dwTimeoutConnect != NO_TIMEOUT) ioctlsocket(m_hSocket, FIONBIO, &iMode); - #else - if (m_dwTimeoutConnect != NO_TIMEOUT) fcntl(m_hSocket, F_SETFL, O_NONBLOCK); - #endif + bool wasBlocking = nonBlocking; + if(m_dwTimeoutConnect != NO_TIMEOUT){ + SetNonBlocking(true); + } - bool ret = (connect(m_hSocket, (sockaddr *)&addr_in, sizeof(sockaddr)) != SOCKET_ERROR); - + int ret = connect(m_hSocket, (sockaddr *)&addr_in, sizeof(sockaddr)); + int err = 0; + if(ret<0) err = ofxNetworkCheckError(); // set a timeout - if (m_dwTimeoutConnect != NO_TIMEOUT) { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutConnect, 0}; - fd_set fdset; - if(select(m_hSocket+1,NULL,&fd,NULL,&tv)== 1) { - int so_error; - socklen_t len = sizeof so_error; - getsockopt(m_hSocket, SOL_SOCKET, SO_ERROR, (char*)&so_error, &len); - if (so_error == 0) { - return true; + if (ret < 0 && (err == OFXNETWORK_ERROR(INPROGRESS) || err == OFXNETWORK_ERROR(WOULDBLOCK)) && m_dwTimeoutConnect != NO_TIMEOUT) { + ret = WaitSend(m_dwTimeoutConnect, 0); + if(ret == 0) { + socklen_t len = sizeof err; + if (getsockopt(m_hSocket, SOL_SOCKET, SO_ERROR, (char*)&err, &len)<0){ + ret = SOCKET_ERROR; + }else if(err != 0) { + ret = SOCKET_ERROR; } - } + } } + + if(m_dwTimeoutConnect != NO_TIMEOUT){ + SetNonBlocking(wasBlocking); + } - if(!ret) ofxNetworkCheckError(); - return ret; + return ret>=0; +} + +//-------------------------------------------------------------------------------- +int ofxTCPManager::WaitReceive(time_t timeoutSeconds, time_t timeoutMicros){ + if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR; + + fd_set fd; + FD_ZERO(&fd); + FD_SET(m_hSocket, &fd); + timeval tv; + tv.tv_sec = timeoutSeconds; + tv.tv_usec = timeoutMicros; + auto ret = select(m_hSocket+1,&fd,NULL,NULL,&tv); + if(ret == 0){ + return SOCKET_TIMEOUT; + }else if(ret < 0){ + return SOCKET_ERROR; + }else{ + return 0; + } +} + +//-------------------------------------------------------------------------------- +int ofxTCPManager::WaitSend(time_t timeoutSeconds, time_t timeoutMicros){ + if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR; + + fd_set fd; + FD_ZERO(&fd); + FD_SET(m_hSocket, &fd); + timeval tv; + tv.tv_sec = timeoutSeconds; + tv.tv_usec = timeoutMicros; + auto ret = select(m_hSocket+1,NULL,&fd,NULL,&tv); + if(ret == 0){ + return SOCKET_TIMEOUT; + }else if(ret < 0){ + return SOCKET_ERROR; + }else{ + return 0; + } } //-------------------------------------------------------------------------------- -///Theo added - Choose to set nonBLocking - default mode is to block bool ofxTCPManager::SetNonBlocking(bool useNonBlocking) { - nonBlocking = useNonBlocking; + if(useNonBlocking==nonBlocking){ + return true; + } + auto prevNonBlocking = nonBlocking; + nonBlocking = useNonBlocking; #ifdef TARGET_WIN32 unsigned long arg = nonBlocking; int retVal = ioctlsocket(m_hSocket,FIONBIO,&arg); #else - int arg = nonBlocking; - int retVal = ioctl(m_hSocket,FIONBIO,&arg); + int flags = fcntl(m_hSocket, F_GETFL, 0); + int retVal; + if(useNonBlocking){ + retVal = fcntl(m_hSocket, F_SETFL, flags | O_NONBLOCK); + }else{ + retVal = fcntl(m_hSocket, F_SETFL, flags & ~O_NONBLOCK); + } #endif bool ret = (retVal >= 0); - if(!ret) ofxNetworkCheckError(); + if(!ret){ + ofxNetworkCheckError(); + nonBlocking = prevNonBlocking; + } return ret; } +bool ofxTCPManager::IsNonBlocking(){ + return nonBlocking; +} + //-------------------------------------------------------------------------------- int ofxTCPManager::Write(const char* pBuff, const int iSize) { @@ -224,33 +321,18 @@ int ofxTCPManager::Write(const char* pBuff, const int iSize) int iBytesTemp; const char* pTemp= pBuff; - do { - iBytesTemp= Send(pTemp, iSize - iBytesSent); - // error occured? - if (iBytesTemp == SOCKET_ERROR) return(SOCKET_ERROR); - if (iBytesTemp == SOCKET_TIMEOUT) return(SOCKET_TIMEOUT); + do { + iBytesTemp= Send(pTemp, iSize - iBytesSent); + // error occured? + if (iBytesTemp == SOCKET_ERROR) return(SOCKET_ERROR); + if (iBytesTemp == SOCKET_TIMEOUT) return(SOCKET_TIMEOUT); iBytesSent+= iBytesTemp; pTemp+= iBytesTemp; } while(iBytesSent < iSize); - return(iBytesSent); -} - -//-------------------------------------------------------------------------------- -//Theo added - alternative to GetTickCount for windows -//This version returns the milliseconds since the unix epoch -//Should be good enough for what it is being used for here -//(mainly time comparision) -#ifndef TARGET_WIN32 -unsigned long GetTickCount(){ - timeb bsdTime; - ftime(&bsdTime); - - unsigned long msSinceUnix = (bsdTime.time*1000) + bsdTime.millitm; - return msSinceUnix; + return(iBytesSent); } -#endif //-------------------------------------------------------------------------------- /// Return values: @@ -258,22 +340,15 @@ unsigned long GetTickCount(){ /// SOCKET_ERROR in case of a problem. int ofxTCPManager::Send(const char* pBuff, const int iSize) { - if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - - if (m_dwTimeoutSend != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,NULL,&fd,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); + if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); + + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto ret = WaitSend(m_dwTimeoutSend,0); + if(ret!=0){ + return ret; } } - int ret = send(m_hSocket, pBuff, iSize, 0); - if(ret==-1) ofxNetworkCheckError(); - return ret; + return send(m_hSocket, pBuff, iSize, 0); } //-------------------------------------------------------------------------------- @@ -282,40 +357,41 @@ int ofxTCPManager::Send(const char* pBuff, const int iSize) /// SOCKET_ERROR in case of a problem. int ofxTCPManager::SendAll(const char* pBuff, const int iSize) { - if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - - - unsigned long timestamp= GetTickCount(); - - if (m_dwTimeoutSend != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,NULL,&fd,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); - } - } + if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); + auto timestamp = ofGetElapsedTimeMicros(); + auto timeleftSecs = m_dwTimeoutSend; + auto timeleftMicros = 0; int total= 0; int bytesleft = iSize; int ret=-1; - int err = 0; - while (total < iSize) { + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto ret = WaitSend(timeleftSecs,timeleftMicros); + if(ret!=0){ + return ret; + } + } ret = send(m_hSocket, pBuff + total, bytesleft, 0); - if (ret == -1) { err = ofxNetworkCheckError(); break; } + if (ret == SOCKET_ERROR) { + return SOCKET_ERROR; + } total += ret; bytesleft -=ret; - if (GetTickCount() - timestamp > m_dwTimeoutSend * 1000) return SOCKET_TIMEOUT; + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto now = ofGetElapsedTimeMicros(); + auto diff = now - timestamp; + if (diff > m_dwTimeoutSend * 1000000){ + return SOCKET_TIMEOUT; + } + float timeFloat = m_dwTimeoutSend - diff/1000000.; + timeleftSecs = timeFloat; + timeleftMicros = (timeFloat - timeleftSecs) * 1000000; + } } - if(err == EPIPE || err == ECONNRESET || err == ECONNABORTED ){ Close(); return 0; } - - return ret==-1 && bytesleft == iSize?SOCKET_ERROR:total; + return total; } @@ -326,22 +402,15 @@ int ofxTCPManager::SendAll(const char* pBuff, const int iSize) /// int ofxTCPManager::Receive(char* pBuff, const int iSize) { - if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - - if (m_dwTimeoutReceive != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,&fd,NULL,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); - } - } - int ret = recv(m_hSocket, pBuff, iSize, 0); - if(ret==-1) ofxNetworkCheckError(); - return ret; + if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); + + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto ret = WaitReceive(m_dwTimeoutReceive,0); + if(ret!=0){ + return ret; + } + } + return recv(m_hSocket, pBuff, iSize, 0); } @@ -353,21 +422,16 @@ int ofxTCPManager::Receive(char* pBuff, const int iSize) /// int ofxTCPManager::PeekReceive(char* pBuff, const int iSize) { - if (m_hSocket == INVALID_SOCKET) - return(SOCKET_ERROR); - - int ret = recv(m_hSocket, pBuff, iSize, MSG_PEEK); - - if(ret==-1) - { - // if socket is non-blocking, the result is likely to be EWOULDBLOCK (no data) so return zero-bytes - int NetError = ofxNetworkCheckError(); - if ( NetError == OFXNETWORK_ERROR(WOULDBLOCK) ) - return 0; - // error - return SOCKET_ERROR; + if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); + + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto ret = WaitReceive(m_dwTimeoutReceive,0); + if(ret!=0){ + return ret; + } } - return ret; + + return recv(m_hSocket, pBuff, iSize, MSG_PEEK); } //-------------------------------------------------------------------------------- @@ -378,53 +442,39 @@ int ofxTCPManager::ReceiveAll(char* pBuff, const int iSize) { if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - unsigned long timestamp= GetTickCount(); - - if (m_dwTimeoutReceive != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,&fd,NULL,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); - } - } + auto timestamp = ofGetElapsedTimeMicros(); + auto timeleftSecs = m_dwTimeoutReceive; + auto timeleftMicros = 0; int totalBytes=0; - unsigned long stamp = GetTickCount(); - do { - int ret= recv(m_hSocket, pBuff+totalBytes, iSize-totalBytes, 0); - if (ret==0 && totalBytes != iSize) return SOCKET_ERROR; + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto ret = WaitReceive(timeleftSecs, timeleftMicros); + if(ret!=0){ + return ret; + } + } + int ret = recv(m_hSocket, pBuff+totalBytes, iSize-totalBytes, 0); + if (ret==0 && totalBytes != iSize){ + return SOCKET_ERROR; + } if (ret < 0){ - ofxNetworkCheckError(); return SOCKET_ERROR; } - if (GetTickCount() - timestamp > m_dwTimeoutReceive * 1000) return SOCKET_TIMEOUT; totalBytes += ret; - #ifndef TARGET_WIN32 - usleep(20000); //should be 20ms - #else - Sleep(20); - #endif - if (GetTickCount() - stamp > 10000) - return SOCKET_TIMEOUT; + + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto now = ofGetElapsedTimeMicros(); + auto diff = now - timestamp; + if(diff > m_dwTimeoutReceive){ + return SOCKET_TIMEOUT; + } + float timeFloat = m_dwTimeoutSend - diff/1000000.; + timeleftSecs = timeFloat; + timeleftMicros = (timeFloat - timeleftSecs) * 1000000; + } }while(totalBytes < iSize); -/* - if (totalBytes > 0) - { - char out[400]; - sprintf(out, "%d bytes received:", totalBytes); - int len = strlen(out); - memcpy((char*)out + len, pBuff, totalBytes); - len += totalBytes; - out[len] = 0; - OutputDebugString(out); - } -*/ return totalBytes; } diff --git a/addons/ofxNetwork/src/ofxTCPManager.h b/addons/ofxNetwork/src/ofxTCPManager.h index 5ce21ad496a..d8fac2ebec7 100644 --- a/addons/ofxNetwork/src/ofxTCPManager.h +++ b/addons/ofxNetwork/src/ofxTCPManager.h @@ -66,7 +66,7 @@ SetTimeoutReceive() #include #ifndef TARGET_ANDROID - #include + #include #else #include #endif @@ -175,7 +175,7 @@ class ofxTCPManager bool Close(); bool Create(); bool Listen(int iMaxConnections); - bool Connect(char *pAddrStr, unsigned short usPort); + bool Connect(const char *pAddrStr, unsigned short usPort); bool Bind(unsigned short usPort); bool Accept(ofxTCPManager& sock); //sends the data, but it is not guaranteed that really all data will be sent @@ -202,13 +202,20 @@ class ofxTCPManager int GetSendBufferSize(); int GetMaxConnections(); bool SetNonBlocking(bool useNonBlocking); + bool IsNonBlocking(); bool CheckHost(const char *pAddrStr); void CleanUp(); + // Tries to detect half open connection http://stackoverflow.com/a/283387 + bool CheckIsConnected(); + + private: // private copy so this can't be copied to avoid problems with destruction ofxTCPManager(const ofxTCPManager & mom){}; ofxTCPManager & operator=(const ofxTCPManager & mom){return *this;} + int WaitReceive(time_t timeoutSeconds, time_t timeoutMillis); + int WaitSend(time_t timeoutSeconds, time_t timeoutMillis); int m_iListenPort; int m_iMaxConnections; @@ -226,5 +233,4 @@ class ofxTCPManager bool nonBlocking; static bool m_bWinsockInit; bool m_closing; - }; diff --git a/addons/ofxNetwork/src/ofxTCPServer.cpp b/addons/ofxNetwork/src/ofxTCPServer.cpp index 62b5f64c34a..fff59fe4810 100644 --- a/addons/ofxNetwork/src/ofxTCPServer.cpp +++ b/addons/ofxNetwork/src/ofxTCPServer.cpp @@ -37,12 +37,15 @@ bool ofxTCPServer::setup(int _port, bool blocking){ port = _port; bClientBlocking = blocking; + std::unique_lock lck(mConnectionsLock); startThread(); + serverReady.wait(lck); + return true; } //-------------------------- -void ofxTCPServer::setMessageDelimiter(string delim){ +void ofxTCPServer::setMessageDelimiter(std::string delim){ if(delim != ""){ messageDelimiter = delim; } @@ -50,29 +53,14 @@ void ofxTCPServer::setMessageDelimiter(string delim){ //-------------------------- bool ofxTCPServer::close(){ - - if(connected) - { - mConnectionsLock.lock(); - map >::iterator it; - for(it=TCPConnections.begin(); it!=TCPConnections.end(); it++){ - it->second->close(); - } - stopThread(); - connected = false; - } - TCPConnections.clear(); - mConnectionsLock.unlock(); // unlock for thread - stopThread(); - + stopThread(); if( !TCPServer.Close() ){ ofLogWarning("ofxTCPServer") << "close(): couldn't close connections"; - - waitForThread(false); //stop the thread + waitForThread(false); // wait for the thread to finish return false; - }else{ - - waitForThread(false); //stop the thread + }else{ + ofLogVerbose("ofxTCPServer") << "Closing server"; + waitForThread(false); // wait for the thread to finish return true; } } @@ -83,7 +71,7 @@ ofxTCPClient & ofxTCPServer::getClient(int clientID){ //-------------------------- bool ofxTCPServer::disconnectClient(int clientID){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "disconnectClient(): client " << clientID << " doesn't exist"; return false; @@ -95,28 +83,34 @@ bool ofxTCPServer::disconnectClient(int clientID){ } //-------------------------- -bool ofxTCPServer::send(int clientID, string message){ - std::unique_lock Lock( mConnectionsLock ); +bool ofxTCPServer::disconnectAllClients(){ + std::unique_lock lck( mConnectionsLock ); + TCPConnections.clear(); + return true; +} + +//-------------------------- +bool ofxTCPServer::send(int clientID, std::string message){ + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "send(): client " << clientID << " doesn't exist"; return false; }else{ - getClient(clientID).send(message); + auto ret = getClient(clientID).send(message); if(!getClient(clientID).isConnected()) TCPConnections.erase(clientID); - return true; + return ret; } } //-------------------------- -bool ofxTCPServer::sendToAll(string message){ - std::unique_lock Lock( mConnectionsLock ); +bool ofxTCPServer::sendToAll(std::string message){ + std::unique_lock lck( mConnectionsLock ); if(TCPConnections.size() == 0) return false; - map >::iterator it; - vector disconnect; - for(it=TCPConnections.begin(); it!=TCPConnections.end(); it++){ - if(it->second->isConnected()) it->second->send(message); - else disconnect.push_back(it->first); + std::vector disconnect; + for(auto & conn: TCPConnections){ + if(conn.second->isConnected()) conn.second->send(message); + else disconnect.push_back(conn.first); } for(int i=0; i<(int)disconnect.size(); i++){ TCPConnections.erase(disconnect[i]); @@ -125,15 +119,15 @@ bool ofxTCPServer::sendToAll(string message){ } //-------------------------- -string ofxTCPServer::receive(int clientID){ - std::unique_lock Lock( mConnectionsLock ); +std::string ofxTCPServer::receive(int clientID){ + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "receive(): client " << clientID << " doesn't exist"; return "client " + ofToString(clientID) + "doesn't exist"; } if( !getClient(clientID).isConnected() ){ - disconnectClient(clientID); + TCPConnections.erase(clientID); return ""; } @@ -142,7 +136,7 @@ string ofxTCPServer::receive(int clientID){ //-------------------------- bool ofxTCPServer::sendRawBytes(int clientID, const char * rawBytes, const int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "sendRawBytes(): client " << clientID << " doesn't exist"; @@ -155,12 +149,13 @@ bool ofxTCPServer::sendRawBytes(int clientID, const char * rawBytes, const int n //-------------------------- bool ofxTCPServer::sendRawBytesToAll(const char * rawBytes, const int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if(TCPConnections.size() == 0 || numBytes <= 0) return false; - map >::iterator it; - for(it=TCPConnections.begin(); it!=TCPConnections.end(); it++){ - if(it->second->isConnected())it->second->sendRawBytes(rawBytes, numBytes); + for(auto & conn: TCPConnections){ + if(conn.second->isConnected()){ + conn.second->sendRawBytes(rawBytes, numBytes); + } } return true; } @@ -168,7 +163,7 @@ bool ofxTCPServer::sendRawBytesToAll(const char * rawBytes, const int numBytes){ //-------------------------- bool ofxTCPServer::sendRawMsg(int clientID, const char * rawBytes, const int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "sendRawMsg(): client " << clientID << " doesn't exist"; return false; @@ -180,19 +175,20 @@ bool ofxTCPServer::sendRawMsg(int clientID, const char * rawBytes, const int num //-------------------------- bool ofxTCPServer::sendRawMsgToAll(const char * rawBytes, const int numBytes){ - std::unique_lock Lock( mConnectionsLock ); - if(TCPConnections.size() == 0 || numBytes <= 0) return false; + std::unique_lock lck( mConnectionsLock ); + if(TCPConnections.empty() || numBytes <= 0) return false; - map >::iterator it; - for(it=TCPConnections.begin(); it!=TCPConnections.end(); it++){ - if(it->second->isConnected())it->second->sendRawMsg(rawBytes, numBytes); + for(auto & conn: TCPConnections){ + if(conn.second->isConnected()){ + conn.second->sendRawMsg(rawBytes, numBytes); + } } return true; } //-------------------------- int ofxTCPServer::getNumReceivedBytes(int clientID){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "getNumReceivedBytes(): client " << clientID << " doesn't exist"; return 0; @@ -203,7 +199,7 @@ int ofxTCPServer::getNumReceivedBytes(int clientID){ //-------------------------- int ofxTCPServer::receiveRawBytes(int clientID, char * receiveBytes, int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "receiveRawBytes(): client " << clientID << " doesn't exist"; return 0; @@ -215,7 +211,7 @@ int ofxTCPServer::receiveRawBytes(int clientID, char * receiveBytes, int numByt //-------------------------- int ofxTCPServer::peekReceiveRawBytes(int clientID, char * receiveBytes, int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLog(OF_LOG_WARNING, "ofxTCPServer: client " + ofToString(clientID) + " doesn't exist"); return 0; @@ -226,7 +222,7 @@ int ofxTCPServer::peekReceiveRawBytes(int clientID, char * receiveBytes, int nu //-------------------------- int ofxTCPServer::receiveRawMsg(int clientID, char * receiveBytes, int numBytes){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "receiveRawMsg(): client " << clientID << " doesn't exist"; return 0; @@ -237,7 +233,7 @@ int ofxTCPServer::receiveRawMsg(int clientID, char * receiveBytes, int numBytes //-------------------------- int ofxTCPServer::getClientPort(int clientID){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "getClientPort(): client " << clientID << " doesn't exist"; return 0; @@ -246,8 +242,8 @@ int ofxTCPServer::getClientPort(int clientID){ } //-------------------------- -string ofxTCPServer::getClientIP(int clientID){ - std::unique_lock Lock( mConnectionsLock ); +std::string ofxTCPServer::getClientIP(int clientID){ + std::unique_lock lck( mConnectionsLock ); if( !isClientSetup(clientID) ){ ofLogWarning("ofxTCPServer") << "getClientIP(): client " << clientID << " doesn't exist"; return "000.000.000.000"; @@ -257,7 +253,6 @@ string ofxTCPServer::getClientIP(int clientID){ //-------------------------- int ofxTCPServer::getNumClients(){ - std::unique_lock Lock( mConnectionsLock ); return TCPConnections.size(); } @@ -278,16 +273,30 @@ bool ofxTCPServer::isConnected(){ //-------------------------- bool ofxTCPServer::isClientSetup(int clientID){ - std::unique_lock Lock( mConnectionsLock ); return TCPConnections.find(clientID)!=TCPConnections.end(); } //-------------------------- bool ofxTCPServer::isClientConnected(int clientID){ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); return isClientSetup(clientID) && getClient(clientID).isConnected(); } + +void ofxTCPServer::waitConnectedClient(){ + std::unique_lock lck( mConnectionsLock ); + if(TCPConnections.empty()){ + serverReady.wait(lck); + } +} + +void ofxTCPServer::waitConnectedClient(int ms){ + std::unique_lock lck( mConnectionsLock ); + if(TCPConnections.empty()){ + serverReady.wait_for(lck, std::chrono::milliseconds(ms)); + } +} + //don't call this //-------------------------- void ofxTCPServer::threadedFunction(){ @@ -308,23 +317,32 @@ void ofxTCPServer::threadedFunction(){ if( !TCPServer.Listen(TCP_MAX_CLIENTS) ){ if(isThreadRunning()) ofLogError("ofxTCPServer") << "listening failed"; } + + { + std::unique_lock lck( mConnectionsLock ); + serverReady.notify_one(); + } // we need to lock here, but can't as it blocks... // so use a temporary to not block the lock - ofPtr client(new ofxTCPClient); + std::shared_ptr client(new ofxTCPClient); if( !TCPServer.Accept( client->TCPClient ) ){ if(isThreadRunning()) ofLogError("ofxTCPServer") << "couldn't accept client " << acceptId; }else{ - std::unique_lock Lock( mConnectionsLock ); + std::unique_lock lck( mConnectionsLock ); // take owenership of socket from NewClient TCPConnections[acceptId] = client; - TCPConnections[acceptId]->setup(acceptId, bClientBlocking); + TCPConnections[acceptId]->setupConnectionIdx(acceptId, bClientBlocking); TCPConnections[acceptId]->setMessageDelimiter(messageDelimiter); ofLogVerbose("ofxTCPServer") << "client " << acceptId << " connected on port " << TCPConnections[acceptId]->getPort(); if(acceptId == idCount) idCount++; + serverReady.notify_all(); } } idCount = 0; + std::unique_lock lck( mConnectionsLock ); + TCPConnections.clear(); + connected = false; ofLogVerbose("ofxTCPServer") << "listening thread stopped"; } diff --git a/addons/ofxNetwork/src/ofxTCPServer.h b/addons/ofxNetwork/src/ofxTCPServer.h index 9c0aec6be55..ab0c3490e18 100644 --- a/addons/ofxNetwork/src/ofxTCPServer.h +++ b/addons/ofxNetwork/src/ofxTCPServer.h @@ -4,6 +4,7 @@ #include "ofThread.h" #include "ofxTCPManager.h" #include +#include #define TCP_MAX_CLIENTS 32 @@ -16,12 +17,18 @@ class ofxTCPServer : public ofThread{ ofxTCPServer(); ~ofxTCPServer(); + + // ofxTCPServer can't be copied to avoid problems with destruction + ofxTCPServer(const ofxTCPServer & mom) = delete; + ofxTCPServer & operator=(const ofxTCPServer & mom) = delete; + void setVerbose(bool _verbose); bool setup(int _port, bool blocking = false); - void setMessageDelimiter(string delim); + void setMessageDelimiter(std::string delim); bool close(); bool disconnectClient(int clientID); + bool disconnectAllClients(); int getNumClients(); //total number of clients - not sutible for iterating through clients with int getLastID(); //this returns the last current id number if you want to loop through with a for loop @@ -30,7 +37,7 @@ class ofxTCPServer : public ofThread{ bool isConnected(); int getClientPort(int clientID); - string getClientIP(int clientID); + std::string getClientIP(int clientID); bool isClientConnected(int clientID); @@ -38,8 +45,8 @@ class ofxTCPServer : public ofThread{ //is added to the end of the string which is //used to indicate the end of the message to //the receiver see: STR_END_MSG (ofTCPClient.h) - bool send(int clientID, string message); - bool sendToAll(string message); + bool send(int clientID, std::string message); + bool sendToAll(std::string message); // same as send for binary data @@ -65,7 +72,7 @@ class ofxTCPServer : public ofThread{ //eg: if you want to send "Hello World" from other //software and want to receive it as a string //sender should send "Hello World[/TCP]" - string receive(int clientID); + std::string receive(int clientID); // same as receive for binary data int receiveRawMsg(int clientID, char * receiveBytes, int numBytes); @@ -78,26 +85,24 @@ class ofxTCPServer : public ofThread{ //amount of filled-bytes returned int peekReceiveRawBytes(int clientID, char * receiveBytes, int numBytes); - + void waitConnectedClient(); + void waitConnectedClient(int ms); private: - // private copy so this can't be copied to avoid problems with destruction - ofxTCPServer(const ofxTCPServer & mom){}; - ofxTCPServer & operator=(const ofxTCPServer & mom){return *this;} - ofxTCPClient & getClient(int clientID); bool isClientSetup(int clientID); void threadedFunction(); ofxTCPManager TCPServer; - map > TCPConnections; + std::map > TCPConnections; std::mutex mConnectionsLock; + std::condition_variable serverReady; bool connected; - string str; + std::string str; int idCount, port; bool bClientBlocking; - string messageDelimiter; + std::string messageDelimiter; }; diff --git a/addons/ofxNetwork/src/ofxUDPManager.cpp b/addons/ofxNetwork/src/ofxUDPManager.cpp index 58b3589190a..bc94adbcffb 100644 --- a/addons/ofxNetwork/src/ofxUDPManager.cpp +++ b/addons/ofxNetwork/src/ofxUDPManager.cpp @@ -21,7 +21,8 @@ ofxUDPManager::ofxUDPManager() #endif m_hSocket= INVALID_SOCKET; - m_dwTimeoutReceive= OF_UDP_DEFAULT_TIMEOUT; + m_dwTimeoutReceive = OF_UDP_DEFAULT_TIMEOUT; + m_dwTimeoutSend = OF_UDP_DEFAULT_TIMEOUT; canGetRemoteAddress = false; nonBlocking = true; @@ -69,8 +70,48 @@ bool ofxUDPManager::Create() return ret; } + +//-------------------------------------------------------------------------------- +int ofxUDPManager::WaitReceive(time_t timeoutSeconds, time_t timeoutMicros){ + if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR; + + fd_set fd; + FD_ZERO(&fd); + FD_SET(m_hSocket, &fd); + timeval tv; + tv.tv_sec = timeoutSeconds; + tv.tv_usec = timeoutMicros; + auto ret = select(m_hSocket+1,&fd,NULL,NULL,&tv); + if(ret == 0){ + return SOCKET_TIMEOUT; + }else if(ret < 0){ + return SOCKET_ERROR; + }else{ + return 0; + } +} + +//-------------------------------------------------------------------------------- +int ofxUDPManager::WaitSend(time_t timeoutSeconds, time_t timeoutMicros){ + if (m_hSocket == INVALID_SOCKET) return SOCKET_ERROR; + + fd_set fd; + FD_ZERO(&fd); + FD_SET(m_hSocket, &fd); + timeval tv; + tv.tv_sec = timeoutSeconds; + tv.tv_usec = timeoutMicros; + auto ret = select(m_hSocket+1,NULL,&fd,NULL,&tv); + if(ret == 0){ + return SOCKET_TIMEOUT; + }else if(ret < 0){ + return SOCKET_ERROR; + }else{ + return 0; + } +} + //-------------------------------------------------------------------------------- -///Theo added - Choose to set nonBLocking - default mode is to block bool ofxUDPManager::SetNonBlocking(bool useNonBlocking) { nonBlocking = useNonBlocking; @@ -160,7 +201,8 @@ bool ofxUDPManager::ConnectMcast(char* pMcast, unsigned short usPort) if (!Bind(usPort)) { #ifdef _DEBUG - ofLogError("ofxUDPManager") << "ConnectMcast(): couldn't bind to " << usPort<< ", err " << WSAGetLastError(); + ofLogError("ofxUDPManager") << "ConnectMcast(): couldn't bind to " << usPort; + ofxNetworkCheckError(); #endif return false; } @@ -169,14 +211,16 @@ bool ofxUDPManager::ConnectMcast(char* pMcast, unsigned short usPort) if (!SetTTL(1)) { #ifdef _DEBUG - ofLogWarning("ofxUDPManager") << "ConnectMcast(): couldn't set TTL: err " << WSAGetLastError() << ", contining anyway"; + ofLogWarning("ofxUDPManager") << "ConnectMcast(): couldn't set TTL; continuing anyway"; + ofxNetworkCheckError(); #endif } if (!Connect(pMcast, usPort)) { #ifdef _DEBUG - ofLogError("ofxUDPManager") << " ConnectMcast(): couldn't connect to socket: err " << WSAGetLastError(); + ofLogError("ofxUDPManager") << " ConnectMcast(): couldn't connect to socket"; + ofxNetworkCheckError(); #endif return false; } @@ -193,17 +237,12 @@ int ofxUDPManager::Send(const char* pBuff, const int iSize) { if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - /*if (m_dwTimeoutSend != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,NULL,&fd,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto ret = WaitSend(m_dwTimeoutSend,0); + if(ret!=0){ + return ret; } - }*/ + } int ret = sendto(m_hSocket, (char*)pBuff, iSize, 0, (sockaddr *)&saClient, sizeof(sockaddr)); if(ret==-1) ofxNetworkCheckError(); @@ -219,37 +258,39 @@ int ofxUDPManager::SendAll(const char* pBuff, const int iSize) { if (m_hSocket == INVALID_SOCKET) return(SOCKET_ERROR); - if (m_dwTimeoutSend != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {(time_t)m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,NULL,&fd,NULL,&tv)== 0) - { - ofxNetworkCheckError(); - return(SOCKET_TIMEOUT); + auto timestamp = ofGetElapsedTimeMicros(); + auto timeleftSecs = m_dwTimeoutSend; + auto timeleftMicros = 0; + int total= 0; + int bytesleft = iSize; + int ret=-1; + + while (total < iSize) { + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto ret = WaitSend(timeleftSecs,timeleftMicros); + if(ret!=0){ + return ret; + } } - } - - - int total= 0; - int bytesleft = iSize; - int n=0; - - while (total < iSize) - { - n = sendto(m_hSocket, (char*)pBuff, iSize, 0, (sockaddr *)&saClient, sizeof(sockaddr)); - if (n == -1) - { - ofxNetworkCheckError(); - break; + ret = sendto(m_hSocket, (char*)pBuff, iSize, 0, (sockaddr *)&saClient, sizeof(sockaddr)); + if (ret == SOCKET_ERROR) { + return SOCKET_ERROR; + } + total += ret; + bytesleft -=ret; + if (m_dwTimeoutSend != NO_TIMEOUT){ + auto now = ofGetElapsedTimeMicros(); + auto diff = now - timestamp; + if (diff > m_dwTimeoutSend * 1000000){ + return SOCKET_TIMEOUT; } - total += n; - bytesleft -=n; + float timeFloat = m_dwTimeoutSend - diff/1000000.; + timeleftSecs = timeFloat; + timeleftMicros = (timeFloat - timeleftSecs) * 1000000; + } } - return n==-1?SOCKET_ERROR:total; + return total; } @@ -262,15 +303,22 @@ int ofxUDPManager::PeekReceive() return SOCKET_ERROR; } + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto ret = WaitReceive(m_dwTimeoutReceive,0); + if(ret!=0){ + return ret; + } + } + // we can use MSG_PEEK, but we still need a large buffer (udp protocol max is 64kb even if max for this socket is less) // don't want a 64kb stack item here, so instead read how much can be read (note: not queue size, there may be more data-more packets) - #ifdef TARGET_WIN32 - unsigned long size = 0; - int retVal = ioctlsocket(m_hSocket,FIONREAD,&size); - #else - int size = 0; - int retVal = ioctl(m_hSocket,FIONREAD,&size); - #endif + #ifdef TARGET_WIN32 + unsigned long size = 0; + int retVal = ioctlsocket(m_hSocket,FIONREAD,&size); + #else + int size = 0; + int retVal = ioctl(m_hSocket,FIONREAD,&size); + #endif // error if ( retVal != 0 ) @@ -297,17 +345,12 @@ int ofxUDPManager::Receive(char* pBuff, const int iSize) } - /*if (m_dwTimeoutSend != NO_TIMEOUT) - { - fd_set fd; - FD_ZERO(&fd); - FD_SET(m_hSocket, &fd); - timeval tv= {m_dwTimeoutSend, 0}; - if(select(m_hSocket+1,&fd,NULL,NULL,&tv)== 0) - { - return(SOCKET_TIMEOUT); + if (m_dwTimeoutReceive != NO_TIMEOUT){ + auto ret = WaitReceive(m_dwTimeoutReceive,0); + if(ret!=0){ + return ret; } - }*/ + } #ifndef TARGET_WIN32 socklen_t nLen= sizeof(sockaddr); @@ -516,7 +559,7 @@ int ofxUDPManager::GetTTL() if (getsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *) &nTTL, &nSize) == SOCKET_ERROR) { #ifdef _DEBUG - ofLogError("ofxUDPManager") << "GetTTL(): getsockopt failed: err " << WSAGetLastError(); + ofLogError("ofxUDPManager") << "GetTTL(): getsockopt failed"; #endif ofxNetworkCheckError(); return -1; @@ -534,7 +577,7 @@ bool ofxUDPManager::SetTTL(int nTTL) if (setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&nTTL, sizeof (int)) == SOCKET_ERROR) { #ifdef _DEBUG - ofLogError("ofxUDPManager") << "SetTTL(): setsockopt failed: err " << WSAGetLastError(); + ofLogError("ofxUDPManager") << "SetTTL(): setsockopt failed"; #endif ofxNetworkCheckError(); return false; diff --git a/addons/ofxNetwork/src/ofxUDPManager.h b/addons/ofxNetwork/src/ofxUDPManager.h index 4cfd883899f..c9aea67fb71 100644 --- a/addons/ofxNetwork/src/ofxUDPManager.h +++ b/addons/ofxNetwork/src/ofxUDPManager.h @@ -159,6 +159,8 @@ class ofxUDPManager int m_hSocket; #endif + int WaitReceive(time_t timeoutSeconds, time_t timeoutMillis); + int WaitSend(time_t timeoutSeconds, time_t timeoutMillis); unsigned long m_dwTimeoutReceive; unsigned long m_dwTimeoutSend; diff --git a/addons/ofxOpenCv/addon_config.mk b/addons/ofxOpenCv/addon_config.mk index c5176233d9f..9731af9c398 100644 --- a/addons/ofxOpenCv/addon_config.mk +++ b/addons/ofxOpenCv/addon_config.mk @@ -84,23 +84,11 @@ linuxarmv7l: ADDON_INCLUDES_EXCLUDE = libs/opencv ADDON_INCLUDES_EXCLUDE += libs/opencv/% -win_cb: - ADDON_LIBS = - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_legacy231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_haartraining_engine.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_calib3d231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_features2d231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_objdetect231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_video231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_imgproc231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_highgui231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_ml231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_core231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_flann231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_contrib231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_gpu231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libopencv_ts231.a - ADDON_LIBS += libs/opencv/lib/win_cb/libzlib.a +msys2: + ADDON_PKG_CONFIG_LIBRARIES = opencv + ADDON_LIBS_EXCLUDE = libs/opencv/% + ADDON_INCLUDES_EXCLUDE = libs/opencv + ADDON_INCLUDES_EXCLUDE += libs/opencv/% android/armeabi: ADDON_LIBS = @@ -128,3 +116,9 @@ android/armeabi-v7a: ADDON_LIBS += libs/opencv/lib/android/armeabi-v7a/libopencv_core.a ADDON_LIBS += libs/opencv/lib/android/armeabi-v7a/libopencv_flann.a ADDON_LIBS += libs/opencv/lib/android/armeabi-v7a/libopencv_contrib.a + + +ios: + # osx/iOS only, any framework that should be included in the project + ADDON_FRAMEWORKS = AssetsLibrary + diff --git a/addons/ofxOpenCv/libs/opencv/include/opencv2/opencv_modules.hpp b/addons/ofxOpenCv/libs/opencv/include/opencv2/opencv_modules.hpp index 63342287836..35503da32ca 100644 --- a/addons/ofxOpenCv/libs/opencv/include/opencv2/opencv_modules.hpp +++ b/addons/ofxOpenCv/libs/opencv/include/opencv2/opencv_modules.hpp @@ -11,7 +11,6 @@ #define HAVE_OPENCV_CORE #define HAVE_OPENCV_FEATURES2D #define HAVE_OPENCV_FLANN -#define HAVE_OPENCV_GPU #define HAVE_OPENCV_HIGHGUI #define HAVE_OPENCV_IMGPROC #define HAVE_OPENCV_LEGACY @@ -20,8 +19,6 @@ #define HAVE_OPENCV_OBJDETECT #define HAVE_OPENCV_PHOTO #define HAVE_OPENCV_STITCHING -#define HAVE_OPENCV_SUPERRES -#define HAVE_OPENCV_TS #define HAVE_OPENCV_VIDEO #define HAVE_OPENCV_VIDEOSTAB diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_calib3d.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_calib3d.a index cd65f976ee2..95911400855 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_calib3d.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_calib3d.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_contrib.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_contrib.a index 4758f488c90..b0d161cffc5 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_contrib.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_contrib.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_core.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_core.a index 75c59705db0..e8ab44f06a4 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_core.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_core.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_features2d.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_features2d.a index a474031a4a4..9942e6fb842 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_features2d.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_features2d.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_flann.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_flann.a index e13e3925ce4..d15aef50b3e 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_flann.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_flann.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_highgui.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_highgui.a index 95be4feff3c..3b2b557bce0 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_highgui.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_highgui.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_imgproc.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_imgproc.a index dfdb0f8352b..6f06eeba682 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_imgproc.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_imgproc.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_legacy.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_legacy.a index 6eb9a5418a5..1e149969cf7 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_legacy.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_legacy.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_ml.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_ml.a index 7a849d77994..46a99f3bc2b 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_ml.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_ml.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_nonfree.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_nonfree.a index aca714a4d93..734ffd364f8 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_nonfree.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_nonfree.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_objdetect.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_objdetect.a index cad56c9cd45..4f3ae45bd25 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_objdetect.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_objdetect.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_photo.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_photo.a index ab8ff4afeb4..814ebacbfe6 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_photo.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_photo.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_stitching.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_stitching.a index a13d6169b87..319d8b6d85e 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_stitching.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_stitching.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_video.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_video.a index 8dd4add1caa..69995609b61 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_video.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_video.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_videostab.a b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_videostab.a index fbe065e0166..f5d187a5584 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_videostab.a and b/addons/ofxOpenCv/libs/opencv/lib/ios/opencv_videostab.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/osx/opencv.a b/addons/ofxOpenCv/libs/opencv/lib/osx/opencv.a index b42cfb4864e..f275e6e8254 100644 Binary files a/addons/ofxOpenCv/libs/opencv/lib/osx/opencv.a and b/addons/ofxOpenCv/libs/opencv/lib/osx/opencv.a differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_calib3d249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_calib3d249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_calib3d249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_calib3d249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_contrib249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_contrib249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_contrib249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_contrib249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_core249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_core249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_core249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_core249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_features2d249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_features2d249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_features2d249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_features2d249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_flann249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_flann249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_flann249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_flann249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_gpu249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_gpu249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_gpu249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_gpu249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_highgui249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_highgui249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_highgui249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_highgui249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_imgproc249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_imgproc249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_imgproc249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_imgproc249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_legacy249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_legacy249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_legacy249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_legacy249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ml249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_ml249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ml249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_ml249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_nonfree249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_nonfree249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_nonfree249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_nonfree249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_objdetect249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_objdetect249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_objdetect249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_objdetect249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_photo249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_photo249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_photo249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_photo249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_stitching249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_stitching249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_stitching249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_stitching249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_superres249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_superres249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_superres249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_superres249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ts249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_ts249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ts249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_ts249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_video249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_video249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_video249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_video249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_videostab249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_videostab249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_videostab249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/opencv_videostab249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/zlibd.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/zlibd.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/zlibd.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Debug/zlibd.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_calib3d249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_calib3d249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_calib3d249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_calib3d249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_contrib249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_contrib249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_contrib249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_contrib249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_core249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_core249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_core249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_core249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_features2d249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_features2d249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_features2d249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_features2d249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_flann249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_flann249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_flann249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_flann249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_gpu249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_gpu249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_gpu249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_gpu249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_highgui249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_highgui249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_highgui249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_highgui249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_imgproc249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_imgproc249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_imgproc249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_imgproc249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_legacy249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_legacy249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_legacy249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_legacy249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ml249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_ml249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ml249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_ml249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_nonfree249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_nonfree249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_nonfree249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_nonfree249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_objdetect249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_objdetect249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_objdetect249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_objdetect249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_photo249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_photo249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_photo249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_photo249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_stitching249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_stitching249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_stitching249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_stitching249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_superres249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_superres249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_superres249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_superres249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ts249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_ts249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_ts249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_ts249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_video249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_video249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_video249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_video249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_videostab249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_videostab249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/opencv_videostab249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/opencv_videostab249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/zlib.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/zlib.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/Win32/zlib.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/Win32/Release/zlib.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_calib3d249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_calib3d249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_calib3d249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_calib3d249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_contrib249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_contrib249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_contrib249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_contrib249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_core249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_core249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_core249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_core249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_features2d249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_features2d249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_features2d249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_features2d249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_flann249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_flann249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_flann249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_flann249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_gpu249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_gpu249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_gpu249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_gpu249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_highgui249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_highgui249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_highgui249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_highgui249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_imgproc249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_imgproc249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_imgproc249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_imgproc249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_legacy249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_legacy249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_legacy249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_legacy249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ml249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_ml249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ml249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_ml249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_nonfree249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_nonfree249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_nonfree249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_nonfree249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_objdetect249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_objdetect249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_objdetect249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_objdetect249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_photo249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_photo249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_photo249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_photo249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_stitching249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_stitching249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_stitching249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_stitching249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_superres249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_superres249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_superres249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_superres249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ts249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_ts249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ts249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_ts249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_video249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_video249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_video249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_video249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_videostab249d.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_videostab249d.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_videostab249d.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/opencv_videostab249d.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/zlibd.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/zlibd.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/zlibd.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Debug/zlibd.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_calib3d249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_calib3d249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_calib3d249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_calib3d249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_contrib249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_contrib249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_contrib249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_contrib249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_core249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_core249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_core249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_core249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_features2d249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_features2d249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_features2d249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_features2d249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_flann249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_flann249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_flann249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_flann249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_gpu249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_gpu249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_gpu249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_gpu249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_highgui249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_highgui249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_highgui249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_highgui249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_imgproc249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_imgproc249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_imgproc249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_imgproc249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_legacy249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_legacy249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_legacy249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_legacy249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ml249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_ml249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ml249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_ml249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_nonfree249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_nonfree249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_nonfree249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_nonfree249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_objdetect249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_objdetect249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_objdetect249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_objdetect249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_photo249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_photo249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_photo249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_photo249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_stitching249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_stitching249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_stitching249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_stitching249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_superres249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_superres249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_superres249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_superres249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ts249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_ts249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_ts249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_ts249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_video249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_video249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_video249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_video249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_videostab249.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_videostab249.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/opencv_videostab249.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/opencv_videostab249.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/vs/x64/zlib.lib b/addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/zlib.lib similarity index 100% rename from addons/ofxOpenCv/libs/opencv/lib/vs/x64/zlib.lib rename to addons/ofxOpenCv/libs/opencv/lib/vs/x64/Release/zlib.lib diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_calib3d231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_calib3d231.a deleted file mode 100644 index 5ff0f3467c0..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_calib3d231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_contrib231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_contrib231.a deleted file mode 100644 index 974e79c360b..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_contrib231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_core231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_core231.a deleted file mode 100644 index 7ed6b74272d..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_core231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_features2d231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_features2d231.a deleted file mode 100644 index db0ffca9e9a..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_features2d231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_flann231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_flann231.a deleted file mode 100644 index 69f11866276..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_flann231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_gpu231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_gpu231.a deleted file mode 100644 index 5255b16583c..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_gpu231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_haartraining_engine.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_haartraining_engine.a deleted file mode 100644 index b1a9c910a94..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_haartraining_engine.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_highgui231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_highgui231.a deleted file mode 100644 index 64b88708f44..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_highgui231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_imgproc231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_imgproc231.a deleted file mode 100644 index a09faec6deb..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_imgproc231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_legacy231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_legacy231.a deleted file mode 100644 index 08718814076..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_legacy231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ml231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ml231.a deleted file mode 100644 index bc99047b0b7..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ml231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_objdetect231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_objdetect231.a deleted file mode 100644 index 50174e1124e..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_objdetect231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ts231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ts231.a deleted file mode 100644 index f8b3df63251..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_ts231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_video231.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_video231.a deleted file mode 100644 index 186cc4a0af5..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libopencv_video231.a and /dev/null differ diff --git a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libzlib.a b/addons/ofxOpenCv/libs/opencv/lib/win_cb/libzlib.a deleted file mode 100644 index f10116400df..00000000000 Binary files a/addons/ofxOpenCv/libs/opencv/lib/win_cb/libzlib.a and /dev/null differ diff --git a/addons/ofxOpenCv/scripts/formulas/opencv.sh b/addons/ofxOpenCv/scripts/formulas/opencv.sh index 5d73beed90d..c55ac9124d2 100644 --- a/addons/ofxOpenCv/scripts/formulas/opencv.sh +++ b/addons/ofxOpenCv/scripts/formulas/opencv.sh @@ -6,7 +6,7 @@ # # uses a CMake build system -FORMULA_TYPES=( "osx" "ios" "vs" "android" "emscripten" ) +FORMULA_TYPES=( "osx" "ios" "tvos" "vs" "android" "emscripten" ) # define the version VER=2.4.9 @@ -51,19 +51,18 @@ function build() { LIB_FOLDER="$BUILD_DIR/opencv/build/$TYPE/" if [ "$TYPE" == "osx" ] ; then - rm -f CMakeCache.txt LOG="$LIB_FOLDER/opencv2-${VER}.log" echo "Logging to $LOG" mkdir -p $LIB_FOLDER cd build + rm -f CMakeCache.txt echo "Log:" >> "${LOG}" 2>&1 set +e cmake .. -DCMAKE_INSTALL_PREFIX=$LIB_FOLDER \ - -DGLFW_BUILD_UNIVERSAL=ON \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \ -DENABLE_FAST_MATH=OFF \ - -DCMAKE_CXX_FLAGS="-fvisibility-inlines-hidden -stdlib=libc++ -O3" \ - -DCMAKE_C_FLAGS="-fvisibility-inlines-hidden -stdlib=libc++ -O3" \ + -DCMAKE_CXX_FLAGS="-fvisibility-inlines-hidden -stdlib=libc++ -O3 -fPIC -arch i386 -arch x86_64 -mmacosx-version-min=${OSX_MIN_SDK_VER}" \ + -DCMAKE_C_FLAGS="-fvisibility-inlines-hidden -stdlib=libc++ -O3 -fPIC -arch i386 -arch x86_64 -mmacosx-version-min=${OSX_MIN_SDK_VER}" \ -DCMAKE_BUILD_TYPE="Release" \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_DOCS=OFF \ @@ -96,31 +95,33 @@ function build() { -DWITH_QUICKTIME=OFF \ -DWITH_V4L=OFF \ -DWITH_PVAPI=OFF \ + -DWITH_OPENEXR=OFF \ + -DWITH_EIGEN=OFF \ -DBUILD_TESTS=OFF \ - -DBUILD_PERF_TESTS=OFF | tee ${LOG} + -DBUILD_PERF_TESTS=OFF 2>&1 | tee -a ${LOG} echo "CMAKE Successful" echo "--------------------" echo "Running make clean" - make clean | tee ${LOG} + make clean 2>&1 | tee -a ${LOG} echo "Make Clean Successful" echo "--------------------" echo "Running make" - make -j${PARALLEL_MAKE} | tee ${LOG} + make -j${PARALLEL_MAKE} 2>&1 | tee -a ${LOG} echo "Make Successful" echo "--------------------" echo "Running make install" - make install | tee ${LOG} + make install 2>&1 | tee -a ${LOG} echo "Make install Successful" - + echo "--------------------" echo "Joining all libs in one" outputlist="lib/lib*.a" - libtool -static $outputlist -o "$LIB_FOLDER/lib/opencv.a" | tee ${LOG} + libtool -static $outputlist -o "$LIB_FOLDER/lib/opencv.a" 2>&1 | tee -a ${LOG} echo "Joining all libs in one Successful" - + elif [ "$TYPE" == "vs" ] ; then rm -f CMakeCache.txt #LIB_FOLDER="$BUILD_DIR/opencv/build/$TYPE" @@ -209,7 +210,7 @@ function build() { vs-build "OpenCV.sln" Build "Debug|x64" fi - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then local LIB_FOLDER_IOS="$BUILD_ROOT_DIR/$TYPE/iOS/opencv" local LIB_FOLDER_IOS_SIM="$BUILD_ROOT_DIR/$TYPE/iOS_SIMULATOR/opencv" @@ -217,7 +218,12 @@ function build() { # This was quite helpful as a reference: https://github.com/x2on/OpenSSL-for-iPhone # Refer to the other script if anything drastic changes for future versions - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + SDKVERSION="" + if [[ "${TYPE}" == "tvos" ]]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [[ "$TYPE" == "ios" ]]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi set -e CURRENTPATH=`pwd` @@ -225,7 +231,13 @@ function build() { TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER - local IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + local IOS_ARCHS + if [[ "${TYPE}" == "tvos" ]]; then + IOS_ARCHS="x86_64 arm64" + elif [[ "$TYPE" == "ios" ]]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi + local STDLIB="libc++" echo "--------------------" echo $CURRENTPATH @@ -258,26 +270,52 @@ function build() { # make sure backed up rm -f CMakeCache.txt MIN_IOS_VERSION=$IOS_MIN_SDK_VER - # min iOS version for arm64 is iOS 7 + # min iOS version for arm64 is iOS 7 + + if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures + elif [[ "${IOS_ARCH}" == "i386" ]]; then + MIN_IOS_VERSION=7.0 # 6.0 to prevent start linking errors + fi - if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures - elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors - fi - export IPHONE_SDK_VERSION_MIN=$IOS_MIN_SDK_VER + if [[ "${TYPE}" == "tvos" ]]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [[ "$TYPE" == "ios" ]]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi echo "The compiler: $THECOMPILER" - MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" - ISSIM="TRUE" - MIN_TYPE=-mios-simulator-version-min= + if [[ "${TYPE}" == "tvos" ]]; then + PLATFORM="AppleTVSimulator" + ISSIM="TRUE" + elif [[ "$TYPE" == "ios" ]]; then + PLATFORM="iPhoneSimulator" + ISSIM="TRUE" + fi else - PLATFORM="iPhoneOS" - ISSIM="FALSE" + if [[ "${TYPE}" == "tvos" ]]; then + PLATFORM="AppleTVOS" + ISSIM="FALSE" + elif [[ "$TYPE" == "ios" ]]; then + PLATFORM="iPhoneOS" + ISSIM="FALSE" + fi + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 fi @@ -292,7 +330,7 @@ function build() { isBuilding=true; echo "Log:" >> "${LOG}" 2>&1 - while $isBuilding; do theTail="$(tail -n 1 ${LOG})"; echo $theTail | cut -c -70 ; echo "...";sleep 30; done & # fix for 10 min time out travis + # while $isBuilding; do theTail="$(tail -n 1 ${LOG})"; echo $theTail | cut -c -70 ; echo "...";sleep 30; done & # fix for 10 min time out travis @@ -314,8 +352,8 @@ function build() { -DCMAKE_XCODE_EFFECTIVE_PLATFORMS="-$PLATFORM" \ -DGLFW_BUILD_UNIVERSAL=ON \ -DENABLE_FAST_MATH=OFF \ - -DCMAKE_CXX_FLAGS="-stdlib=libc++ -fvisibility=hidden -fPIC -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -DNDEBUG -Os $MIN_TYPE$IPHONE_SDK_VERSION_MIN" \ - -DCMAKE_C_FLAGS="-stdlib=libc++ -fvisibility=hidden -fPIC -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -DNDEBUG -Os $MIN_TYPE$IPHONE_SDK_VERSION_MIN" \ + -DCMAKE_CXX_FLAGS="-stdlib=libc++ -fvisibility=hidden $BITCODE -fPIC -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -DNDEBUG -Os $MIN_TYPE$MIN_IOS_VERSION" \ + -DCMAKE_C_FLAGS="-stdlib=libc++ -fvisibility=hidden $BITCODE -fPIC -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -DNDEBUG -Os $MIN_TYPE$MIN_IOS_VERSION" \ -DCMAKE_BUILD_TYPE="Release" \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_DOCS=OFF \ @@ -348,6 +386,9 @@ function build() { -DWITH_QUICKTIME=OFF \ -DWITH_V4L=OFF \ -DWITH_PVAPI=OFF \ + -DWITH_EIGEN=OFF \ + -DWITH_OPENEXR=OFF \ + -DBUILD_OPENEXR=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF >> "${LOG}" 2>&1 @@ -410,15 +451,20 @@ function build() { mkdir -p lib/$TYPE echo "--------------------" echo "Creating Fat Libs" - cd build/iOS + cd "build/$TYPE" # link into universal lib, strip "lib" from filename local lib - rm -rf i386/lib/pkgconfig + rm -rf arm64/lib/pkgconfig - for lib in $( ls -1 i386/lib) ; do + for lib in $( ls -1 arm64/lib) ; do local renamedLib=$(echo $lib | sed 's|lib||') if [ ! -e $renamedLib ] ; then - lipo -c armv7/lib/$lib arm64/lib/$lib i386/lib/$lib x86_64/lib/$lib -o "$CURRENTPATH/lib/$TYPE/$renamedLib" + echo "renamed"; + if [[ "${TYPE}" == "tvos" ]] ; then + lipo -c arm64/lib/$lib x86_64/lib/$lib -o "$CURRENTPATH/lib/$TYPE/$renamedLib" + elif [[ "$TYPE" == "ios" ]]; then + lipo -c armv7/lib/$lib arm64/lib/$lib i386/lib/$lib x86_64/lib/$lib -o "$CURRENTPATH/lib/$TYPE/$renamedLib" + fi fi done @@ -489,6 +535,7 @@ function build() { -DWITH_QUICKTIME=OFF \ -DWITH_V4L=OFF \ -DWITH_PVAPI=OFF \ + -DWITH_EIGEN=OFF -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF cd build_android_arm @@ -527,6 +574,7 @@ function build() { -DWITH_QUICKTIME=OFF \ -DWITH_V4L=OFF \ -DWITH_PVAPI=OFF \ + -DWITH_EIGEN=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF cd build_android_x86 @@ -569,6 +617,7 @@ function build() { -DWITH_QUICKTIME=OFF \ -DWITH_V4L=OFF \ -DWITH_PVAPI=OFF \ + -DWITH_EIGEN=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF make -j${PARALLEL_MAKE} @@ -616,7 +665,7 @@ function copy() { cp -v build_vs_64/3rdparty/lib/Release/*.lib $1/../../addons/ofxOpenCv/libs/opencv/lib/$TYPE/x64/ cp -v build_vs_64/3rdparty/lib/Debug/*.lib $1/../../addons/ofxOpenCv/libs/opencv/lib/$TYPE/x64/ fi - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then # Standard *nix style copy. # copy headers @@ -649,5 +698,7 @@ function copy() { function clean() { if [ "$TYPE" == "osx" ] ; then make clean; + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then + make clean; fi } diff --git a/addons/ofxOpenCv/src/ofxCvColorImage.cpp b/addons/ofxOpenCv/src/ofxCvColorImage.cpp index 7cc283d8564..58951c8856a 100644 --- a/addons/ofxOpenCv/src/ofxCvColorImage.cpp +++ b/addons/ofxOpenCv/src/ofxCvColorImage.cpp @@ -22,12 +22,21 @@ ofxCvColorImage::ofxCvColorImage( const ofxCvColorImage& _mom ) { } } + +//-------------------------------------------------------------------------------- +void ofxCvColorImage::allocateTexture(){ + tex.allocate(pixels); +} + +//-------------------------------------------------------------------------------- +void ofxCvColorImage::allocatePixels(int w, int h){ + pixels.allocate(w,h,OF_PIXELS_RGB); +} + //-------------------------------------------------------------------------------- void ofxCvColorImage::init() { ipldepth = IPL_DEPTH_8U; iplchannels = 3; - gldepth = GL_UNSIGNED_BYTE; - glchannels = GL_RGB; cvGrayscaleImage = NULL; } @@ -161,7 +170,7 @@ void ofxCvColorImage::setFromGrayscalePlanarImages( ofxCvGrayscaleImage& red, of greenRoi.width == roi.width && greenRoi.height == roi.height && blueRoi.width == roi.width && blueRoi.height == roi.height ) { - cvCvtPlaneToPix(red.getCvImage(), green.getCvImage(), blue.getCvImage(),NULL, cvImage); + cvMerge(red.getCvImage(), green.getCvImage(), blue.getCvImage(),NULL, cvImage); flagImageChanged(); } else { ofLogError("ofxCvColorImage") << "setFromGrayscalePlanarImages(): image size or region of interest mismatch"; @@ -322,7 +331,7 @@ void ofxCvColorImage::convertToGrayscalePlanarImages(ofxCvGrayscaleImage& red, o greenRoi.width == roi.width && greenRoi.height == roi.height && blueRoi.width == roi.width && blueRoi.height == roi.height ) { - cvCvtPixToPlane(cvImage, red.getCvImage(), green.getCvImage(), blue.getCvImage(), NULL); + cvSplit(cvImage, red.getCvImage(), green.getCvImage(), blue.getCvImage(), NULL); red.flagImageChanged(); green.flagImageChanged(); blue.flagImageChanged(); @@ -350,15 +359,15 @@ void ofxCvColorImage::convertToGrayscalePlanarImage (ofxCvGrayscaleImage& grayIm switch (whichPlane){ case 0: - cvCvtPixToPlane(cvImage, grayImage.getCvImage(), NULL, NULL, NULL); + cvSplit(cvImage, grayImage.getCvImage(), NULL, NULL, NULL); grayImage.flagImageChanged(); break; case 1: - cvCvtPixToPlane(cvImage, NULL, grayImage.getCvImage(), NULL, NULL); + cvSplit(cvImage, NULL, grayImage.getCvImage(), NULL, NULL); grayImage.flagImageChanged(); break; case 2: - cvCvtPixToPlane(cvImage, NULL, NULL, grayImage.getCvImage(), NULL); + cvSplit(cvImage, NULL, NULL, grayImage.getCvImage(), NULL); grayImage.flagImageChanged(); break; } diff --git a/addons/ofxOpenCv/src/ofxCvColorImage.h b/addons/ofxOpenCv/src/ofxCvColorImage.h index 840d8674b3f..6426ae47e0c 100644 --- a/addons/ofxOpenCv/src/ofxCvColorImage.h +++ b/addons/ofxOpenCv/src/ofxCvColorImage.h @@ -128,7 +128,8 @@ class ofxCvColorImage : public ofxCvImage { protected: - + void allocateTexture(); + void allocatePixels(int w, int h); void init(); IplImage* cvGrayscaleImage; // internal helper grayscale, allocated on demand diff --git a/addons/ofxOpenCv/src/ofxCvContourFinder.cpp b/addons/ofxOpenCv/src/ofxCvContourFinder.cpp index 5b8f5b9de5f..ad00314bd6a 100644 --- a/addons/ofxOpenCv/src/ofxCvContourFinder.cpp +++ b/addons/ofxOpenCv/src/ofxCvContourFinder.cpp @@ -77,7 +77,7 @@ int ofxCvContourFinder::findContours( ofxCvGrayscaleImage& input, contour_storage = cvCreateMemStorage( 1000 ); storage = cvCreateMemStorage( 1000 ); - CvContourRetrievalMode retrieve_mode + int retrieve_mode = (bFindHoles) ? CV_RETR_LIST : CV_RETR_EXTERNAL; cvFindContours( inputCopy.getCvImage(), contour_storage, &contour_list, sizeof(CvContour), retrieve_mode, bUseApproximation ? CV_CHAIN_APPROX_SIMPLE : CV_CHAIN_APPROX_NONE ); diff --git a/addons/ofxOpenCv/src/ofxCvFloatImage.cpp b/addons/ofxOpenCv/src/ofxCvFloatImage.cpp index 761714c5bc9..ecf81df749a 100644 --- a/addons/ofxOpenCv/src/ofxCvFloatImage.cpp +++ b/addons/ofxOpenCv/src/ofxCvFloatImage.cpp @@ -29,8 +29,6 @@ ofxCvFloatImage::ofxCvFloatImage( const ofxCvFloatImage& _mom ) { void ofxCvFloatImage::init() { ipldepth = IPL_DEPTH_32F; iplchannels = 1; - gldepth = GL_FLOAT; - glchannels = GL_LUMINANCE; bFloatPixelsDirty = true; cvGrayscaleImage = NULL; scaleMin = 0.0f; @@ -478,6 +476,17 @@ IplImage* ofxCvFloatImage::getCv8BitsImage() { return cvGrayscaleImage; } + +//-------------------------------------------------------------------------------- +void ofxCvFloatImage::allocateTexture(){ + tex.allocate(floatPixels); +} + +//-------------------------------------------------------------------------------- +void ofxCvFloatImage::allocatePixels(int w, int h){ + floatPixels.allocate(w,h,OF_PIXELS_GRAY); +} + //-------------------------------------------------------------------------------- IplImage* ofxCvFloatImage::getCv8BitsRoiImage() { if( !bAllocated ){ diff --git a/addons/ofxOpenCv/src/ofxCvFloatImage.h b/addons/ofxOpenCv/src/ofxCvFloatImage.h index 3f7bfda1ef7..135d01995da 100644 --- a/addons/ofxOpenCv/src/ofxCvFloatImage.h +++ b/addons/ofxOpenCv/src/ofxCvFloatImage.h @@ -140,7 +140,8 @@ class ofxCvFloatImage : public ofxCvImage { protected: - + void allocateTexture(); + void allocatePixels(int w, int h); void init(); virtual void convertFloatToGray( IplImage* floatImg, IplImage* grayImg ); virtual void convertGrayToFloat( IplImage* grayImg, IplImage* floatImg ); diff --git a/addons/ofxOpenCv/src/ofxCvGrayscaleImage.cpp b/addons/ofxOpenCv/src/ofxCvGrayscaleImage.cpp index d167e2d71ec..460697660e9 100644 --- a/addons/ofxOpenCv/src/ofxCvGrayscaleImage.cpp +++ b/addons/ofxOpenCv/src/ofxCvGrayscaleImage.cpp @@ -32,11 +32,18 @@ ofxCvGrayscaleImage::ofxCvGrayscaleImage( const ofxCvGrayscaleImage& _mom ) { void ofxCvGrayscaleImage::init() { ipldepth = IPL_DEPTH_8U; iplchannels = 1; - gldepth = GL_UNSIGNED_BYTE; - glchannels = GL_LUMINANCE; briConLutMatrix = cvCreateMat(1,256,CV_8UC1); } +//-------------------------------------------------------------------------------- +void ofxCvGrayscaleImage::allocateTexture(){ + tex.allocate(pixels); +} + +//-------------------------------------------------------------------------------- +void ofxCvGrayscaleImage::allocatePixels(int w, int h){ + pixels.allocate(w,h,OF_PIXELS_GRAY); +} // Set Pixel Data - Arrays //------------------------------------------------------------------------------------- diff --git a/addons/ofxOpenCv/src/ofxCvGrayscaleImage.h b/addons/ofxOpenCv/src/ofxCvGrayscaleImage.h index 9fdc70138cf..7dc0ffce4be 100644 --- a/addons/ofxOpenCv/src/ofxCvGrayscaleImage.h +++ b/addons/ofxOpenCv/src/ofxCvGrayscaleImage.h @@ -41,7 +41,6 @@ class ofxCvGrayscaleImage : public ofxCvImage { // ofRectangle& rec2 ); // inbase class - // Set Pixel Data // virtual void set( float value ); @@ -153,5 +152,7 @@ class ofxCvGrayscaleImage : public ofxCvImage { CvMat* briConLutMatrix; void init(); + void allocateTexture(); + void allocatePixels(int w, int h); }; diff --git a/addons/ofxOpenCv/src/ofxCvImage.cpp b/addons/ofxOpenCv/src/ofxCvImage.cpp index 5b08833a65d..ada6b970d70 100644 --- a/addons/ofxOpenCv/src/ofxCvImage.cpp +++ b/addons/ofxOpenCv/src/ofxCvImage.cpp @@ -4,7 +4,7 @@ #include "ofxCvColorImage.h" #include "ofxCvFloatImage.h" #include "ofxCvBlob.h" - +#include "ofConstants.h" @@ -18,6 +18,11 @@ ofxCvImage::ofxCvImage() { bAllocated = false; bPixelsDirty = true; bRoiPixelsDirty = true; + cvImageTemp = nullptr; + bAnchorIsPct = false; + cvImage = nullptr; + ipldepth = 0; + iplchannels = 0; } //-------------------------------------------------------------------------------- @@ -45,7 +50,8 @@ void ofxCvImage::allocate( int w, int h ) { bAllocated = true; if( bUseTexture ) { - tex.allocate( width, height, glchannels ); + allocatePixels(w,h); + allocateTexture(); bTextureDirty = true; } } @@ -415,12 +421,6 @@ void ofxCvImage::updateTexture(){ ofLogWarning("ofxCvImage") << "updateTexture(): image not allocated"; } else if(bUseTexture ) { if( bTextureDirty ) { - if(tex.getWidth() != width || tex.getHeight() != height) { - //ROI was changed - // reallocating texture - this could be faster with ROI support - tex.clear(); - tex.allocate( width, height, glchannels ); - } tex.loadData( getPixels() ); bTextureDirty = false; } @@ -433,38 +433,6 @@ void ofxCvImage::draw( float x, float y, float w, float h ) const { ofxCvImage* mutImage = const_cast(this); mutImage->updateTexture(); tex.draw(x,y, w,h); - } else { - #ifdef TARGET_OPENGLES - ofLogError("ofxCvImage") << "draw(): textureless drawing mode not supported in OpenGL ES"; - #else - // this is slower than the typical draw method based on textures - // but useful when dealing with threads GL textures often don't work - ofLogNotice("ofxCvImage") << "draw(): using textureless drawing mode"; - ofLogNotice("ofxCvImage") << "draw(): drawing is slower, aligned to the window, & does not support rotation"; - - if( x == 0) { - ofLogNotice("ofxCvImage") << "draw(): x position cannot be 0 in textureless drawing mode, setting to 0.01"; - x += 0.01; - } - - if(bAnchorIsPct){ - x -= anchor.x * w; - y -= anchor.y * h; - }else{ - x -= anchor.x; - y -= anchor.y; - } - - glRasterPos2f( x, y+h ); - - IplImage* tempImg; - tempImg = cvCreateImage( cvSize((int)w, (int)h), ipldepth, iplchannels ); - cvResize( cvImage, tempImg, CV_INTER_NN ); - cvFlip( tempImg, tempImg, 0 ); - glDrawPixels( tempImg->width, tempImg->height , - glchannels, gldepth, tempImg->imageData ); - cvReleaseImage( &tempImg ); - #endif } } @@ -479,17 +447,11 @@ void ofxCvImage::drawROI( float x, float y, float w, float h ) const { if( bUseTexture ) { ofRectangle roi = getROI(); if( bTextureDirty ) { - if(tex.getWidth() != roi.width || tex.getHeight() != roi.height) { - //ROI was changed - // reallocating texture - this could be faster with ROI support - tex.clear(); - tex.allocate( (int)roi.width, (int)roi.height, glchannels ); - } tex.loadData( getRoiPixels() ); bTextureDirty = false; } - tex.draw(x,y, w,h); + tex.drawSubsection(x,y, w,h,0,0,roi.width,roi.height); } else { ofLogError("ofxCvImage") << "drawROI(): textureless drawing mode not implemented"; @@ -687,7 +649,9 @@ void ofxCvImage::undistort( float radialDistX, float radialDistY, } float camIntrinsics[] = { focalX, 0, centerX, 0, focalY, centerY, 0, 0, 1 }; float distortionCoeffs[] = { radialDistX, radialDistY, tangentDistX, tangentDistY }; - cvUnDistortOnce( cvImage, cvImageTemp, camIntrinsics, distortionCoeffs, 1 ); + CvMat _a = cvMat( 3, 3, CV_32F, (void*)camIntrinsics ); + CvMat _k = cvMat( 4, 1, CV_32F, (void*)distortionCoeffs ); + cvUndistort2( cvImage, cvImageTemp, &_a, &_k, 0 ); swapTemp(); flagImageChanged(); } @@ -745,7 +709,7 @@ void ofxCvImage::warpPerspective( const ofPoint& A, const ofPoint& B, const ofPo cvsrc[3].x = D.x; cvsrc[3].y = D.y; - cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate ); // calculate homography + cvGetPerspectiveTransform( cvsrc, cvdst, translate ); // calculate homography cvWarpPerspective( cvImage, cvImageTemp, translate ); swapTemp(); flagImageChanged(); @@ -780,7 +744,7 @@ void ofxCvImage::warpIntoMe( ofxCvImage& mom, const ofPoint src[4], const ofPoin cvdst[i].x = dst[i].x; cvdst[i].y = dst[i].y; } - cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate ); // calculate homography + cvGetPerspectiveTransform( cvsrc, cvdst, translate ); // calculate homography cvWarpPerspective( mom.getCvImage(), cvImage, translate); flagImageChanged(); cvReleaseMat( &translate ); diff --git a/addons/ofxOpenCv/src/ofxCvImage.h b/addons/ofxOpenCv/src/ofxCvImage.h index 6870640c801..142a5f02edb 100644 --- a/addons/ofxOpenCv/src/ofxCvImage.h +++ b/addons/ofxOpenCv/src/ofxCvImage.h @@ -154,6 +154,8 @@ class ofxCvImage : public ofBaseImage { protected: + virtual void allocateTexture() = 0; + virtual void allocatePixels(int w, int h) = 0; bool matchingROI( const ofRectangle& rec1, const ofRectangle& rec2 ); virtual void setImageROI( IplImage* img, const ofRectangle& rect ); virtual void resetImageROI( IplImage* img ); @@ -172,9 +174,6 @@ class ofxCvImage : public ofBaseImage { int ipldepth; // IPL_DEPTH_8U, IPL_DEPTH_16U, IPL_DEPTH_32F, ... int iplchannels; // 1, 3, 4, ... - - int gldepth; // GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, ... - int glchannels; // GL_LUMINANCE, GL_RGB, GL_RGBA, ... ofPixels pixels; // not width stepped for getPixels(), allocated on demand ofPixels roiPixels; diff --git a/addons/ofxOpenCv/src/ofxCvShortImage.cpp b/addons/ofxOpenCv/src/ofxCvShortImage.cpp index 600675bd1b8..468b672e6fc 100644 --- a/addons/ofxOpenCv/src/ofxCvShortImage.cpp +++ b/addons/ofxOpenCv/src/ofxCvShortImage.cpp @@ -29,8 +29,6 @@ ofxCvShortImage::ofxCvShortImage( const ofxCvShortImage& _mom ) { void ofxCvShortImage::init() { ipldepth = IPL_DEPTH_16U; iplchannels = 1; - gldepth = GL_UNSIGNED_SHORT; - glchannels = GL_LUMINANCE; cvGrayscaleImage = NULL; bShortPixelsDirty = true; } @@ -51,6 +49,15 @@ void ofxCvShortImage::flagImageChanged() { ofxCvImage::flagImageChanged(); } +//-------------------------------------------------------------------------------- +void ofxCvShortImage::allocateTexture(){ + tex.allocate(shortPixels); +} + +//-------------------------------------------------------------------------------- +void ofxCvShortImage::allocatePixels(int w, int h){ + pixels.allocate(w,h,OF_PIXELS_GRAY); +} //-------------------------------------------------------------------------------- void ofxCvShortImage::convertShortToGray( IplImage* shortImg, IplImage* grayImg ) { diff --git a/addons/ofxOpenCv/src/ofxCvShortImage.h b/addons/ofxOpenCv/src/ofxCvShortImage.h index eb27936adb6..22fee5a8c19 100644 --- a/addons/ofxOpenCv/src/ofxCvShortImage.h +++ b/addons/ofxOpenCv/src/ofxCvShortImage.h @@ -24,6 +24,7 @@ class ofxCvShortImage : public ofxCvImage { // virtual void allocate( int w, int h ); //in base class virtual void clear(); virtual void flagImageChanged(); + //virtual float getWidth(); //in base class //virtual float getHeight(); //in base class // virtual void setUseTexture( bool bUse ); //in base class @@ -120,7 +121,9 @@ class ofxCvShortImage : public ofxCvImage { ofShortPixels & getRoiShortPixelsRef(); protected: - + + void allocatePixels(int w, int h); + void allocateTexture(); void init(); virtual void convertShortToGray( IplImage* floatImg, IplImage* grayImg ); virtual void convertGrayToShort( IplImage* grayImg, IplImage* floatImg ); diff --git a/addons/ofxOsc/addon_config.mk b/addons/ofxOsc/addon_config.mk index 116c028cc6c..ada28e55908 100644 --- a/addons/ofxOsc/addon_config.mk +++ b/addons/ofxOsc/addon_config.mk @@ -68,27 +68,15 @@ common: # a specific platform # ADDON_INCLUDES_EXCLUDE = -win_cb: +msys2: # when parsing the file system looking for sources exclude this for all or # a specific platform - ADDON_SOURCES_EXCLUDE += libs/oscpack/src/ip/posix/% - - # source files, these will be usually parsed from the file system looking - # in the src folders in libs and the root of the addon. if your addon needs - # to include files in different places or a different set of files per platform - # they can be specified here - ADDON_SOURCES += libs/oscpack/src/ip/win32/% + ADDON_SOURCES_EXCLUDE = libs/oscpack/src/ip/posix/% vs: # when parsing the file system looking for sources exclude this for all or # a specific platform - ADDON_SOURCES_EXCLUDE += libs/oscpack/src/ip/posix/% - - # source files, these will be usually parsed from the file system looking - # in the src folders in libs and the root of the addon. if your addon needs - # to include files in different places or a different set of files per platform - # they can be specified here - ADDON_SOURCES += libs/oscpack/src/ip/win32/% + ADDON_SOURCES_EXCLUDE = libs/oscpack/src/ip/posix/% diff --git a/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.cpp b/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.cpp old mode 100755 new mode 100644 index 50b02622160..81e9d9bfb6e --- a/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.cpp +++ b/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.cpp @@ -41,9 +41,10 @@ #include "NetworkingUtils.h" +namespace osc{ unsigned long IpEndpointName::GetHostByName( const char *s ) { - return ::GetHostByName(s); + return osc::GetHostByName(s); } @@ -86,3 +87,4 @@ void IpEndpointName::AddressAndPortAsString( char *s ) const } } } +} diff --git a/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.h b/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.h old mode 100755 new mode 100644 index c83e1c3cfe3..d2387ccf598 --- a/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.h +++ b/addons/ofxOsc/libs/oscpack/src/ip/IpEndpointName.h @@ -38,6 +38,7 @@ #define INCLUDED_OSCPACK_IPENDPOINTNAME_H +namespace osc{ class IpEndpointName{ static unsigned long GetHostByName( const char *s ); public: @@ -79,5 +80,6 @@ inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) { return !(lhs == rhs); } +} #endif /* INCLUDED_OSCPACK_IPENDPOINTNAME_H */ diff --git a/addons/ofxOsc/libs/oscpack/src/ip/NetworkingUtils.h b/addons/ofxOsc/libs/oscpack/src/ip/NetworkingUtils.h old mode 100755 new mode 100644 index a83612aeda5..f029bbbbde9 --- a/addons/ofxOsc/libs/oscpack/src/ip/NetworkingUtils.h +++ b/addons/ofxOsc/libs/oscpack/src/ip/NetworkingUtils.h @@ -38,6 +38,7 @@ #define INCLUDED_OSCPACK_NETWORKINGUTILS_H +namespace osc{ // in general NetworkInitializer is only used internally, but if you're // application creates multiple sockets from different threads at runtime you // should instantiate one of these in main just to make sure the networking @@ -51,6 +52,7 @@ class NetworkInitializer{ // return ip address of host name in host byte order unsigned long GetHostByName( const char *name ); +} #endif /* INCLUDED_OSCPACK_NETWORKINGUTILS_H */ diff --git a/addons/ofxOsc/libs/oscpack/src/ip/PacketListener.h b/addons/ofxOsc/libs/oscpack/src/ip/PacketListener.h old mode 100755 new mode 100644 index 6c26b32996d..e2e0682eeea --- a/addons/ofxOsc/libs/oscpack/src/ip/PacketListener.h +++ b/addons/ofxOsc/libs/oscpack/src/ip/PacketListener.h @@ -38,6 +38,7 @@ #define INCLUDED_OSCPACK_PACKETLISTENER_H +namespace osc{ class IpEndpointName; class PacketListener{ @@ -46,5 +47,6 @@ class PacketListener{ virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) = 0; }; +} #endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/addons/ofxOsc/libs/oscpack/src/ip/TimerListener.h b/addons/ofxOsc/libs/oscpack/src/ip/TimerListener.h old mode 100755 new mode 100644 index 59b4040600f..24936a39048 --- a/addons/ofxOsc/libs/oscpack/src/ip/TimerListener.h +++ b/addons/ofxOsc/libs/oscpack/src/ip/TimerListener.h @@ -38,10 +38,12 @@ #define INCLUDED_OSCPACK_TIMERLISTENER_H +namespace osc{ class TimerListener{ public: virtual ~TimerListener() {} virtual void TimerExpired() = 0; }; +} #endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/addons/ofxOsc/libs/oscpack/src/ip/UdpSocket.h b/addons/ofxOsc/libs/oscpack/src/ip/UdpSocket.h old mode 100755 new mode 100644 index bd516acfbb7..10e277c036f --- a/addons/ofxOsc/libs/oscpack/src/ip/UdpSocket.h +++ b/addons/ofxOsc/libs/oscpack/src/ip/UdpSocket.h @@ -43,6 +43,7 @@ #include "IpEndpointName.h" +namespace osc{ class PacketListener; class TimerListener; @@ -81,6 +82,7 @@ class UdpSocket{ Implementation *impl_; friend class SocketReceiveMultiplexer::Implementation; + static unsigned long maxBufferSize; public: @@ -89,6 +91,20 @@ class UdpSocket{ UdpSocket(); virtual ~UdpSocket(); + // Enable broadcast addresses (e.g. x.x.x.255) + // Sets SO_BROADCAST socket option. + void SetEnableBroadcast( bool enableBroadcast ); + + // Enable multiple listeners for a single port on same + // network interface* + // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). + // [*] The exact behavior of SO_REUSEADDR and + // SO_REUSEPORT is undefined for some common cases + // and may have drastically different behavior on different + // operating systems. + void SetAllowReuse( bool allowReuse ); + + // The socket is created in an unbound, unconnected state // such a socket can only be used to send to an arbitrary // address using SendTo(). To use Send() you need to first @@ -115,21 +131,6 @@ class UdpSocket{ static void SetUdpBufferSize( unsigned long bufferSize ); static unsigned long GetUdpBufferSize(); - -protected: - // Enable broadcast addresses (e.g. x.x.x.255) - // Sets SO_BROADCAST socket option. - void SetEnableBroadcast( bool enableBroadcast ); - - // Enable multiple listeners for a single port on same - // network interface* - // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). - // [*] The exact behavior of SO_REUSEADDR and - // SO_REUSEPORT is undefined for some common cases - // and may have drastically different behavior on different - // operating systems. - void SetAllowReuse( bool allowReuse ); - static unsigned long maxBufferSize; }; @@ -175,6 +176,6 @@ class UdpListeningReceiveSocket : public UdpSocket{ void Break() { mux_.Break(); } void AsynchronousBreak() { mux_.AsynchronousBreak(); } }; - +} #endif /* INCLUDED_OSCPACK_UDPSOCKET_H */ diff --git a/addons/ofxOsc/libs/oscpack/src/ip/posix/NetworkingUtils.cpp b/addons/ofxOsc/libs/oscpack/src/ip/posix/NetworkingUtils.cpp old mode 100755 new mode 100644 index 7f366054724..c669a775755 --- a/addons/ofxOsc/libs/oscpack/src/ip/posix/NetworkingUtils.cpp +++ b/addons/ofxOsc/libs/oscpack/src/ip/posix/NetworkingUtils.cpp @@ -44,6 +44,7 @@ +namespace osc{ NetworkInitializer::NetworkInitializer() {} NetworkInitializer::~NetworkInitializer() {} @@ -62,3 +63,4 @@ unsigned long GetHostByName( const char *name ) return result; } +} diff --git a/addons/ofxOsc/libs/oscpack/src/ip/posix/UdpSocket.cpp b/addons/ofxOsc/libs/oscpack/src/ip/posix/UdpSocket.cpp old mode 100755 new mode 100644 index a8f82b4393d..7e27bd1c0b1 --- a/addons/ofxOsc/libs/oscpack/src/ip/posix/UdpSocket.cpp +++ b/addons/ofxOsc/libs/oscpack/src/ip/posix/UdpSocket.cpp @@ -61,6 +61,7 @@ #include "ip/TimerListener.h" +namespace osc{ #if defined(__APPLE__) && !defined(_SOCKLEN_T) // pre system 10.3 didn't have socklen_t typedef ssize_t socklen_t; @@ -622,3 +623,4 @@ void SocketReceiveMultiplexer::AsynchronousBreak() impl_->AsynchronousBreak(); } +} diff --git a/addons/ofxOsc/libs/oscpack/src/ip/win32/NetworkingUtils.cpp b/addons/ofxOsc/libs/oscpack/src/ip/win32/NetworkingUtils.cpp old mode 100755 new mode 100644 index f5f7c8e2663..22621294b87 --- a/addons/ofxOsc/libs/oscpack/src/ip/win32/NetworkingUtils.cpp +++ b/addons/ofxOsc/libs/oscpack/src/ip/win32/NetworkingUtils.cpp @@ -42,6 +42,7 @@ #include +namespace osc{ static LONG initCount_ = 0; static bool winsockInitialized_ = false; @@ -93,3 +94,4 @@ unsigned long GetHostByName( const char *name ) return result; } +} diff --git a/addons/ofxOsc/libs/oscpack/src/ip/win32/UdpSocket.cpp b/addons/ofxOsc/libs/oscpack/src/ip/win32/UdpSocket.cpp old mode 100755 new mode 100644 index a6e81a1d5bd..a16f74a78c4 --- a/addons/ofxOsc/libs/oscpack/src/ip/win32/UdpSocket.cpp +++ b/addons/ofxOsc/libs/oscpack/src/ip/win32/UdpSocket.cpp @@ -61,6 +61,7 @@ typedef int socklen_t; +namespace osc{ static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) { std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); @@ -447,12 +448,8 @@ class SocketReceiveMultiplexer::Implementation{ timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - unsigned long maxSize = UdpSocket::GetUdpBufferSize(); - if( maxSize == 0 ) { - maxSize = 4098; - } - const unsigned long MAX_BUFFER_SIZE = maxSize; - char * data = new char[ MAX_BUFFER_SIZE ]; + const int MAX_BUFFER_SIZE = 4098; + char *data = new char[ MAX_BUFFER_SIZE ]; IpEndpointName remoteEndpoint; while( !break_ ){ @@ -591,3 +588,4 @@ void SocketReceiveMultiplexer::AsynchronousBreak() impl_->AsynchronousBreak(); } +} diff --git a/addons/ofxOsc/libs/oscpack/src/osc/MessageMappingOscPacketListener.h b/addons/ofxOsc/libs/oscpack/src/osc/MessageMappingOscPacketListener.h old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscException.h b/addons/ofxOsc/libs/oscpack/src/osc/OscException.h old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscHostEndianness.h b/addons/ofxOsc/libs/oscpack/src/osc/OscHostEndianness.h old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.cpp b/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.cpp old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.h b/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.h old mode 100755 new mode 100644 index 3cc28350813..2ca851788b4 --- a/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.h +++ b/addons/ofxOsc/libs/oscpack/src/osc/OscOutboundPacketStream.h @@ -105,7 +105,7 @@ class OutboundPacketStream{ OutboundPacketStream& operator<<( const InfinitumType& rhs ); OutboundPacketStream& operator<<( int32 rhs ); -#if !(defined(__x86_64__) || defined(_M_X64)) +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__LP64__)) OutboundPacketStream& operator<<( int rhs ) { *this << (int32)rhs; return *this; } #endif diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscPacketListener.h b/addons/ofxOsc/libs/oscpack/src/osc/OscPacketListener.h old mode 100755 new mode 100644 index 472cb1066f6..beed84d9e8c --- a/addons/ofxOsc/libs/oscpack/src/osc/OscPacketListener.h +++ b/addons/ofxOsc/libs/oscpack/src/osc/OscPacketListener.h @@ -46,7 +46,7 @@ namespace osc{ class OscPacketListener : public PacketListener{ protected: virtual void ProcessBundle( const osc::ReceivedBundle& b, - const IpEndpointName& remoteEndpoint ) + const osc::IpEndpointName& remoteEndpoint ) { // ignore bundle time tag for now @@ -60,11 +60,11 @@ class OscPacketListener : public PacketListener{ } virtual void ProcessMessage( const osc::ReceivedMessage& m, - const IpEndpointName& remoteEndpoint ) = 0; + const osc::IpEndpointName& remoteEndpoint ) = 0; public: virtual void ProcessPacket( const char *data, int size, - const IpEndpointName& remoteEndpoint ) + const osc::IpEndpointName& remoteEndpoint ) { osc::ReceivedPacket p( data, size ); if( p.IsBundle() ) diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.cpp b/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.cpp old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.h b/addons/ofxOsc/libs/oscpack/src/osc/OscPrintReceivedElements.h old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.cpp b/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.cpp old mode 100755 new mode 100644 index 1d57d3740a5..14bbe39c19b --- a/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.cpp +++ b/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.cpp @@ -249,7 +249,7 @@ int32 ReceivedMessageArgument::AsInt32Unchecked() const return u.i; #else - return *(int32*)argument_; + return *(int32*)argumentPtr_; #endif } @@ -280,7 +280,7 @@ float ReceivedMessageArgument::AsFloatUnchecked() const return u.f; #else - return *(float*)argument_; + return *(float*)argumentPtr_; #endif } @@ -400,7 +400,7 @@ double ReceivedMessageArgument::AsDoubleUnchecked() const return u.d; #else - return *(double*)argument_; + return *(double*)argumentPtr_; #endif } diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.h b/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.h old mode 100755 new mode 100644 index b6205f31687..f0604dd645a --- a/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.h +++ b/addons/ofxOsc/libs/oscpack/src/osc/OscReceivedElements.h @@ -100,7 +100,7 @@ class ReceivedPacket{ : contents_( contents ) , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} -#if !(defined(__x86_64__) || defined(_M_X64)) +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__LP64__)) ReceivedPacket( const char *contents, int size ) : contents_( contents ) , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.cpp b/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.cpp old mode 100755 new mode 100644 diff --git a/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.h b/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.h old mode 100755 new mode 100644 index 610020182e3..a29c5f3aca0 --- a/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.h +++ b/addons/ofxOsc/libs/oscpack/src/osc/OscTypes.h @@ -47,7 +47,7 @@ namespace osc{ typedef __int64 int64; typedef unsigned __int64 uint64; -#elif defined(__x86_64__) || defined(_M_X64) +#elif defined(__x86_64__) || defined(_M_X64) || defined(__LP64__) typedef long int64; typedef unsigned long uint64; @@ -61,7 +61,7 @@ typedef unsigned long long uint64; -#if defined(__x86_64__) || defined(_M_X64) +#if defined(__x86_64__) || defined(_M_X64) || defined(__LP64__) typedef signed int int32; typedef unsigned int uint32; diff --git a/addons/ofxOsc/src/ofxOscArg.h b/addons/ofxOsc/src/ofxOscArg.h index ac6cc9de0c0..d77874bc1b0 100644 --- a/addons/ofxOsc/src/ofxOscArg.h +++ b/addons/ofxOsc/src/ofxOscArg.h @@ -101,7 +101,7 @@ subclasses for each possible argument type class ofxOscArgInt32 : public ofxOscArg { public: - ofxOscArgInt32( int32_t _value ) { value = _value; }; + ofxOscArgInt32( std::int32_t _value ) { value = _value; }; ~ofxOscArgInt32() {}; /// return the type of this argument @@ -109,25 +109,25 @@ class ofxOscArgInt32 : public ofxOscArg std::string getTypeName() { return "i"; }; /// return value - int32_t get() const { return value; }; + std::int32_t get() const { return value; }; /// set value - void set( int32_t _value ) { value = _value; }; + void set( std::int32_t _value ) { value = _value; }; private: - int32_t value; + std::int32_t value; }; class ofxOscArgInt : public ofxOscArgInt32 { public: - ofxOscArgInt( int32_t _value ) : ofxOscArgInt32(_value) {}; + ofxOscArgInt( std::int32_t _value ) : ofxOscArgInt32(_value) {}; ~ofxOscArgInt(){}; }; class ofxOscArgInt64 : public ofxOscArg { public: - ofxOscArgInt64( int64_t _value ) { value = _value; }; + ofxOscArgInt64( std::int64_t _value ) { value = _value; }; ~ofxOscArgInt64() {}; /// return the type of this argument @@ -135,12 +135,12 @@ class ofxOscArgInt64 : public ofxOscArg std::string getTypeName() { return "h"; }; /// return value - int64_t get() const { return value; }; + std::int64_t get() const { return value; }; /// set value - void set( int64_t _value ) { value = _value; }; + void set( std::int64_t _value ) { value = _value; }; private: - int64_t value; + std::int64_t value; }; class ofxOscArgFloat : public ofxOscArg @@ -151,7 +151,7 @@ class ofxOscArgFloat : public ofxOscArg /// return the type of this argument ofxOscArgType getType() { return OFXOSC_TYPE_FLOAT; }; - string getTypeName() { return "f"; }; + std::string getTypeName() { return "f"; }; /// return value float get() const { return value; }; @@ -184,7 +184,7 @@ class ofxOscArgDouble : public ofxOscArg class ofxOscArgString : public ofxOscArg { public: - ofxOscArgString( std::string _value ) { value = _value; }; + ofxOscArgString( const std::string &_value ) { value = _value; }; ~ofxOscArgString() {}; /// return the type of this argument @@ -192,10 +192,10 @@ class ofxOscArgString : public ofxOscArg std::string getTypeName() { return "s"; }; /// return value - std::string get() const { return value; } + const std::string &get() const { return value; } /// set value void set( const char* _value ) { value = _value; }; - void set( std::string _value ) {value = _value; }; + void set( const std::string &_value ) {value = _value; }; private: std::string value; @@ -204,7 +204,7 @@ class ofxOscArgString : public ofxOscArg class ofxOscArgSymbol : public ofxOscArgString { public: - ofxOscArgSymbol( std::string _value ) : ofxOscArgString(_value){}; + ofxOscArgSymbol( const std::string &_value ) : ofxOscArgString(_value){}; ~ofxOscArgSymbol() {}; /// return the type of this argument @@ -234,7 +234,7 @@ class ofxOscArgChar : public ofxOscArg class ofxOscArgMidiMessage : public ofxOscArgInt32 { public: - ofxOscArgMidiMessage( int32_t _value ) : ofxOscArgInt32(_value) {}; + ofxOscArgMidiMessage( std::int32_t _value ) : ofxOscArgInt32(_value) {}; ~ofxOscArgMidiMessage() {}; /// return the type of this argument @@ -285,7 +285,7 @@ class ofxOscArgTrigger : public ofxOscArgBool class ofxOscArgTimetag : public ofxOscArgInt64 { public: - ofxOscArgTimetag( int64_t _value ) : ofxOscArgInt64(_value) {}; + ofxOscArgTimetag( std::int64_t _value ) : ofxOscArgInt64(_value) {}; ~ofxOscArgTimetag() {}; /// return the type of this argument @@ -296,7 +296,7 @@ class ofxOscArgTimetag : public ofxOscArgInt64 class ofxOscArgBlob : public ofxOscArg { public: - ofxOscArgBlob( ofBuffer _value ){ + ofxOscArgBlob( const ofBuffer &_value ){ value = _value; } ~ofxOscArgBlob(){}; @@ -306,7 +306,7 @@ class ofxOscArgBlob : public ofxOscArg std::string getTypeName() { return "b"; }; /// return value - ofBuffer get() const { return value; }; + const ofBuffer &get() const { return value; }; /// set value void set( const char * _value, unsigned int length ) { value.set(_value, length); }; @@ -317,7 +317,7 @@ class ofxOscArgBlob : public ofxOscArg class ofxOscArgRgbaColor : public ofxOscArg { public: - ofxOscArgRgbaColor( int32_t _value ) {value = _value;}; + ofxOscArgRgbaColor( std::int32_t _value ) { value = _value; }; ~ofxOscArgRgbaColor() {}; /// return the type of this argument @@ -325,11 +325,11 @@ class ofxOscArgRgbaColor : public ofxOscArg std::string getTypeName() { return "r"; }; /// return value - int32_t get() const { return value; }; + std::int32_t get() const { return value; }; /// set value - void set( int32_t _value ) { value = _value; }; + void set( std::int32_t _value ) { value = _value; }; private: - int32_t value; + std::int32_t value; }; diff --git a/addons/ofxOsc/src/ofxOscMessage.cpp b/addons/ofxOsc/src/ofxOscMessage.cpp index 6296bd1b96c..b0dac2001ca 100644 --- a/addons/ofxOsc/src/ofxOscMessage.cpp +++ b/addons/ofxOsc/src/ofxOscMessage.cpp @@ -71,7 +71,7 @@ ofxOscArgType ofxOscMessage::getArgType( int index ) const return args[index]->getType(); } -string ofxOscMessage::getArgTypeName( int index ) const +std::string ofxOscMessage::getArgTypeName( int index ) const { if ( index >= (int)args.size() ) { @@ -82,19 +82,19 @@ string ofxOscMessage::getArgTypeName( int index ) const return args[index]->getTypeName(); } -int32_t ofxOscMessage::getArgAsInt( int index ) const +std::int32_t ofxOscMessage::getArgAsInt( int index ) const { return getArgAsInt32(index); } -int32_t ofxOscMessage::getArgAsInt32( int index ) const +std::int32_t ofxOscMessage::getArgAsInt32( int index ) const { if ( getArgType(index) != OFXOSC_TYPE_INT32 ) { if ( getArgType( index ) == OFXOSC_TYPE_FLOAT ) { ofLogWarning("ofxOscMessage") << "getArgAsInt32(): converting float to int32 for argument " << index; - return (int32_t)((ofxOscArgFloat*)args[index])->get(); + return (std::int32_t)((ofxOscArgFloat*)args[index])->get(); } else { @@ -106,14 +106,14 @@ int32_t ofxOscMessage::getArgAsInt32( int index ) const return ((ofxOscArgInt32*)args[index])->get(); } -int64_t ofxOscMessage::getArgAsInt64( int index ) const +std::int64_t ofxOscMessage::getArgAsInt64( int index ) const { if ( getArgType(index) != OFXOSC_TYPE_INT64 ) { if ( getArgType( index ) == OFXOSC_TYPE_FLOAT ) { ofLogWarning("ofxOscMessage") << "getArgAsInt64(): converting float to int64 for argument " << index; - return (int64_t)((ofxOscArgFloat*)args[index])->get(); + return (std::int64_t)((ofxOscArgFloat*)args[index])->get(); } else { @@ -232,14 +232,14 @@ char ofxOscMessage::getArgAsChar(int index) const } } -int32_t ofxOscMessage::getArgAsMidiMessage(int index) const +std::int32_t ofxOscMessage::getArgAsMidiMessage(int index) const { if ( getArgType(index) != OFXOSC_TYPE_INT32 ) { if ( getArgType( index ) == OFXOSC_TYPE_FLOAT ) { ofLogWarning("ofxOscMessage") << "getArgAsInt32(): converting float to int32 for argument " << index; - return (int32_t)((ofxOscArgFloat*)args[index])->get(); + return (std::int32_t)((ofxOscArgFloat*)args[index])->get(); } else { @@ -306,14 +306,14 @@ bool ofxOscMessage::getArgAsInfinitum(int index) const return getArgAsTrigger(index); } -int64_t ofxOscMessage::getArgAsTimetag(int index) const +std::int64_t ofxOscMessage::getArgAsTimetag(int index) const { if ( getArgType(index) != OFXOSC_TYPE_TIMETAG ) { if ( getArgType( index ) == OFXOSC_TYPE_DOUBLE ) { ofLogWarning("ofxOscMessage") << "getArgAsTimetag(): converting double to Timetag for argument " << index; - return (int32_t)((ofxOscArgFloat*)args[index])->get(); + return (std::int32_t)((ofxOscArgFloat*)args[index])->get(); } else { @@ -336,7 +336,16 @@ ofBuffer ofxOscMessage::getArgAsBlob( int index ) const return ((ofxOscArgBlob*)args[index])->get(); } - +std::int32_t ofxOscMessage::getArgAsRgbaColor( int index ) const +{ + if ( getArgType(index) != OFXOSC_TYPE_RGBA_COLOR ) + { + ofLogError("ofxOscMessage") << "getArgAsRgbaColor(): argument " << index << " is not a rgba color"; + return 0; + } + else + return ((ofxOscArgRgbaColor*)args[index])->get(); +} /* @@ -344,17 +353,17 @@ set methods */ -void ofxOscMessage::addIntArg( int32_t argument ) +void ofxOscMessage::addIntArg( std::int32_t argument ) { args.push_back( new ofxOscArgInt32( argument ) ); } -void ofxOscMessage::addInt32Arg( int32_t argument ) +void ofxOscMessage::addInt32Arg( std::int32_t argument ) { args.push_back( new ofxOscArgInt32( argument ) ); } -void ofxOscMessage::addInt64Arg( int64_t argument ) +void ofxOscMessage::addInt64Arg( std::int64_t argument ) { args.push_back( new ofxOscArgInt64( argument ) ); } @@ -369,12 +378,12 @@ void ofxOscMessage::addDoubleArg( double argument ) args.push_back( new ofxOscArgDouble( argument ) ); } -void ofxOscMessage::addStringArg( string argument ) +void ofxOscMessage::addStringArg( const std::string &argument ) { args.push_back( new ofxOscArgString( argument ) ); } -void ofxOscMessage::addSymbolArg( string argument ) +void ofxOscMessage::addSymbolArg( const std::string &argument ) { args.push_back( new ofxOscArgSymbol( argument ) ); } @@ -384,7 +393,7 @@ void ofxOscMessage::addCharArg( char argument ) args.push_back( new ofxOscArgChar( argument ) ); } -void ofxOscMessage::addMidiMessageArg( int32_t argument ) +void ofxOscMessage::addMidiMessageArg( std::int32_t argument ) { args.push_back( new ofxOscArgMidiMessage( argument ) ); } @@ -409,17 +418,17 @@ void ofxOscMessage::addInfinitumArg() args.push_back( new ofxOscArgTrigger() ); } -void ofxOscMessage::addTimetagArg( int64_t argument ) +void ofxOscMessage::addTimetagArg( std::int64_t argument ) { args.push_back( new ofxOscArgBool( argument ) ); } -void ofxOscMessage::addBlobArg( ofBuffer argument ) +void ofxOscMessage::addBlobArg( const ofBuffer &argument ) { args.push_back( new ofxOscArgBlob( argument ) ); } -void ofxOscMessage::addRgbaColorArg( int32_t argument ) +void ofxOscMessage::addRgbaColorArg( std::int32_t argument ) { args.push_back( new ofxOscArgRgbaColor( argument ) ); } @@ -467,8 +476,8 @@ ofxOscMessage& ofxOscMessage::copy( const ofxOscMessage& other ) args.push_back( new ofxOscArgTimetag( other.getArgAsTimetag( i ) ) ); else if ( argType == OFXOSC_TYPE_BLOB ) args.push_back( new ofxOscArgBlob( other.getArgAsBlob( i ) ) ); - //else if ( argType == OFXOSC_TYPE_RGBA_COLOR ) - // args.push_back( new ofxOscArgRgbaColor( other.getArgAsRgbaColor( i ) ) ); + else if ( argType == OFXOSC_TYPE_RGBA_COLOR ) + args.push_back( new ofxOscArgRgbaColor( other.getArgAsRgbaColor( i ) ) ); else { assert( false && "bad argument type" ); diff --git a/addons/ofxOsc/src/ofxOscMessage.h b/addons/ofxOsc/src/ofxOscMessage.h index 88bab2d2719..01cbb367d4e 100644 --- a/addons/ofxOsc/src/ofxOscMessage.h +++ b/addons/ofxOsc/src/ofxOscMessage.h @@ -32,7 +32,7 @@ #include #include -using namespace std; +using namespace std; // could we remove this? class ofxOscMessage { @@ -48,10 +48,10 @@ class ofxOscMessage void clear(); /// return the address - string getAddress() const { return address; } + std::string getAddress() const { return address; } /// return the remote ip - string getRemoteIp() const { return remote_host; } + std::string getRemoteIp() const { return remote_host; } /// return the remote port int getRemotePort() const { return remote_port; } @@ -61,7 +61,7 @@ class ofxOscMessage ofxOscArgType getArgType( int index ) const; /// return argument type name as string /// - either "int", "float", or "string" - string getArgTypeName( int index ) const; + std::string getArgTypeName( int index ) const; /// get the argument with the given index as an int, float, or string /// ensure that the type matches what you're requesting @@ -85,51 +85,51 @@ class ofxOscMessage See : http://cnmat.berkeley.edu/system/files/attachments/Nime09OSCfinal.pdf */ - int32_t getArgAsInt( int index ) const; - int32_t getArgAsInt32( int index ) const; - int64_t getArgAsInt64( int index ) const; + std::int32_t getArgAsInt( int index ) const; + std::int32_t getArgAsInt32( int index ) const; + std::int64_t getArgAsInt64( int index ) const; float getArgAsFloat( int index ) const; double getArgAsDouble( int index ) const; std::string getArgAsString( int index ) const; std::string getArgAsSymbol( int index ) const; char getArgAsChar( int index ) const; - int32_t getArgAsMidiMessage( int index ) const; + std::int32_t getArgAsMidiMessage( int index ) const; bool getArgAsBool(int index) const; bool getArgAsTrigger(int index) const; bool getArgAsImpulse(int index) const; bool getArgAsInfinitum(int index) const; - int64_t getArgAsTimetag( int index ) const; + std::int64_t getArgAsTimetag( int index ) const; ofBuffer getArgAsBlob( int index ) const; - int32_t getArgAsRgbaColor( int index ) const; + std::int32_t getArgAsRgbaColor( int index ) const; /// message construction - void setAddress( string _address ) { address = _address; }; + void setAddress( const std::string &_address ) { address = _address; }; /// host and port of the remote endpoint - void setRemoteEndpoint( string host, int port ) { remote_host = host; remote_port = port; } + void setRemoteEndpoint( const std::string &host, int port ) { remote_host = host; remote_port = port; } - void addIntArg( int32_t argument ); - void addInt32Arg( int32_t argument ); - void addInt64Arg( int64_t argument ); + void addIntArg( std::int32_t argument ); + void addInt32Arg( std::int32_t argument ); + void addInt64Arg( std::int64_t argument ); void addFloatArg( float argument ); void addDoubleArg( double argument ); - void addStringArg( string argument ); - void addSymbolArg( string argument ); + void addStringArg( const std::string &argument ); + void addSymbolArg( const std::string &argument ); void addCharArg( char argument ); - void addMidiMessageArg( int32_t argument ); + void addMidiMessageArg( std::int32_t argument ); void addBoolArg( bool argument ); void addTriggerArg(); void addImpulseArg(); void addInfinitumArg(); - void addTimetagArg( int64_t argument ); - void addBlobArg( ofBuffer argument ); - void addRgbaColorArg( int32_t argument ); + void addTimetagArg( std::int64_t argument ); + void addBlobArg( const ofBuffer &argument ); + void addRgbaColorArg( std::int32_t argument ); private: - string address; - vector args; + std::string address; + std::vector args; - string remote_host; + std::string remote_host; int remote_port; diff --git a/addons/ofxOsc/src/ofxOscParameterSync.cpp b/addons/ofxOsc/src/ofxOscParameterSync.cpp index 63e204343e5..39f69055e2e 100644 --- a/addons/ofxOsc/src/ofxOscParameterSync.cpp +++ b/addons/ofxOsc/src/ofxOscParameterSync.cpp @@ -16,7 +16,7 @@ ofxOscParameterSync::~ofxOscParameterSync(){ } -void ofxOscParameterSync::setup(ofParameterGroup & group, int localPort, string host, int remotePort){ +void ofxOscParameterSync::setup(ofParameterGroup & group, int localPort, const std::string& host, int remotePort){ syncGroup = group; ofAddListener(syncGroup.parameterChangedE(),this,&ofxOscParameterSync::parameterChanged); sender.setup(host,remotePort); diff --git a/addons/ofxOsc/src/ofxOscParameterSync.h b/addons/ofxOsc/src/ofxOscParameterSync.h index 28ee763a9f7..be65bd7f25d 100644 --- a/addons/ofxOsc/src/ofxOscParameterSync.h +++ b/addons/ofxOsc/src/ofxOscParameterSync.h @@ -18,7 +18,7 @@ class ofxOscParameterSync { ~ofxOscParameterSync(); /// the remote and local ports must be different to avoid collisions - void setup(ofParameterGroup & group, int localPort, string remoteHost, int remotePort); + void setup(ofParameterGroup & group, int localPort, const std::string& remoteHost, int remotePort); void update(); private: diff --git a/addons/ofxOsc/src/ofxOscReceiver.cpp b/addons/ofxOsc/src/ofxOscReceiver.cpp index b8100c741e8..2a6bb150955 100644 --- a/addons/ofxOsc/src/ofxOscReceiver.cpp +++ b/addons/ofxOsc/src/ofxOscReceiver.cpp @@ -35,118 +35,80 @@ #include ofxOscReceiver::ofxOscReceiver() +:allowReuse(true) +,listen_port(0) { - listen_socket = NULL; } -void ofxOscReceiver::setup( int listen_port, bool allowReuse ) +ofxOscReceiver::ofxOscReceiver(const ofxOscReceiver & mom) +:allowReuse(mom.allowReuse) +,listen_port(mom.listen_port){ + if(mom.listen_socket){ + setup(listen_port); + } +} + +ofxOscReceiver & ofxOscReceiver::operator=(const ofxOscReceiver & mom){ + if(this == &mom) return *this; + + allowReuse = mom.allowReuse; + listen_port = mom.listen_port; + if(mom.listen_socket){ + setup(listen_port); + } + return *this; +} + +void ofxOscReceiver::setup( int listen_port ) { - if( UdpSocket::GetUdpBufferSize() == 0 ){ - UdpSocket::SetUdpBufferSize(65535); + if( osc::UdpSocket::GetUdpBufferSize() == 0 ){ + osc::UdpSocket::SetUdpBufferSize(65535); } // if we're already running, shutdown before running again - if ( listen_socket ) + if ( listen_socket ){ shutdown(); - - // create the mutex - #ifdef TARGET_WIN32 - mutex = CreateMutexA( NULL, FALSE, NULL ); - #else - pthread_mutex_init( &mutex, NULL ); - #endif + } // create socket - socketHasShutdown = false; - listen_socket = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, listen_port ), this, allowReuse ); - - // start thread - #ifdef TARGET_WIN32 - thread = CreateThread( - NULL, // default security attributes - 0, // use default stack size - &ofxOscReceiver::startThread, // thread function - (void*)this, // argument to thread function - 0, // use default creation flags - NULL); // we don't the the thread id - - #else - pthread_create( &thread, NULL, &ofxOscReceiver::startThread, (void*)this ); - #endif -} - -void ofxOscReceiver::shutdown() -{ - if ( listen_socket ) - { + auto socket = new osc::UdpListeningReceiveSocket( osc::IpEndpointName( osc::IpEndpointName::ANY_ADDRESS, listen_port ), this, allowReuse ); + auto deleter = [](osc::UdpListeningReceiveSocket*socket){ // tell the socket to shutdown - listen_socket->AsynchronousBreak(); - // wait for shutdown to complete - while (!socketHasShutdown) - { - #ifdef TARGET_WIN32 - Sleep(1); - #else - // sleep 0.1ms - usleep(100); - #endif - } - - // thread will clean up itself - - // clean up the mutex - #ifdef TARGET_WIN32 - ReleaseMutex( mutex ); - #else - pthread_mutex_destroy( &mutex ); - #endif - - // delete the socket - delete listen_socket; - listen_socket = NULL; - } + socket->Break(); + delete socket; + }; + auto new_ptr = std::unique_ptr(socket, deleter); + listen_socket = std::move(new_ptr); + + listen_thread = std::thread([this]{ + listen_socket->Run(); + }); + + // detach thread so we don't have to wait on it before creating a new socket + // or on destruction, the custom deleter for the socket unique_ptr already + // does the right thing + listen_thread.detach(); + + this->listen_port = listen_port; } -ofxOscReceiver::~ofxOscReceiver() -{ - shutdown(); -} - -#ifdef TARGET_WIN32 -DWORD WINAPI -#else -void* -#endif - -ofxOscReceiver::startThread( void* receiverInstance ) +void ofxOscReceiver::shutdown() { - // cast the instance - ofxOscReceiver* instance = (ofxOscReceiver*)receiverInstance; - // start the socket listener - instance->listen_socket->Run(); - // socket listener has finished - remember this fact - instance->socketHasShutdown = true; - // return - #ifdef TARGET_WIN32 - return 0; - #else - return NULL; - #endif + listen_socket.reset(); } -void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const IpEndpointName& remoteEndpoint ) +void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const osc::IpEndpointName& remoteEndpoint ) { - // convert the message to an ofxOscMessage - ofxOscMessage* ofMessage = new ofxOscMessage(); + ofxOscMessage msg; // set the address - ofMessage->setAddress( m.AddressPattern() ); + msg.setAddress( m.AddressPattern() ); // set the sender ip/host - char endpoint_host[ IpEndpointName::ADDRESS_STRING_LENGTH ]; + char endpoint_host[ osc::IpEndpointName::ADDRESS_STRING_LENGTH ]; remoteEndpoint.AddressAsString( endpoint_host ); - ofMessage->setRemoteEndpoint( endpoint_host, remoteEndpoint.port ); + msg.setRemoteEndpoint( endpoint_host, remoteEndpoint.port ); // transfer the arguments for ( osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); @@ -154,35 +116,35 @@ void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const IpEndp ++arg ) { if ( arg->IsInt32() ) - ofMessage->addIntArg( arg->AsInt32Unchecked() ); + msg.addIntArg( arg->AsInt32Unchecked() ); else if ( arg->IsInt64() ) - ofMessage->addInt64Arg( arg->AsInt64Unchecked() ); + msg.addInt64Arg( arg->AsInt64Unchecked() ); else if ( arg->IsFloat() ) - ofMessage->addFloatArg( arg->AsFloatUnchecked() ); + msg.addFloatArg( arg->AsFloatUnchecked() ); else if ( arg->IsDouble() ) - ofMessage->addDoubleArg( arg->AsDoubleUnchecked() ); + msg.addDoubleArg( arg->AsDoubleUnchecked() ); else if ( arg->IsString() ) - ofMessage->addStringArg( arg->AsStringUnchecked() ); + msg.addStringArg( arg->AsStringUnchecked() ); else if ( arg->IsSymbol() ) - ofMessage->addSymbolArg( arg->AsSymbolUnchecked() ); + msg.addSymbolArg( arg->AsSymbolUnchecked() ); else if ( arg->IsChar() ) - ofMessage->addCharArg( arg->AsCharUnchecked() ); + msg.addCharArg( arg->AsCharUnchecked() ); else if ( arg->IsMidiMessage() ) - ofMessage->addMidiMessageArg( arg->AsMidiMessageUnchecked() ); + msg.addMidiMessageArg( arg->AsMidiMessageUnchecked() ); else if ( arg->IsBool()) - ofMessage->addBoolArg( arg->AsBoolUnchecked() ); + msg.addBoolArg( arg->AsBoolUnchecked() ); else if ( arg->IsInfinitum() ) - ofMessage->addTriggerArg(); + msg.addTriggerArg(); else if ( arg->IsTimeTag() ) - ofMessage->addTimetagArg( arg->AsTimeTagUnchecked() ); + msg.addTimetagArg( arg->AsTimeTagUnchecked() ); else if ( arg->IsRgbaColor() ) - ofMessage->addRgbaColorArg( arg->AsRgbaColorUnchecked() ); + msg.addRgbaColorArg( arg->AsRgbaColorUnchecked() ); else if ( arg->IsBlob() ){ const char * dataPtr; osc::osc_bundle_element_size_t len = 0; arg->AsBlobUnchecked((const void*&)dataPtr, len); ofBuffer buffer(dataPtr, len); - ofMessage->addBlobArg( buffer ); + msg.addBlobArg( buffer ); } else { @@ -190,80 +152,32 @@ void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const IpEndp } } - // now add to the queue - - // at this point we are running inside the thread created by startThread, - // so anyone who calls hasWaitingMessages() or getNextMessage() is coming - // from a different thread - - // so we have to practise shared memory management - - // grab a lock on the queue - grabMutex(); - - // add incoming message on to the queue - messages.push_back( ofMessage ); - - // release the lock - releaseMutex(); + // send msg to main thread + messagesChannel.send( std::move(msg) ); } bool ofxOscReceiver::hasWaitingMessages() { - // grab a lock on the queue - grabMutex(); - - // check the length of the queue - int queue_length = (int)messages.size(); - - // release the lock - releaseMutex(); - - // return whether we have any messages - return queue_length > 0; + return !messagesChannel.empty(); } -bool ofxOscReceiver::getNextMessage( ofxOscMessage* message ) +bool ofxOscReceiver::getNextMessage( ofxOscMessage * message ) { - // grab a lock on the queue - grabMutex(); - - // check if there are any to be got - if ( messages.size() == 0 ) - { - // no: release the mutex - releaseMutex(); - return false; - } - - // copy the message from the queue to message - ofxOscMessage* src_message = messages.front(); - message->copy( *src_message ); - - // now delete the src message - delete src_message; - // and remove it from the queue - messages.pop_front(); - - // release the lock on the queue - releaseMutex(); - - // return success - return true; + return getNextMessage(*message); } +bool ofxOscReceiver::getNextMessage( ofxOscMessage & message ) +{ + return messagesChannel.tryReceive(message); +} -bool ofxOscReceiver::getParameter(ofAbstractParameter & parameter){ +bool ofxOscReceiver::getParameter(ofAbstractParameter & parameter) +{ ofxOscMessage msg; - if ( messages.size() == 0 ) return false; - while(hasWaitingMessages()){ + while(messagesChannel.tryReceive(msg)){ ofAbstractParameter * p = ¶meter; - - getNextMessage(&msg); - vector address = ofSplitString(msg.getAddress(),"/",true); - + std::vector address = ofSplitString(msg.getAddress(),"/",true); for(unsigned int i=0;igetEscapedName()){ if(p->type()==typeid(ofParameterGroup).name()){ @@ -295,20 +209,16 @@ bool ofxOscReceiver::getParameter(ofAbstractParameter & parameter){ return true; } -void ofxOscReceiver::grabMutex() -{ -#ifdef TARGET_WIN32 - WaitForSingleObject( mutex, INFINITE ); -#else - pthread_mutex_lock( &mutex ); -#endif +void ofxOscReceiver::disableReuse(){ + allowReuse = false; + if(listen_socket){ + setup(listen_port); + } } -void ofxOscReceiver::releaseMutex() -{ -#ifdef TARGET_WIN32 - ReleaseMutex( mutex ); -#else - pthread_mutex_unlock( &mutex ); -#endif +void ofxOscReceiver::enableReuse(){ + allowReuse = true; + if(listen_socket){ + setup(listen_port); + } } diff --git a/addons/ofxOsc/src/ofxOscReceiver.h b/addons/ofxOsc/src/ofxOscReceiver.h index 50525768d9a..3655690cfe0 100644 --- a/addons/ofxOsc/src/ofxOscReceiver.h +++ b/addons/ofxOsc/src/ofxOscReceiver.h @@ -51,25 +51,34 @@ class ofxOscReceiver : public osc::OscPacketListener { public: ofxOscReceiver(); - ~ofxOscReceiver(); + ofxOscReceiver(const ofxOscReceiver & mom); + ofxOscReceiver & operator=(const ofxOscReceiver & mom); /// listen_port is the port to listen for messages on - void setup( int listen_port, bool allowReuse = true ); + void setup( int listen_port ); /// returns true if there are any messages waiting for collection bool hasWaitingMessages(); /// take the next message on the queue of received messages, copy its details into message, and /// remove it from the queue. return false if there are no more messages to be got, otherwise /// return true - bool getNextMessage( ofxOscMessage* ); + OF_DEPRECATED_MSG("Pass a reference instead of a pointer", bool getNextMessage( ofxOscMessage* msg)); + bool getNextMessage( ofxOscMessage& msg ); bool getParameter(ofAbstractParameter & parameter); + /// disables port reuse reuse which allows to use the same port by several sockets + void disableReuse(); + + /// enabled broadcast capabilities (usually no need to call this, enabled by default) + void enableReuse(); + protected: /// process an incoming osc message and add it to the queue - virtual void ProcessMessage( const osc::ReceivedMessage &m, const IpEndpointName& remoteEndpoint ); + virtual void ProcessMessage( const osc::ReceivedMessage &m, const osc::IpEndpointName& remoteEndpoint ); private: + void setup(osc::UdpListeningReceiveSocket * socket); // shutdown the listener void shutdown(); @@ -79,28 +88,14 @@ class ofxOscReceiver : public osc::OscPacketListener #else static void* startThread( void* ofxOscReceiverInstance ); #endif - // queue of osc messages - std::deque< ofxOscMessage* > messages; // socket to listen on - UdpListeningReceiveSocket* listen_socket; + std::unique_ptr> listen_socket; - // mutex helpers - void grabMutex(); - void releaseMutex(); + std::thread listen_thread; + ofThreadChannel messagesChannel; -#ifdef TARGET_WIN32 - // thread to listen with - HANDLE thread; - // mutex for the thread queue - HANDLE mutex; -#else - // thread to listen with - pthread_t thread; - // mutex for the message queue - pthread_mutex_t mutex; -#endif - // ready to be deleted - bool socketHasShutdown; + bool allowReuse; + int listen_port; }; diff --git a/addons/ofxOsc/src/ofxOscSender.cpp b/addons/ofxOsc/src/ofxOscSender.cpp index 23541ff4707..74efeb113cd 100644 --- a/addons/ofxOsc/src/ofxOscSender.cpp +++ b/addons/ofxOsc/src/ofxOscSender.cpp @@ -37,37 +37,69 @@ #include ofxOscSender::ofxOscSender() +:broadcast(true) +,port(0) { - socket = NULL; } -ofxOscSender::~ofxOscSender() -{ - if ( socket ) - shutdown(); +ofxOscSender::ofxOscSender(const ofxOscSender & mom) +:broadcast(mom.broadcast) +,hostname(mom.hostname) +,port(mom.port){ + if(mom.socket){ + setup(hostname,port); + } +} + +ofxOscSender & ofxOscSender::operator=(const ofxOscSender & mom){ + if(this == &mom) return *this; + + broadcast = mom.broadcast; + hostname = mom.hostname; + port = mom.port; + if(mom.socket){ + setup(hostname,port); + } + return *this; } -void ofxOscSender::setup( std::string hostname, int port, bool enableBroadcast ) +void ofxOscSender::setup( const std::string &hostname, int port ) { - if( UdpSocket::GetUdpBufferSize() == 0 ){ - UdpSocket::SetUdpBufferSize(65535); + if( osc::UdpSocket::GetUdpBufferSize() == 0 ){ + osc::UdpSocket::SetUdpBufferSize(65535); } - if ( socket ) - shutdown(); - - socket = new UdpTransmitSocket(IpEndpointName( hostname.c_str(), port), enableBroadcast); + socket.reset(new osc::UdpTransmitSocket(osc::IpEndpointName( hostname.c_str(), port), broadcast)); + this->hostname = hostname; + this->port = port; +} + +void ofxOscSender::disableBroadcast() +{ + broadcast = false; + if(socket){ + setup(hostname, port); + } +} + +void ofxOscSender::enableBroadcast() +{ + broadcast = true; + if(socket){ + setup(hostname, port); + } } void ofxOscSender::shutdown() { - if ( socket ) - delete socket; - socket = NULL; + socket.reset(); } void ofxOscSender::sendBundle( ofxOscBundle& bundle ) { + if(!socket){ + ofLogError("ofxOscSender") << "trying to send before setup"; + } //setting this much larger as it gets trimmed down to the size its using before being sent. //TODO: much better if we could make this dynamic? Maybe have ofxOscBundle return its size? static const int OUTPUT_BUFFER_SIZE = 327680; @@ -82,6 +114,9 @@ void ofxOscSender::sendBundle( ofxOscBundle& bundle ) void ofxOscSender::sendMessage( ofxOscMessage& message, bool wrapInBundle ) { + if(!socket){ + ofLogError("ofxOscSender") << "trying to send before setup"; + } //setting this much larger as it gets trimmed down to the size its using before being sent. //TODO: much better if we could make this dynamic? Maybe have ofxOscMessage return its size? static const int OUTPUT_BUFFER_SIZE = 327680; @@ -99,8 +134,8 @@ void ofxOscSender::sendMessage( ofxOscMessage& message, bool wrapInBundle ) void ofxOscSender::sendParameter( const ofAbstractParameter & parameter){ if(!parameter.isSerializable()) return; if(parameter.type()==typeid(ofParameterGroup).name()){ - string address = "/"; - const vector hierarchy = parameter.getGroupHierarchyNames(); + std::string address = "/"; + const std::vector hierarchy = parameter.getGroupHierarchyNames(); for(int i=0;i<(int)hierarchy.size()-1;i++){ address+=hierarchy[i] + "/"; } @@ -108,8 +143,8 @@ void ofxOscSender::sendParameter( const ofAbstractParameter & parameter){ appendParameter(bundle,parameter,address); sendBundle(bundle); }else{ - string address = ""; - const vector hierarchy = parameter.getGroupHierarchyNames(); + std::string address = ""; + const std::vector hierarchy = parameter.getGroupHierarchyNames(); for(int i=0;i<(int)hierarchy.size()-1;i++){ address+= "/" + hierarchy[i]; } @@ -121,11 +156,11 @@ void ofxOscSender::sendParameter( const ofAbstractParameter & parameter){ } -void ofxOscSender::appendParameter( ofxOscBundle & _bundle, const ofAbstractParameter & parameter, string address){ +void ofxOscSender::appendParameter( ofxOscBundle & _bundle, const ofAbstractParameter & parameter, const std::string &address){ if(parameter.type()==typeid(ofParameterGroup).name()){ ofxOscBundle bundle; const ofParameterGroup & group = static_cast(parameter); - for(int i=0;i).name()){ msg.addIntArg(parameter.cast()); diff --git a/addons/ofxOsc/src/ofxOscSender.h b/addons/ofxOsc/src/ofxOscSender.h index c7b94ac0556..8f431ff6c0d 100644 --- a/addons/ofxOsc/src/ofxOscSender.h +++ b/addons/ofxOsc/src/ofxOscSender.h @@ -36,7 +36,9 @@ an ofxOscSender sends messages to a single host/port */ -class UdpTransmitSocket; +namespace osc{ + class UdpTransmitSocket; +} #include #include "OscTypes.h" #include "OscOutboundPacketStream.h" @@ -52,10 +54,11 @@ class ofxOscSender { public: ofxOscSender(); - ~ofxOscSender(); + ofxOscSender(const ofxOscSender & mom); + ofxOscSender & operator=(const ofxOscSender & mom); /// send messages to hostname and port - void setup( std::string hostname, int port, bool enableBroadcast = true ); + void setup( const std::string &hostname, int port ); /// send the given message void sendMessage( ofxOscMessage& message, bool wrapInBundle = true ); @@ -64,15 +67,25 @@ class ofxOscSender /// creates a message using an ofParameter void sendParameter( const ofAbstractParameter & parameter); + /// disables broadcast capabilities, usually call this before setup + void disableBroadcast(); + + /// enabled broadcast capabilities (usually no need to call this, enabled by default) + void enableBroadcast(); private: + void setup(osc::UdpTransmitSocket * socket); void shutdown(); // helper methods for constructing messages void appendBundle( ofxOscBundle& bundle, osc::OutboundPacketStream& p ); void appendMessage( ofxOscMessage& message, osc::OutboundPacketStream& p ); - void appendParameter( ofxOscBundle & bundle, const ofAbstractParameter & parameter, string address); - void appendParameter( ofxOscMessage & msg, const ofAbstractParameter & parameter, string address); + void appendParameter( ofxOscBundle & bundle, const ofAbstractParameter & parameter, const std::string &address); + void appendParameter( ofxOscMessage & msg, const ofAbstractParameter & parameter, const std::string &address); + + std::unique_ptr socket; + bool broadcast; + std::string hostname; + int port; - UdpTransmitSocket * socket; }; diff --git a/addons/ofxProjectGenerator/libs/pugixml/src/pugiconfig.hpp b/addons/ofxProjectGenerator/libs/pugixml/src/pugiconfig.hpp deleted file mode 100644 index 5ee5131fe5d..00000000000 --- a/addons/ofxProjectGenerator/libs/pugixml/src/pugiconfig.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * pugixml parser - version 1.6 - * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef HEADER_PUGICONFIG_HPP -#define HEADER_PUGICONFIG_HPP - -// Uncomment this to enable wchar_t mode -// #define PUGIXML_WCHAR_MODE - -// Uncomment this to disable XPath -// #define PUGIXML_NO_XPATH - -// Uncomment this to disable STL -// #define PUGIXML_NO_STL - -// Uncomment this to disable exceptions -// #define PUGIXML_NO_EXCEPTIONS - -// Set this to control attributes for public classes/functions, i.e.: -// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL -// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL -// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall -// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead - -// Tune these constants to adjust memory-related behavior -// #define PUGIXML_MEMORY_PAGE_SIZE 32768 -// #define PUGIXML_MEMORY_OUTPUT_STACK 10240 -// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 - -// Uncomment this to switch to header-only version -// #define PUGIXML_HEADER_ONLY - -// Uncomment this to enable long long support -// #define PUGIXML_HAS_LONG_LONG - -#endif - -/** - * Copyright (c) 2006-2015 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.cpp b/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.cpp deleted file mode 100644 index 5b77a271c37..00000000000 --- a/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.cpp +++ /dev/null @@ -1,11554 +0,0 @@ -/** - * pugixml parser - version 1.6 - * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef SOURCE_PUGIXML_CPP -#define SOURCE_PUGIXML_CPP - -#include "pugixml.hpp" - -#include -#include -#include -#include - -#ifdef PUGIXML_WCHAR_MODE -# include -#endif - -#ifndef PUGIXML_NO_XPATH -# include -# include -# ifdef PUGIXML_NO_EXCEPTIONS -# include -# endif -#endif - -#ifndef PUGIXML_NO_STL -# include -# include -# include -#endif - -// For placement new -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) -# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // this function or variable may be unsafe -# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged -#endif - -#ifdef __INTEL_COMPILER -# pragma warning(disable: 177) // function was declared but never referenced -# pragma warning(disable: 279) // controlling expression is constant -# pragma warning(disable: 1478 1786) // function was declared "deprecated" -# pragma warning(disable: 1684) // conversion from pointer to same-sized integral type -#endif - -#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) -# pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away -#endif - -#ifdef __BORLANDC__ -# pragma option push -# pragma warn -8008 // condition is always false -# pragma warn -8066 // unreachable code -#endif - -#ifdef __SNC__ -// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug -# pragma diag_suppress=178 // function was declared but never referenced -# pragma diag_suppress=237 // controlling expression is constant -#endif - -// Inlining controls -#if defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGI__NO_INLINE __declspec(noinline) -#elif defined(__GNUC__) -# define PUGI__NO_INLINE __attribute__((noinline)) -#else -# define PUGI__NO_INLINE -#endif - -// Branch weight controls -#if defined(__GNUC__) -# define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) -#else -# define PUGI__UNLIKELY(cond) (cond) -#endif - -// Simple static assertion -#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } - -// Digital Mars C++ bug workaround for passing char loaded from memory via stack -#ifdef __DMC__ -# define PUGI__DMC_VOLATILE volatile -#else -# define PUGI__DMC_VOLATILE -#endif - -// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) -#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) -using std::memcpy; -using std::memmove; -#endif - -// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features -#if defined(_MSC_VER) && !defined(__S3E__) -# define PUGI__MSVC_CRT_VERSION _MSC_VER -#endif - -#ifdef PUGIXML_HEADER_ONLY -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } -# define PUGI__FN inline -# define PUGI__FN_NO_INLINE inline -#else -# if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } -# else -# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { -# define PUGI__NS_END } } } -# endif -# define PUGI__FN -# define PUGI__FN_NO_INLINE PUGI__NO_INLINE -#endif - -// uintptr_t -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -# include -#else -# ifndef _UINTPTR_T_DEFINED -// No native uintptr_t in MSVC6 and in some WinCE versions -typedef size_t uintptr_t; -#define _UINTPTR_T_DEFINED -# endif -PUGI__NS_BEGIN - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -PUGI__NS_END -#endif - -// Memory allocation -PUGI__NS_BEGIN - PUGI__FN void* default_allocate(size_t size) - { - return malloc(size); - } - - PUGI__FN void default_deallocate(void* ptr) - { - free(ptr); - } - - template - struct xml_memory_management_function_storage - { - static allocation_function allocate; - static deallocation_function deallocate; - }; - - // Global allocation functions are stored in class statics so that in header mode linker deduplicates them - // Without a template<> we'll get multiple definitions of the same static - template allocation_function xml_memory_management_function_storage::allocate = default_allocate; - template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; - - typedef xml_memory_management_function_storage xml_memory; -PUGI__NS_END - -// String utilities -PUGI__NS_BEGIN - // Get string length - PUGI__FN size_t strlength(const char_t* s) - { - assert(s); - - #ifdef PUGIXML_WCHAR_MODE - return wcslen(s); - #else - return strlen(s); - #endif - } - - // Compare two strings - PUGI__FN bool strequal(const char_t* src, const char_t* dst) - { - assert(src && dst); - - #ifdef PUGIXML_WCHAR_MODE - return wcscmp(src, dst) == 0; - #else - return strcmp(src, dst) == 0; - #endif - } - - // Compare lhs with [rhs_begin, rhs_end) - PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) - { - for (size_t i = 0; i < count; ++i) - if (lhs[i] != rhs[i]) - return false; - - return lhs[count] == 0; - } - - // Get length of wide string, even if CRT lacks wide character support - PUGI__FN size_t strlength_wide(const wchar_t* s) - { - assert(s); - - #ifdef PUGIXML_WCHAR_MODE - return wcslen(s); - #else - const wchar_t* end = s; - while (*end) end++; - return static_cast(end - s); - #endif - } - -#ifdef PUGIXML_WCHAR_MODE - // Convert string to wide string, assuming all symbols are ASCII - PUGI__FN void widen_ascii(wchar_t* dest, const char* source) - { - for (const char* i = source; *i; ++i) *dest++ = *i; - *dest = 0; - } -#endif -PUGI__NS_END - -#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) -// auto_ptr-like buffer holder for exception recovery -PUGI__NS_BEGIN - struct buffer_holder - { - void* data; - void (*deleter)(void*); - - buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_) - { - } - - ~buffer_holder() - { - if (data) deleter(data); - } - - void* release() - { - void* result = data; - data = 0; - return result; - } - }; -PUGI__NS_END -#endif - -PUGI__NS_BEGIN - static const size_t xml_memory_page_size = - #ifdef PUGIXML_MEMORY_PAGE_SIZE - PUGIXML_MEMORY_PAGE_SIZE - #else - 32768 - #endif - ; - - static const uintptr_t xml_memory_page_alignment = 64; - static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); - static const uintptr_t xml_memory_page_contents_shared_mask = 32; - static const uintptr_t xml_memory_page_name_allocated_mask = 16; - static const uintptr_t xml_memory_page_value_allocated_mask = 8; - static const uintptr_t xml_memory_page_type_mask = 7; - static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; - static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; - - #define PUGI__NODETYPE(n) static_cast(((n)->header & impl::xml_memory_page_type_mask) + 1) - - struct xml_allocator; - - struct xml_memory_page - { - static xml_memory_page* construct(void* memory) - { - xml_memory_page* result = static_cast(memory); - - result->allocator = 0; - result->prev = 0; - result->next = 0; - result->busy_size = 0; - result->freed_size = 0; - - return result; - } - - xml_allocator* allocator; - - xml_memory_page* prev; - xml_memory_page* next; - - size_t busy_size; - size_t freed_size; - }; - - struct xml_memory_string_header - { - uint16_t page_offset; // offset from page->data - uint16_t full_size; // 0 if string occupies whole page - }; - - struct xml_allocator - { - xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) - { - } - - xml_memory_page* allocate_page(size_t data_size) - { - size_t size = sizeof(xml_memory_page) + data_size; - - // allocate block with some alignment, leaving memory for worst-case padding - void* memory = xml_memory::allocate(size + xml_memory_page_alignment); - if (!memory) return 0; - - // align to next page boundary (note: this guarantees at least 1 usable byte before the page) - char* page_memory = reinterpret_cast((reinterpret_cast(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); - - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); - assert(page); - - page->allocator = _root->allocator; - - // record the offset for freeing the memory block - assert(page_memory > memory && page_memory - static_cast(memory) <= 127); - page_memory[-1] = static_cast(page_memory - static_cast(memory)); - - return page; - } - - static void deallocate_page(xml_memory_page* page) - { - char* page_memory = reinterpret_cast(page); - - xml_memory::deallocate(page_memory - page_memory[-1]); - } - - void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); - - void* allocate_memory(size_t size, xml_memory_page*& out_page) - { - if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); - - void* buf = reinterpret_cast(_root) + sizeof(xml_memory_page) + _busy_size; - - _busy_size += size; - - out_page = _root; - - return buf; - } - - void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) - { - if (page == _root) page->busy_size = _busy_size; - - assert(ptr >= reinterpret_cast(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast(page) + sizeof(xml_memory_page) + page->busy_size); - (void)!ptr; - - page->freed_size += size; - assert(page->freed_size <= page->busy_size); - - if (page->freed_size == page->busy_size) - { - if (page->next == 0) - { - assert(_root == page); - - // top page freed, just reset sizes - page->busy_size = page->freed_size = 0; - _busy_size = 0; - } - else - { - assert(_root != page); - assert(page->prev); - - // remove from the list - page->prev->next = page->next; - page->next->prev = page->prev; - - // deallocate - deallocate_page(page); - } - } - } - - char_t* allocate_string(size_t length) - { - static const size_t max_encoded_offset = (1 << 16) * sizeof(void*); - - PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); - - // allocate memory for string and header block - size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); - - // round size up to pointer alignment boundary - size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); - - xml_memory_page* page; - xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); - - if (!header) return 0; - - // setup header - ptrdiff_t page_offset = reinterpret_cast(header) - reinterpret_cast(page) - sizeof(xml_memory_page); - - assert(page_offset % sizeof(void*) == 0); - assert(page_offset >= 0 && static_cast(page_offset) < max_encoded_offset); - header->page_offset = static_cast(static_cast(page_offset) / sizeof(void*)); - - // full_size == 0 for large strings that occupy the whole page - assert(full_size % sizeof(void*) == 0); - assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0)); - header->full_size = static_cast(full_size < max_encoded_offset ? full_size / sizeof(void*) : 0); - - // round-trip through void* to avoid 'cast increases required alignment of target type' warning - // header is guaranteed a pointer-sized alignment, which should be enough for char_t - return static_cast(static_cast(header + 1)); - } - - void deallocate_string(char_t* string) - { - // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings - // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string - - // get header - xml_memory_string_header* header = static_cast(static_cast(string)) - 1; - assert(header); - - // deallocate - size_t page_offset = sizeof(xml_memory_page) + header->page_offset * sizeof(void*); - xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); - - // if full_size == 0 then this string occupies the whole page - size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * sizeof(void*); - - deallocate_memory(header, full_size, page); - } - - xml_memory_page* _root; - size_t _busy_size; - }; - - PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) - { - const size_t large_allocation_threshold = xml_memory_page_size / 4; - - xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); - out_page = page; - - if (!page) return 0; - - if (size <= large_allocation_threshold) - { - _root->busy_size = _busy_size; - - // insert page at the end of linked list - page->prev = _root; - _root->next = page; - _root = page; - - _busy_size = size; - } - else - { - // insert page before the end of linked list, so that it is deleted as soon as possible - // the last page is not deleted even if it's empty (see deallocate_memory) - assert(_root->prev); - - page->prev = _root->prev; - page->next = _root; - - _root->prev->next = page; - _root->prev = page; - } - - // allocate inside page - page->busy_size = size; - - return reinterpret_cast(page) + sizeof(xml_memory_page); - } -PUGI__NS_END - -namespace pugi -{ - /// A 'name=value' XML attribute structure. - struct xml_attribute_struct - { - /// Default ctor - xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) - { - } - - uintptr_t header; - - char_t* name; ///< Pointer to attribute name. - char_t* value; ///< Pointer to attribute value. - - xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) - xml_attribute_struct* next_attribute; ///< Next attribute - }; - - /// An XML document tree node. - struct xml_node_struct - { - /// Default ctor - /// \param type - node type - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) - { - } - - uintptr_t header; - - xml_node_struct* parent; ///< Pointer to parent - - char_t* name; ///< Pointer to element name. - char_t* value; ///< Pointer to any associated string data. - - xml_node_struct* first_child; ///< First child - - xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) - xml_node_struct* next_sibling; ///< Right brother - - xml_attribute_struct* first_attribute; ///< First attribute - }; -} - -PUGI__NS_BEGIN - struct xml_extra_buffer - { - char_t* buffer; - xml_extra_buffer* next; - }; - - struct xml_document_struct: public xml_node_struct, public xml_allocator - { - xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) - { - } - - const char_t* buffer; - - xml_extra_buffer* extra_buffers; - }; - - inline xml_allocator& get_allocator(const xml_node_struct* node) - { - assert(node); - - return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; - } - - template inline xml_document_struct& get_document(const Object* object) - { - assert(object); - - return *static_cast(reinterpret_cast(object->header & xml_memory_page_pointer_mask)->allocator); - } -PUGI__NS_END - -// Low-level DOM operations -PUGI__NS_BEGIN - inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) - { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); - - return new (memory) xml_attribute_struct(page); - } - - inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) - { - xml_memory_page* page; - void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); - - return new (memory) xml_node_struct(page, type); - } - - inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) - { - uintptr_t header = a->header; - - if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); - if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); - - alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); - } - - inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) - { - uintptr_t header = n->header; - - if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); - if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); - - for (xml_attribute_struct* attr = n->first_attribute; attr; ) - { - xml_attribute_struct* next = attr->next_attribute; - - destroy_attribute(attr, alloc); - - attr = next; - } - - for (xml_node_struct* child = n->first_child; child; ) - { - xml_node_struct* next = child->next_sibling; - - destroy_node(child, alloc); - - child = next; - } - - alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); - } - - inline void append_node(xml_node_struct* child, xml_node_struct* node) - { - child->parent = node; - - xml_node_struct* head = node->first_child; - - if (head) - { - xml_node_struct* tail = head->prev_sibling_c; - - tail->next_sibling = child; - child->prev_sibling_c = tail; - head->prev_sibling_c = child; - } - else - { - node->first_child = child; - child->prev_sibling_c = child; - } - } - - inline void prepend_node(xml_node_struct* child, xml_node_struct* node) - { - child->parent = node; - - xml_node_struct* head = node->first_child; - - if (head) - { - child->prev_sibling_c = head->prev_sibling_c; - head->prev_sibling_c = child; - } - else - child->prev_sibling_c = child; - - child->next_sibling = head; - node->first_child = child; - } - - inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) - { - xml_node_struct* parent = node->parent; - - child->parent = parent; - - if (node->next_sibling) - node->next_sibling->prev_sibling_c = child; - else - parent->first_child->prev_sibling_c = child; - - child->next_sibling = node->next_sibling; - child->prev_sibling_c = node; - - node->next_sibling = child; - } - - inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) - { - xml_node_struct* parent = node->parent; - - child->parent = parent; - - if (node->prev_sibling_c->next_sibling) - node->prev_sibling_c->next_sibling = child; - else - parent->first_child = child; - - child->prev_sibling_c = node->prev_sibling_c; - child->next_sibling = node; - - node->prev_sibling_c = child; - } - - inline void remove_node(xml_node_struct* node) - { - xml_node_struct* parent = node->parent; - - if (node->next_sibling) - node->next_sibling->prev_sibling_c = node->prev_sibling_c; - else - parent->first_child->prev_sibling_c = node->prev_sibling_c; - - if (node->prev_sibling_c->next_sibling) - node->prev_sibling_c->next_sibling = node->next_sibling; - else - parent->first_child = node->next_sibling; - - node->parent = 0; - node->prev_sibling_c = 0; - node->next_sibling = 0; - } - - inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) - { - xml_attribute_struct* head = node->first_attribute; - - if (head) - { - xml_attribute_struct* tail = head->prev_attribute_c; - - tail->next_attribute = attr; - attr->prev_attribute_c = tail; - head->prev_attribute_c = attr; - } - else - { - node->first_attribute = attr; - attr->prev_attribute_c = attr; - } - } - - inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node) - { - xml_attribute_struct* head = node->first_attribute; - - if (head) - { - attr->prev_attribute_c = head->prev_attribute_c; - head->prev_attribute_c = attr; - } - else - attr->prev_attribute_c = attr; - - attr->next_attribute = head; - node->first_attribute = attr; - } - - inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) - { - if (place->next_attribute) - place->next_attribute->prev_attribute_c = attr; - else - node->first_attribute->prev_attribute_c = attr; - - attr->next_attribute = place->next_attribute; - attr->prev_attribute_c = place; - place->next_attribute = attr; - } - - inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) - { - if (place->prev_attribute_c->next_attribute) - place->prev_attribute_c->next_attribute = attr; - else - node->first_attribute = attr; - - attr->prev_attribute_c = place->prev_attribute_c; - attr->next_attribute = place; - place->prev_attribute_c = attr; - } - - inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) - { - if (attr->next_attribute) - attr->next_attribute->prev_attribute_c = attr->prev_attribute_c; - else - node->first_attribute->prev_attribute_c = attr->prev_attribute_c; - - if (attr->prev_attribute_c->next_attribute) - attr->prev_attribute_c->next_attribute = attr->next_attribute; - else - node->first_attribute = attr->next_attribute; - - attr->prev_attribute_c = 0; - attr->next_attribute = 0; - } - - PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) - { - xml_node_struct* child = allocate_node(alloc, type); - if (!child) return 0; - - append_node(child, node); - - return child; - } - - PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) - { - xml_attribute_struct* attr = allocate_attribute(alloc); - if (!attr) return 0; - - append_attribute(attr, node); - - return attr; - } -PUGI__NS_END - -// Helper classes for code generation -PUGI__NS_BEGIN - struct opt_false - { - enum { value = 0 }; - }; - - struct opt_true - { - enum { value = 1 }; - }; -PUGI__NS_END - -// Unicode utilities -PUGI__NS_BEGIN - inline uint16_t endian_swap(uint16_t value) - { - return static_cast(((value & 0xff) << 8) | (value >> 8)); - } - - inline uint32_t endian_swap(uint32_t value) - { - return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); - } - - struct utf8_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t ch) - { - // U+0000..U+007F - if (ch < 0x80) return result + 1; - // U+0080..U+07FF - else if (ch < 0x800) return result + 2; - // U+0800..U+FFFF - else return result + 3; - } - - static value_type high(value_type result, uint32_t) - { - // U+10000..U+10FFFF - return result + 4; - } - }; - - struct utf8_writer - { - typedef uint8_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - // U+0000..U+007F - if (ch < 0x80) - { - *result = static_cast(ch); - return result + 1; - } - // U+0080..U+07FF - else if (ch < 0x800) - { - result[0] = static_cast(0xC0 | (ch >> 6)); - result[1] = static_cast(0x80 | (ch & 0x3F)); - return result + 2; - } - // U+0800..U+FFFF - else - { - result[0] = static_cast(0xE0 | (ch >> 12)); - result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[2] = static_cast(0x80 | (ch & 0x3F)); - return result + 3; - } - } - - static value_type high(value_type result, uint32_t ch) - { - // U+10000..U+10FFFF - result[0] = static_cast(0xF0 | (ch >> 18)); - result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); - result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - result[3] = static_cast(0x80 | (ch & 0x3F)); - return result + 4; - } - - static value_type any(value_type result, uint32_t ch) - { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } - }; - - struct utf16_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) - { - return result + 1; - } - - static value_type high(value_type result, uint32_t) - { - return result + 2; - } - }; - - struct utf16_writer - { - typedef uint16_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = static_cast(ch); - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - uint32_t msh = static_cast(ch - 0x10000) >> 10; - uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; - - result[0] = static_cast(0xD800 + msh); - result[1] = static_cast(0xDC00 + lsh); - - return result + 2; - } - - static value_type any(value_type result, uint32_t ch) - { - return (ch < 0x10000) ? low(result, ch) : high(result, ch); - } - }; - - struct utf32_counter - { - typedef size_t value_type; - - static value_type low(value_type result, uint32_t) - { - return result + 1; - } - - static value_type high(value_type result, uint32_t) - { - return result + 1; - } - }; - - struct utf32_writer - { - typedef uint32_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - - static value_type any(value_type result, uint32_t ch) - { - *result = ch; - - return result + 1; - } - }; - - struct latin1_writer - { - typedef uint8_t* value_type; - - static value_type low(value_type result, uint32_t ch) - { - *result = static_cast(ch > 255 ? '?' : ch); - - return result + 1; - } - - static value_type high(value_type result, uint32_t ch) - { - (void)ch; - - *result = '?'; - - return result + 1; - } - }; - - template struct wchar_selector; - - template <> struct wchar_selector<2> - { - typedef uint16_t type; - typedef utf16_counter counter; - typedef utf16_writer writer; - }; - - template <> struct wchar_selector<4> - { - typedef uint32_t type; - typedef utf32_counter counter; - typedef utf32_writer writer; - }; - - typedef wchar_selector::counter wchar_counter; - typedef wchar_selector::writer wchar_writer; - - template struct utf_decoder - { - static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) - { - const uint8_t utf8_byte_mask = 0x3f; - - while (size) - { - uint8_t lead = *data; - - // 0xxxxxxx -> U+0000..U+007F - if (lead < 0x80) - { - result = Traits::low(result, lead); - data += 1; - size -= 1; - - // process aligned single-byte (ascii) blocks - if ((reinterpret_cast(data) & 3) == 0) - { - // round-trip through void* to silence 'cast increases required alignment of target type' warnings - while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) - { - result = Traits::low(result, data[0]); - result = Traits::low(result, data[1]); - result = Traits::low(result, data[2]); - result = Traits::low(result, data[3]); - data += 4; - size -= 4; - } - } - } - // 110xxxxx -> U+0080..U+07FF - else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) - { - result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); - data += 2; - size -= 2; - } - // 1110xxxx -> U+0800-U+FFFF - else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) - { - result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); - data += 3; - size -= 3; - } - // 11110xxx -> U+10000..U+10FFFF - else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) - { - result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); - data += 4; - size -= 4; - } - // 10xxxxxx or 11111xxx -> invalid - else - { - data += 1; - size -= 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) - { - const uint16_t* end = data + size; - - while (data < end) - { - unsigned int lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+D7FF - if (lead < 0xD800) - { - result = Traits::low(result, lead); - data += 1; - } - // U+E000..U+FFFF - else if (static_cast(lead - 0xE000) < 0x2000) - { - result = Traits::low(result, lead); - data += 1; - } - // surrogate pair lead - else if (static_cast(lead - 0xD800) < 0x400 && data + 1 < end) - { - uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; - - if (static_cast(next - 0xDC00) < 0x400) - { - result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); - data += 2; - } - else - { - data += 1; - } - } - else - { - data += 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) - { - const uint32_t* end = data + size; - - while (data < end) - { - uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; - - // U+0000..U+FFFF - if (lead < 0x10000) - { - result = Traits::low(result, lead); - data += 1; - } - // U+10000..U+10FFFF - else - { - result = Traits::high(result, lead); - data += 1; - } - } - - return result; - } - - static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result) - { - for (size_t i = 0; i < size; ++i) - { - result = Traits::low(result, data[i]); - } - - return result; - } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf16_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf32_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result) - { - return decode_wchar_block_impl(reinterpret_cast::type*>(data), size, result); - } - }; - - template PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length) - { - for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) - { - for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); - } -#endif -PUGI__NS_END - -PUGI__NS_BEGIN - enum chartype_t - { - ct_parse_pcdata = 1, // \0, &, \r, < - ct_parse_attr = 2, // \0, &, \r, ', " - ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab - ct_space = 8, // \r, \n, space, tab - ct_parse_cdata = 16, // \0, ], >, \r - ct_parse_comment = 32, // \0, -, >, \r - ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . - ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : - }; - - static const unsigned char chartype_table[256] = - { - 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 - 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 - 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 - 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 - - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 - }; - - enum chartypex_t - { - ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > - ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " - ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ - ctx_digit = 8, // 0-9 - ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . - }; - - static const unsigned char chartypex_table[256] = - { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 - 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 - - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 - 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 - }; - -#ifdef PUGIXML_WCHAR_MODE - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) -#else - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) -#endif - - #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) - #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) - - PUGI__FN bool is_little_endian() - { - unsigned int ui = 1; - - return *reinterpret_cast(&ui) == 1; - } - - PUGI__FN xml_encoding get_wchar_encoding() - { - PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); - - if (sizeof(wchar_t) == 2) - return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - else - return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - } - - PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) - { - // look for BOM in first few bytes - if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; - if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; - if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; - if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; - if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; - - // look for <, (contents); - - PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; - - return guess_buffer_encoding(d0, d1, d2, d3); - } - - PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - size_t length = size / sizeof(char_t); - - if (is_mutable) - { - out_buffer = static_cast(const_cast(contents)); - out_length = length; - } - else - { - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - if (contents) - memcpy(buffer, contents, length * sizeof(char_t)); - else - assert(length == 0); - - buffer[length] = 0; - - out_buffer = buffer; - out_length = length + 1; - } - - return true; - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) - { - return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || - (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); - } - - PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - const char_t* data = static_cast(contents); - size_t length = size / sizeof(char_t); - - if (is_mutable) - { - char_t* buffer = const_cast(data); - - convert_wchar_endian_swap(buffer, data, length); - - out_buffer = buffer; - out_length = length; - } - else - { - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - convert_wchar_endian_swap(buffer, data, length); - buffer[length] = 0; - - out_buffer = buffer; - out_length = length + 1; - } - - return true; - } - - PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) - { - const uint8_t* data = static_cast(contents); - size_t data_length = size; - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf8 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf8_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint16_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint16_t); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf16 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf16_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint32_t); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf32 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf32_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) - { - const uint8_t* data = static_cast(contents); - size_t data_length = size; - - // get length in wchar_t units - size_t length = data_length; - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // convert latin1 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_latin1_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) - { - // get native encoding - xml_encoding wchar_encoding = get_wchar_encoding(); - - // fast path: no conversion required - if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // only endian-swapping is required - if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); - - // source encoding is utf8 - if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size); - - assert(!"Invalid encoding"); - return false; - } -#else - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint16_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint16_t); - - // first pass: get length in utf8 units - size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf16 input to utf8 - uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_utf16_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint32_t); - - // first pass: get length in utf8 units - size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf32 input to utf8 - uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_utf32_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) - { - for (size_t i = 0; i < size; ++i) - if (data[i] > 127) - return i; - - return size; - } - - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) - { - const uint8_t* data = static_cast(contents); - size_t data_length = size; - - // get size of prefix that does not need utf8 conversion - size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length); - assert(prefix_length <= data_length); - - const uint8_t* postfix = data + prefix_length; - size_t postfix_length = data_length - prefix_length; - - // if no conversion is needed, just return the original buffer - if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // first pass: get length in utf8 units - size_t length = prefix_length + utf_decoder::decode_latin1_block(postfix, postfix_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert latin1 input to utf8 - memcpy(buffer, data, prefix_length); - - uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_latin1_block(postfix, postfix_length, obegin + prefix_length); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) - { - // fast path: no conversion required - if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); - - // source encoding is utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); - } - - // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); - - assert(!"Invalid encoding"); - return false; - } -#endif - - PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) - { - // get length in utf8 characters - return utf_decoder::decode_wchar_block(str, length, 0); - } - - PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) - { - // convert to utf8 - uint8_t* begin = reinterpret_cast(buffer); - uint8_t* end = utf_decoder::decode_wchar_block(str, length, begin); - - assert(begin + size == end); - (void)!end; - - // zero-terminate - buffer[size] = 0; - } - -#ifndef PUGIXML_NO_STL - PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) - { - // first pass: get length in utf8 characters - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - std::string result; - result.resize(size); - - // second pass: convert to utf8 - if (size > 0) as_utf8_end(&result[0], size, str, length); - - return result; - } - - PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) - { - const uint8_t* data = reinterpret_cast(str); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, size, 0); - - // allocate resulting string - std::basic_string result; - result.resize(length); - - // second pass: convert to wchar_t - if (length > 0) - { - wchar_writer::value_type begin = reinterpret_cast(&result[0]); - wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); - - assert(begin + length == end); - (void)!end; - } - - return result; - } -#endif - - inline bool strcpy_insitu_allow(size_t length, uintptr_t header, uintptr_t header_mask, char_t* target) - { - // never reuse shared memory - if (header & xml_memory_page_contents_shared_mask) return false; - - size_t target_length = strlength(target); - - // always reuse document buffer memory if possible - if ((header & header_mask) == 0) return target_length >= length; - - // reuse heap memory if waste is not too great - const size_t reuse_threshold = 32; - - return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); - } - - PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) - { - assert(header); - - size_t source_length = strlength(source); - - if (source_length == 0) - { - // empty string and null pointer are equivalent, so just deallocate old memory - xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; - - if (header & header_mask) alloc->deallocate_string(dest); - - // mark the string as not allocated - dest = 0; - header &= ~header_mask; - - return true; - } - else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) - { - // we can reuse old buffer, so just copy the new data (including zero terminator) - memcpy(dest, source, (source_length + 1) * sizeof(char_t)); - - return true; - } - else - { - xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; - - // allocate new buffer - char_t* buf = alloc->allocate_string(source_length + 1); - if (!buf) return false; - - // copy the string (including zero terminator) - memcpy(buf, source, (source_length + 1) * sizeof(char_t)); - - // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) - if (header & header_mask) alloc->deallocate_string(dest); - - // the string is now allocated, so set the flag - dest = buf; - header |= header_mask; - - return true; - } - } - - struct gap - { - char_t* end; - size_t size; - - gap(): end(0), size(0) - { - } - - // Push new gap, move s count bytes further (skipping the gap). - // Collapse previous gap. - void push(char_t*& s, size_t count) - { - if (end) // there was a gap already; collapse it - { - // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); - } - - s += count; // end of current gap - - // "merge" two gaps - end = s; - size += count; - } - - // Collapse all gaps, return past-the-end pointer - char_t* flush(char_t* s) - { - if (end) - { - // Move [old_gap_end, current_pos) to [old_gap_start, ...) - assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); - - return s - size; - } - else return s; - } - }; - - PUGI__FN char_t* strconv_escape(char_t* s, gap& g) - { - char_t* stre = s + 1; - - switch (*stre) - { - case '#': // &#... - { - unsigned int ucsc = 0; - - if (stre[1] == 'x') // &#x... (hex code) - { - stre += 2; - - char_t ch = *stre; - - if (ch == ';') return stre; - - for (;;) - { - if (static_cast(ch - '0') <= 9) - ucsc = 16 * ucsc + (ch - '0'); - else if (static_cast((ch | ' ') - 'a') <= 5) - ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); - else if (ch == ';') - break; - else // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } - else // &#... (dec code) - { - char_t ch = *++stre; - - if (ch == ';') return stre; - - for (;;) - { - if (static_cast(static_cast(ch) - '0') <= 9) - ucsc = 10 * ucsc + (ch - '0'); - else if (ch == ';') - break; - else // cancel - return stre; - - ch = *++stre; - } - - ++stre; - } - - #ifdef PUGIXML_WCHAR_MODE - s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); - #else - s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); - #endif - - g.push(s, stre - s); - return stre; - } - - case 'a': // &a - { - ++stre; - - if (*stre == 'm') // &am - { - if (*++stre == 'p' && *++stre == ';') // & - { - *s++ = '&'; - ++stre; - - g.push(s, stre - s); - return stre; - } - } - else if (*stre == 'p') // &ap - { - if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' - { - *s++ = '\''; - ++stre; - - g.push(s, stre - s); - return stre; - } - } - break; - } - - case 'g': // &g - { - if (*++stre == 't' && *++stre == ';') // > - { - *s++ = '>'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - case 'l': // &l - { - if (*++stre == 't' && *++stre == ';') // < - { - *s++ = '<'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - case 'q': // &q - { - if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " - { - *s++ = '"'; - ++stre; - - g.push(s, stre - s); - return stre; - } - break; - } - - default: - break; - } - - return stre; - } - - // Parser utilities - #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) - #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } - #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) - #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } - #define PUGI__POPNODE() { cursor = cursor->parent; } - #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } - #define PUGI__SCANWHILE(X) { while (X) ++s; } - #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } - #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } - #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) - #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } - - PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) - { - gap g; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here - { - *g.flush(s) = 0; - - return s + (s[2] == '>' ? 3 : 2); - } - else if (*s == 0) - { - return 0; - } - else ++s; - } - } - - PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) - { - gap g; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); - - if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here - { - *g.flush(s) = 0; - - return s + 1; - } - else if (*s == 0) - { - return 0; - } - else ++s; - } - } - - typedef char_t* (*strconv_pcdata_t)(char_t*); - - template struct strconv_pcdata_impl - { - static char_t* parse(char_t* s) - { - gap g; - - char_t* begin = s; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata)); - - if (*s == '<') // PCDATA ends here - { - char_t* end = g.flush(s); - - if (opt_trim::value) - while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) - --end; - - *end = 0; - - return s + 1; - } - else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair - { - *s++ = '\n'; // replace first one with 0x0a - - if (*s == '\n') g.push(s, 1); - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (*s == 0) - { - char_t* end = g.flush(s); - - if (opt_trim::value) - while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) - --end; - - *end = 0; - - return s; - } - else ++s; - } - } - }; - - PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) - { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); - - switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim) - { - case 0: return strconv_pcdata_impl::parse; - case 1: return strconv_pcdata_impl::parse; - case 2: return strconv_pcdata_impl::parse; - case 3: return strconv_pcdata_impl::parse; - case 4: return strconv_pcdata_impl::parse; - case 5: return strconv_pcdata_impl::parse; - case 6: return strconv_pcdata_impl::parse; - case 7: return strconv_pcdata_impl::parse; - default: assert(false); return 0; // should not get here - } - } - - typedef char_t* (*strconv_attribute_t)(char_t*, char_t); - - template struct strconv_attribute_impl - { - static char_t* parse_wnorm(char_t* s, char_t end_quote) - { - gap g; - - // trim leading whitespaces - if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - char_t* str = s; - - do ++str; - while (PUGI__IS_CHARTYPE(*str, ct_space)); - - g.push(s, str - s); - } - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); - - if (*s == end_quote) - { - char_t* str = g.flush(s); - - do *str-- = 0; - while (PUGI__IS_CHARTYPE(*str, ct_space)); - - return s + 1; - } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - *s++ = ' '; - - if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - char_t* str = s + 1; - while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; - - g.push(s, str - s); - } - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_wconv(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) - { - if (*s == '\r') - { - *s++ = ' '; - - if (*s == '\n') g.push(s, 1); - } - else *s++ = ' '; - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_eol(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (*s == '\r') - { - *s++ = '\n'; - - if (*s == '\n') g.push(s, 1); - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - - static char_t* parse_simple(char_t* s, char_t end_quote) - { - gap g; - - while (true) - { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - - if (*s == end_quote) - { - *g.flush(s) = 0; - - return s + 1; - } - else if (opt_escape::value && *s == '&') - { - s = strconv_escape(s, g); - } - else if (!*s) - { - return 0; - } - else ++s; - } - } - }; - - PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) - { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); - - switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) - { - case 0: return strconv_attribute_impl::parse_simple; - case 1: return strconv_attribute_impl::parse_simple; - case 2: return strconv_attribute_impl::parse_eol; - case 3: return strconv_attribute_impl::parse_eol; - case 4: return strconv_attribute_impl::parse_wconv; - case 5: return strconv_attribute_impl::parse_wconv; - case 6: return strconv_attribute_impl::parse_wconv; - case 7: return strconv_attribute_impl::parse_wconv; - case 8: return strconv_attribute_impl::parse_wnorm; - case 9: return strconv_attribute_impl::parse_wnorm; - case 10: return strconv_attribute_impl::parse_wnorm; - case 11: return strconv_attribute_impl::parse_wnorm; - case 12: return strconv_attribute_impl::parse_wnorm; - case 13: return strconv_attribute_impl::parse_wnorm; - case 14: return strconv_attribute_impl::parse_wnorm; - case 15: return strconv_attribute_impl::parse_wnorm; - default: assert(false); return 0; // should not get here - } - } - - inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) - { - xml_parse_result result; - result.status = status; - result.offset = offset; - - return result; - } - - struct xml_parser - { - xml_allocator alloc; - char_t* error_offset; - xml_parse_status error_status; - - xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) - { - } - - // DOCTYPE consists of nested sections of the following possible types: - // , , "...", '...' - // - // - // First group can not contain nested groups - // Second group can contain nested groups of the same type - // Third group can contain all other groups - char_t* parse_doctype_primitive(char_t* s) - { - if (*s == '"' || *s == '\'') - { - // quoted string - char_t ch = *s++; - PUGI__SCANFOR(*s == ch); - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s++; - } - else if (s[0] == '<' && s[1] == '?') - { - // - s += 2; - PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s += 2; - } - else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') - { - s += 4; - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); - - s += 3; - } - else PUGI__THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_doctype_ignore(char_t* s) - { - size_t depth = 0; - - assert(s[0] == '<' && s[1] == '!' && s[2] == '['); - s += 3; - - while (*s) - { - if (s[0] == '<' && s[1] == '!' && s[2] == '[') - { - // nested ignore section - s += 3; - depth++; - } - else if (s[0] == ']' && s[1] == ']' && s[2] == '>') - { - // ignore section end - s += 3; - - if (depth == 0) - return s; - - depth--; - } - else s++; - } - - PUGI__THROW_ERROR(status_bad_doctype, s); - } - - char_t* parse_doctype_group(char_t* s, char_t endch) - { - size_t depth = 0; - - assert((s[0] == '<' || s[0] == 0) && s[1] == '!'); - s += 2; - - while (*s) - { - if (s[0] == '<' && s[1] == '!' && s[2] != '-') - { - if (s[2] == '[') - { - // ignore - s = parse_doctype_ignore(s); - if (!s) return s; - } - else - { - // some control group - s += 2; - depth++; - } - } - else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') - { - // unknown tag (forbidden), or some primitive group - s = parse_doctype_primitive(s); - if (!s) return s; - } - else if (*s == '>') - { - if (depth == 0) - return s; - - depth--; - s++; - } - else s++; - } - - if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); - - return s; - } - - char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) - { - // parse node contents, starting with exclamation mark - ++s; - - if (*s == '-') // 'value = s; // Save the offset. - } - - if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) - { - s = strconv_comment(s, endch); - - if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); - } - else - { - // Scan for terminating '-->'. - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_comment, s); - - if (PUGI__OPTSET(parse_comments)) - *s = 0; // Zero-terminate this segment at the first terminating '-'. - - s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. - } - } - else PUGI__THROW_ERROR(status_bad_comment, s); - } - else if (*s == '[') - { - // 'value = s; // Save the offset. - - if (PUGI__OPTSET(parse_eol)) - { - s = strconv_cdata(s, endch); - - if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); - } - else - { - // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); - - *s++ = 0; // Zero-terminate this segment. - } - } - else // Flagged for discard, but we still have to scan for the terminator. - { - // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); - - ++s; - } - - s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. - } - else PUGI__THROW_ERROR(status_bad_cdata, s); - } - else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E')) - { - s -= 2; - - if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); - - char_t* mark = s + 9; - - s = parse_doctype_group(s, endch); - if (!s) return s; - - assert((*s == 0 && endch == '>') || *s == '>'); - if (*s) *s++ = 0; - - if (PUGI__OPTSET(parse_doctype)) - { - while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; - - PUGI__PUSHNODE(node_doctype); - - cursor->value = mark; - } - } - else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); - else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); - else PUGI__THROW_ERROR(status_unrecognized_tag, s); - - return s; - } - - char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) - { - // load into registers - xml_node_struct* cursor = ref_cursor; - char_t ch = 0; - - // parse node contents, starting with question mark - ++s; - - // read PI target - char_t* target = s; - - if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); - - PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); - PUGI__CHECK_ERROR(status_bad_pi, s); - - // determine node type; stricmp / strcasecmp is not portable - bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; - - if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) - { - if (declaration) - { - // disallow non top-level declarations - if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); - - PUGI__PUSHNODE(node_declaration); - } - else - { - PUGI__PUSHNODE(node_pi); - } - - cursor->name = target; - - PUGI__ENDSEG(); - - // parse value/attributes - if (ch == '?') - { - // empty node - if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); - s += (*s == '>'); - - PUGI__POPNODE(); - } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - PUGI__SKIPWS(); - - // scan for tag end - char_t* value = s; - - PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); - - if (declaration) - { - // replace ending ? with / so that 'element' terminates properly - *s = '/'; - - // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES - s = value; - } - else - { - // store value and step over > - cursor->value = value; - PUGI__POPNODE(); - - PUGI__ENDSEG(); - - s += (*s == '>'); - } - } - else PUGI__THROW_ERROR(status_bad_pi, s); - } - else - { - // scan for tag end - PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); - - s += (s[1] == '>' ? 2 : 1); - } - - // store from registers - ref_cursor = cursor; - - return s; - } - - char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) - { - strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); - strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); - - char_t ch = 0; - xml_node_struct* cursor = root; - char_t* mark = s; - - while (*s != 0) - { - if (*s == '<') - { - ++s; - - LOC_TAG: - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' - { - PUGI__PUSHNODE(node_element); // Append a new node to the tree. - - cursor->name = s; - - PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. - - if (ch == '>') - { - // end of tag - } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - LOC_ATTRIBUTES: - while (true) - { - PUGI__SKIPWS(); // Eat any whitespace. - - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... - { - xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute. - if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); - - a->name = s; // Save the offset. - - PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. - - if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - PUGI__SKIPWS(); // Eat any whitespace. - - ch = *s; - ++s; - } - - if (ch == '=') // '<... #=...' - { - PUGI__SKIPWS(); // Eat any whitespace. - - if (*s == '"' || *s == '\'') // '<... #="...' - { - ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. - ++s; // Step over the quote. - a->value = s; // Save the offset. - - s = strconv_attribute(s, ch); - - if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); - - // After this line the loop continues from the start; - // Whitespaces, / and > are ok, symbols and EOF are wrong, - // everything else will be detected - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); - } - else PUGI__THROW_ERROR(status_bad_attribute, s); - } - else PUGI__THROW_ERROR(status_bad_attribute, s); - } - else if (*s == '/') - { - ++s; - - if (*s == '>') - { - PUGI__POPNODE(); - s++; - break; - } - else if (*s == 0 && endch == '>') - { - PUGI__POPNODE(); - break; - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - else if (*s == '>') - { - ++s; - - break; - } - else if (*s == 0 && endch == '>') - { - break; - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - - // !!! - } - else if (ch == '/') // '<#.../' - { - if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); - - PUGI__POPNODE(); // Pop. - - s += (*s == '>'); - } - else if (ch == 0) - { - // we stepped over null terminator, backtrack & handle closing tag - --s; - - if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); - } - else PUGI__THROW_ERROR(status_bad_start_element, s); - } - else if (*s == '/') - { - ++s; - - char_t* name = cursor->name; - if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); - - while (PUGI__IS_CHARTYPE(*s, ct_symbol)) - { - if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); - } - - if (*name) - { - if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); - else PUGI__THROW_ERROR(status_end_element_mismatch, s); - } - - PUGI__POPNODE(); // Pop. - - PUGI__SKIPWS(); - - if (*s == 0) - { - if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); - } - else - { - if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); - ++s; - } - } - else if (*s == '?') // 'first_child) continue; - } - } - - if (!PUGI__OPTSET(parse_trim_pcdata)) - s = mark; - - if (cursor->parent || PUGI__OPTSET(parse_fragment)) - { - PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. - - s = strconv_pcdata(s); - - PUGI__POPNODE(); // Pop since this is a standalone. - - if (!*s) break; - } - else - { - PUGI__SCANFOR(*s == '<'); // '...<' - if (!*s) break; - - ++s; - } - - // We're after '<' - goto LOC_TAG; - } - } - - // check that last tag is closed - if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s); - - return s; - } - - #ifdef PUGIXML_WCHAR_MODE - static char_t* parse_skip_bom(char_t* s) - { - unsigned int bom = 0xfeff; - return (s[0] == static_cast(bom)) ? s + 1 : s; - } - #else - static char_t* parse_skip_bom(char_t* s) - { - return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s; - } - #endif - - static bool has_element_node_siblings(xml_node_struct* node) - { - while (node) - { - if (PUGI__NODETYPE(node) == node_element) return true; - - node = node->next_sibling; - } - - return false; - } - - static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) - { - // allocator object is a part of document object - xml_allocator& alloc_ = *static_cast(xmldoc); - - // early-out for empty documents - if (length == 0) - return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); - - // get last child of the root before parsing - xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0; - - // create parser on stack - xml_parser parser(alloc_); - - // save last character and make buffer zero-terminated (speeds up parsing) - char_t endch = buffer[length - 1]; - buffer[length - 1] = 0; - - // skip BOM to make sure it does not end up as part of parse output - char_t* buffer_data = parse_skip_bom(buffer); - - // perform actual parsing - parser.parse_tree(buffer_data, root, optmsk, endch); - - // update allocator state - alloc_ = parser.alloc; - - xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); - assert(result.offset >= 0 && static_cast(result.offset) <= length); - - if (result) - { - // since we removed last character, we have to handle the only possible false positive (stray <) - if (endch == '<') - return make_parse_result(status_unrecognized_tag, length - 1); - - // check if there are any element nodes parsed - xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling : root->first_child; - - if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) - return make_parse_result(status_no_document_element, length - 1); - } - else - { - // roll back offset if it occurs on a null terminator in the source buffer - if (result.offset > 0 && static_cast(result.offset) == length - 1 && endch == 0) - result.offset--; - } - - return result; - } - }; - - // Output facilities - PUGI__FN xml_encoding get_write_native_encoding() - { - #ifdef PUGIXML_WCHAR_MODE - return get_wchar_encoding(); - #else - return encoding_utf8; - #endif - } - - PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) - { - // replace wchar encoding with utf implementation - if (encoding == encoding_wchar) return get_wchar_encoding(); - - // replace utf16 encoding with utf16 with specific endianness - if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - // replace utf32 encoding with utf32 with specific endianness - if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - // only do autodetection if no explicit encoding is requested - if (encoding != encoding_auto) return encoding; - - // assume utf8 encoding - return encoding_utf8; - } - -#ifdef PUGIXML_WCHAR_MODE - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) - { - if (length < 1) return 0; - - // discard last character if it's the lead of a surrogate pair - return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; - } - - PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) - { - // only endian-swapping is required - if (need_endian_swap_utf(encoding, get_wchar_encoding())) - { - convert_wchar_endian_swap(r_char, data, length); - - return length * sizeof(char_t); - } - - // convert to utf8 - if (encoding == encoding_utf8) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - return static_cast(end - dest); - } - - // convert to utf16 - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - // convert to utf32 - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - // convert to latin1 - if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); - return 0; - } -#else - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) - { - if (length < 5) return 0; - - for (size_t i = 1; i <= 4; ++i) - { - uint8_t ch = static_cast(data[length - i]); - - // either a standalone character or a leading one - if ((ch & 0xc0) != 0x80) return length - i; - } - - // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk - return length; - } - - PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) - { - if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) - { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); - } - - if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) - { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary - xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); - } - - if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); - return 0; - } -#endif - - class xml_buffered_writer - { - xml_buffered_writer(const xml_buffered_writer&); - xml_buffered_writer& operator=(const xml_buffered_writer&); - - public: - xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) - { - PUGI__STATIC_ASSERT(bufcapacity >= 8); - } - - ~xml_buffered_writer() - { - flush(); - } - - size_t flush() - { - flush(buffer, bufsize); - bufsize = 0; - return 0; - } - - void flush(const char_t* data, size_t size) - { - if (size == 0) return; - - // fast path, just write data - if (encoding == get_write_native_encoding()) - writer.write(data, size * sizeof(char_t)); - else - { - // convert chunk - size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); - assert(result <= sizeof(scratch)); - - // write data - writer.write(scratch.data_u8, result); - } - } - - void write_direct(const char_t* data, size_t length) - { - // flush the remaining buffer contents - flush(); - - // handle large chunks - if (length > bufcapacity) - { - if (encoding == get_write_native_encoding()) - { - // fast path, can just write data chunk - writer.write(data, length * sizeof(char_t)); - return; - } - - // need to convert in suitable chunks - while (length > bufcapacity) - { - // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer - // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) - size_t chunk_size = get_valid_length(data, bufcapacity); - assert(chunk_size); - - // convert chunk and write - flush(data, chunk_size); - - // iterate - data += chunk_size; - length -= chunk_size; - } - - // small tail is copied below - bufsize = 0; - } - - memcpy(buffer + bufsize, data, length * sizeof(char_t)); - bufsize += length; - } - - void write_buffer(const char_t* data, size_t length) - { - size_t offset = bufsize; - - if (offset + length <= bufcapacity) - { - memcpy(buffer + offset, data, length * sizeof(char_t)); - bufsize = offset + length; - } - else - { - write_direct(data, length); - } - } - - void write_string(const char_t* data) - { - // write the part of the string that fits in the buffer - size_t offset = bufsize; - - while (*data && offset < bufcapacity) - buffer[offset++] = *data++; - - // write the rest - if (offset < bufcapacity) - { - bufsize = offset; - } - else - { - // backtrack a bit if we have split the codepoint - size_t length = offset - bufsize; - size_t extra = length - get_valid_length(data - length, length); - - bufsize = offset - extra; - - write_direct(data - extra, strlength(data) + extra); - } - } - - void write(char_t d0) - { - size_t offset = bufsize; - if (offset > bufcapacity - 1) offset = flush(); - - buffer[offset + 0] = d0; - bufsize = offset + 1; - } - - void write(char_t d0, char_t d1) - { - size_t offset = bufsize; - if (offset > bufcapacity - 2) offset = flush(); - - buffer[offset + 0] = d0; - buffer[offset + 1] = d1; - bufsize = offset + 2; - } - - void write(char_t d0, char_t d1, char_t d2) - { - size_t offset = bufsize; - if (offset > bufcapacity - 3) offset = flush(); - - buffer[offset + 0] = d0; - buffer[offset + 1] = d1; - buffer[offset + 2] = d2; - bufsize = offset + 3; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3) - { - size_t offset = bufsize; - if (offset > bufcapacity - 4) offset = flush(); - - buffer[offset + 0] = d0; - buffer[offset + 1] = d1; - buffer[offset + 2] = d2; - buffer[offset + 3] = d3; - bufsize = offset + 4; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) - { - size_t offset = bufsize; - if (offset > bufcapacity - 5) offset = flush(); - - buffer[offset + 0] = d0; - buffer[offset + 1] = d1; - buffer[offset + 2] = d2; - buffer[offset + 3] = d3; - buffer[offset + 4] = d4; - bufsize = offset + 5; - } - - void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) - { - size_t offset = bufsize; - if (offset > bufcapacity - 6) offset = flush(); - - buffer[offset + 0] = d0; - buffer[offset + 1] = d1; - buffer[offset + 2] = d2; - buffer[offset + 3] = d3; - buffer[offset + 4] = d4; - buffer[offset + 5] = d5; - bufsize = offset + 6; - } - - // utf8 maximum expansion: x4 (-> utf32) - // utf16 maximum expansion: x2 (-> utf32) - // utf32 maximum expansion: x1 - enum - { - bufcapacitybytes = - #ifdef PUGIXML_MEMORY_OUTPUT_STACK - PUGIXML_MEMORY_OUTPUT_STACK - #else - 10240 - #endif - , - bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) - }; - - char_t buffer[bufcapacity]; - - union - { - uint8_t data_u8[4 * bufcapacity]; - uint16_t data_u16[2 * bufcapacity]; - uint32_t data_u32[bufcapacity]; - char_t data_char[bufcapacity]; - } scratch; - - xml_writer& writer; - size_t bufsize; - xml_encoding encoding; - }; - - PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) - { - while (*s) - { - const char_t* prev = s; - - // While *s is a usual symbol - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); - - writer.write_buffer(prev, static_cast(s - prev)); - - switch (*s) - { - case 0: break; - case '&': - writer.write('&', 'a', 'm', 'p', ';'); - ++s; - break; - case '<': - writer.write('&', 'l', 't', ';'); - ++s; - break; - case '>': - writer.write('&', 'g', 't', ';'); - ++s; - break; - case '"': - writer.write('&', 'q', 'u', 'o', 't', ';'); - ++s; - break; - default: // s is not a usual symbol - { - unsigned int ch = static_cast(*s++); - assert(ch < 32); - - writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); - } - } - } - } - - PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) - { - if (flags & format_no_escapes) - writer.write_string(s); - else - text_output_escaped(writer, s, type); - } - - PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) - { - do - { - writer.write('<', '!', '[', 'C', 'D'); - writer.write('A', 'T', 'A', '['); - - const char_t* prev = s; - - // look for ]]> sequence - we can't output it as is since it terminates CDATA - while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; - - // skip ]] if we stopped at ]]>, > will go to the next CDATA section - if (*s) s += 2; - - writer.write_buffer(prev, static_cast(s - prev)); - - writer.write(']', ']', '>'); - } - while (*s); - } - - PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) - { - switch (indent_length) - { - case 1: - { - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent[0]); - break; - } - - case 2: - { - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent[0], indent[1]); - break; - } - - case 3: - { - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent[0], indent[1], indent[2]); - break; - } - - case 4: - { - for (unsigned int i = 0; i < depth; ++i) - writer.write(indent[0], indent[1], indent[2], indent[3]); - break; - } - - default: - { - for (unsigned int i = 0; i < depth; ++i) - writer.write_buffer(indent, indent_length); - } - } - } - - PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) - { - writer.write('<', '!', '-', '-'); - - while (*s) - { - const char_t* prev = s; - - // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body - while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s; - - writer.write_buffer(prev, static_cast(s - prev)); - - if (*s) - { - assert(*s == '-'); - - writer.write('-', ' '); - ++s; - } - } - - writer.write('-', '-', '>'); - } - - PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) - { - while (*s) - { - const char_t* prev = s; - - // look for ?> sequence - we can't output it since ?> terminates PI - while (*s && !(s[0] == '?' && s[1] == '>')) ++s; - - writer.write_buffer(prev, static_cast(s - prev)); - - if (*s) - { - assert(s[0] == '?' && s[1] == '>'); - - writer.write('?', ' ', '>'); - s += 2; - } - } - } - - PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) - { - writer.write(' '); - writer.write_string(a->name ? a->name : default_name); - writer.write('=', '"'); - - if (a->value) - text_output(writer, a->value, ctx_special_attr, flags); - - writer.write('"'); - } - } - - PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - const char_t* name = node->name ? node->name : default_name; - - writer.write('<'); - writer.write_string(name); - - if (node->first_attribute) - node_output_attributes(writer, node, flags); - - if (!node->first_child) - { - writer.write(' ', '/', '>'); - - return false; - } - else - { - writer.write('>'); - - return true; - } - } - - PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - const char_t* name = node->name ? node->name : default_name; - - writer.write('<', '/'); - writer.write_string(name); - writer.write('>'); - } - - PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) - { - const char_t* default_name = PUGIXML_TEXT(":anonymous"); - - switch (PUGI__NODETYPE(node)) - { - case node_pcdata: - text_output(writer, node->value ? node->value : PUGIXML_TEXT(""), ctx_special_pcdata, flags); - break; - - case node_cdata: - text_output_cdata(writer, node->value ? node->value : PUGIXML_TEXT("")); - break; - - case node_comment: - node_output_comment(writer, node->value ? node->value : PUGIXML_TEXT("")); - break; - - case node_pi: - writer.write('<', '?'); - writer.write_string(node->name ? node->name : default_name); - - if (node->value) - { - writer.write(' '); - node_output_pi_value(writer, node->value); - } - - writer.write('?', '>'); - break; - - case node_declaration: - writer.write('<', '?'); - writer.write_string(node->name ? node->name : default_name); - node_output_attributes(writer, node, flags); - writer.write('?', '>'); - break; - - case node_doctype: - writer.write('<', '!', 'D', 'O', 'C'); - writer.write('T', 'Y', 'P', 'E'); - - if (node->value) - { - writer.write(' '); - writer.write_string(node->value); - } - - writer.write('>'); - break; - - default: - assert(!"Invalid node type"); - } - } - - enum indent_flags_t - { - indent_newline = 1, - indent_indent = 2 - }; - - PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) - { - size_t indent_length = ((flags & (format_indent | format_raw)) == format_indent) ? strlength(indent) : 0; - unsigned int indent_flags = indent_indent; - - xml_node_struct* node = root; - - do - { - assert(node); - - // begin writing current node - if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata) - { - node_output_simple(writer, node, flags); - - indent_flags = 0; - } - else - { - if ((indent_flags & indent_newline) && (flags & format_raw) == 0) - writer.write('\n'); - - if ((indent_flags & indent_indent) && indent_length) - text_output_indent(writer, indent, indent_length, depth); - - if (PUGI__NODETYPE(node) == node_element) - { - indent_flags = indent_newline | indent_indent; - - if (node_output_start(writer, node, flags)) - { - node = node->first_child; - depth++; - continue; - } - } - else if (PUGI__NODETYPE(node) == node_document) - { - indent_flags = indent_indent; - - if (node->first_child) - { - node = node->first_child; - continue; - } - } - else - { - node_output_simple(writer, node, flags); - - indent_flags = indent_newline | indent_indent; - } - } - - // continue to the next node - while (node != root) - { - if (node->next_sibling) - { - node = node->next_sibling; - break; - } - - node = node->parent; - - // write closing node - if (PUGI__NODETYPE(node) == node_element) - { - depth--; - - if ((indent_flags & indent_newline) && (flags & format_raw) == 0) - writer.write('\n'); - - if ((indent_flags & indent_indent) && indent_length) - text_output_indent(writer, indent, indent_length, depth); - - node_output_end(writer, node); - - indent_flags = indent_newline | indent_indent; - } - } - } - while (node != root); - - if ((indent_flags & indent_newline) && (flags & format_raw) == 0) - writer.write('\n'); - } - - PUGI__FN bool has_declaration(xml_node_struct* node) - { - for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) - { - xml_node_type type = PUGI__NODETYPE(child); - - if (type == node_declaration) return true; - if (type == node_element) return false; - } - - return false; - } - - PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) - { - for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) - if (a == attr) - return true; - - return false; - } - - PUGI__FN bool allow_insert_attribute(xml_node_type parent) - { - return parent == node_element || parent == node_declaration; - } - - PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) - { - if (parent != node_document && parent != node_element) return false; - if (child == node_document || child == node_null) return false; - if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; - - return true; - } - - PUGI__FN bool allow_move(xml_node parent, xml_node child) - { - // check that child can be a child of parent - if (!allow_insert_child(parent.type(), child.type())) - return false; - - // check that node is not moved between documents - if (parent.root() != child.root()) - return false; - - // check that new parent is not in the child subtree - xml_node cur = parent; - - while (cur) - { - if (cur == child) - return false; - - cur = cur.parent(); - } - - return true; - } - - PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc) - { - assert(!dest && (header & header_mask) == 0); - - if (source) - { - if (alloc && (source_header & header_mask) == 0) - { - dest = source; - - // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared - header |= xml_memory_page_contents_shared_mask; - source_header |= xml_memory_page_contents_shared_mask; - } - else - strcpy_insitu(dest, header, header_mask, source); - } - } - - PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) - { - node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); - node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); - - for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) - { - xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn)); - - if (da) - { - node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); - } - } - } - - PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) - { - xml_allocator& alloc = get_allocator(dn); - xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0; - - node_copy_contents(dn, sn, shared_alloc); - - xml_node_struct* dit = dn; - xml_node_struct* sit = sn->first_child; - - while (sit && sit != sn) - { - if (sit != dn) - { - xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); - - if (copy) - { - node_copy_contents(copy, sit, shared_alloc); - - if (sit->first_child) - { - dit = copy; - sit = sit->first_child; - continue; - } - } - } - - // continue to the next node - do - { - if (sit->next_sibling) - { - sit = sit->next_sibling; - break; - } - - sit = sit->parent; - dit = dit->parent; - } - while (sit != sn); - } - } - - inline bool is_text_node(xml_node_struct* node) - { - xml_node_type type = PUGI__NODETYPE(node); - - return type == node_pcdata || type == node_cdata; - } - - // get value with conversion functions - PUGI__FN int get_integer_base(const char_t* value) - { - const char_t* s = value; - - while (PUGI__IS_CHARTYPE(*s, ct_space)) - s++; - - if (*s == '-') - s++; - - return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; - } - - PUGI__FN int get_value_int(const char_t* value, int def) - { - if (!value) return def; - - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstol(value, 0, base)); - #else - return static_cast(strtol(value, 0, base)); - #endif - } - - PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def) - { - if (!value) return def; - - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstoul(value, 0, base)); - #else - return static_cast(strtoul(value, 0, base)); - #endif - } - - PUGI__FN double get_value_double(const char_t* value, double def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return wcstod(value, 0); - #else - return strtod(value, 0); - #endif - } - - PUGI__FN float get_value_float(const char_t* value, float def) - { - if (!value) return def; - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstod(value, 0)); - #else - return static_cast(strtod(value, 0)); - #endif - } - - PUGI__FN bool get_value_bool(const char_t* value, bool def) - { - if (!value) return def; - - // only look at first char - char_t first = *value; - - // 1*, t* (true), T* (True), y* (yes), Y* (YES) - return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long get_value_llong(const char_t* value, long long def) - { - if (!value) return def; - - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - #ifdef PUGI__MSVC_CRT_VERSION - return _wcstoi64(value, 0, base); - #else - return wcstoll(value, 0, base); - #endif - #else - #ifdef PUGI__MSVC_CRT_VERSION - return _strtoi64(value, 0, base); - #else - return strtoll(value, 0, base); - #endif - #endif - } - - PUGI__FN unsigned long long get_value_ullong(const char_t* value, unsigned long long def) - { - if (!value) return def; - - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - #ifdef PUGI__MSVC_CRT_VERSION - return _wcstoui64(value, 0, base); - #else - return wcstoull(value, 0, base); - #endif - #else - #ifdef PUGI__MSVC_CRT_VERSION - return _strtoui64(value, 0, base); - #else - return strtoull(value, 0, base); - #endif - #endif - } -#endif - - // set value with conversion functions - PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128]) - { - #ifdef PUGIXML_WCHAR_MODE - char_t wbuf[128]; - impl::widen_ascii(wbuf, buf); - - return strcpy_insitu(dest, header, header_mask, wbuf); - #else - return strcpy_insitu(dest, header, header_mask, buf); - #endif - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value) - { - char buf[128]; - sprintf(buf, "%d", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value) - { - char buf[128]; - sprintf(buf, "%u", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, float value) - { - char buf[128]; - sprintf(buf, "%.9g", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value) - { - char buf[128]; - sprintf(buf, "%.17g", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value) - { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, long long value) - { - char buf[128]; - sprintf(buf, "%lld", value); - - return set_value_buffer(dest, header, header_mask, buf); - } - - PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned long long value) - { - char buf[128]; - sprintf(buf, "%llu", value); - - return set_value_buffer(dest, header, header_mask, buf); - } -#endif - - // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick - PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) - { - #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) - // there are 64-bit versions of fseek/ftell, let's use them - typedef __int64 length_type; - - _fseeki64(file, 0, SEEK_END); - length_type length = _ftelli64(file); - _fseeki64(file, 0, SEEK_SET); - #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) - // there are 64-bit versions of fseek/ftell, let's use them - typedef off64_t length_type; - - fseeko64(file, 0, SEEK_END); - length_type length = ftello64(file); - fseeko64(file, 0, SEEK_SET); - #else - // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. - typedef long length_type; - - fseek(file, 0, SEEK_END); - length_type length = ftell(file); - fseek(file, 0, SEEK_SET); - #endif - - // check for I/O errors - if (length < 0) return status_io_error; - - // check for overflow - size_t result = static_cast(length); - - if (static_cast(result) != length) return status_out_of_memory; - - // finalize - out_result = result; - - return status_ok; - } - - PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) - { - // We only need to zero-terminate if encoding conversion does not do it for us - #ifdef PUGIXML_WCHAR_MODE - xml_encoding wchar_encoding = get_wchar_encoding(); - - if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding)) - { - size_t length = size / sizeof(char_t); - - static_cast(buffer)[length] = 0; - return (length + 1) * sizeof(char_t); - } - #else - if (encoding == encoding_utf8) - { - static_cast(buffer)[size] = 0; - return size + 1; - } - #endif - - return size; - } - - PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) - { - if (!file) return make_parse_result(status_file_not_found); - - // get file size (can result in I/O errors) - size_t size = 0; - xml_parse_status size_status = get_file_size(file, size); - - if (size_status != status_ok) - { - fclose(file); - return make_parse_result(size_status); - } - - size_t max_suffix_size = sizeof(char_t); - - // allocate buffer for the whole file - char* contents = static_cast(xml_memory::allocate(size + max_suffix_size)); - - if (!contents) - { - fclose(file); - return make_parse_result(status_out_of_memory); - } - - // read file in memory - size_t read_size = fread(contents, 1, size, file); - fclose(file); - - if (read_size != size) - { - xml_memory::deallocate(contents); - return make_parse_result(status_io_error); - } - - xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); - - return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding); - } - -#ifndef PUGIXML_NO_STL - template struct xml_stream_chunk - { - static xml_stream_chunk* create() - { - void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); - - return new (memory) xml_stream_chunk(); - } - - static void destroy(void* ptr) - { - xml_stream_chunk* chunk = static_cast(ptr); - - // free chunk chain - while (chunk) - { - xml_stream_chunk* next_ = chunk->next; - - xml_memory::deallocate(chunk); - - chunk = next_; - } - } - - xml_stream_chunk(): next(0), size(0) - { - } - - xml_stream_chunk* next; - size_t size; - - T data[xml_memory_page_size / sizeof(T)]; - }; - - template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) - { - buffer_holder chunks(0, xml_stream_chunk::destroy); - - // read file to a chunk list - size_t total = 0; - xml_stream_chunk* last = 0; - - while (!stream.eof()) - { - // allocate new chunk - xml_stream_chunk* chunk = xml_stream_chunk::create(); - if (!chunk) return status_out_of_memory; - - // append chunk to list - if (last) last = last->next = chunk; - else chunks.data = last = chunk; - - // read data to chunk - stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); - chunk->size = static_cast(stream.gcount()) * sizeof(T); - - // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors - if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; - - // guard against huge files (chunk size is small enough to make this overflow check work) - if (total + chunk->size < total) return status_out_of_memory; - total += chunk->size; - } - - size_t max_suffix_size = sizeof(char_t); - - // copy chunk list to a contiguous buffer - char* buffer = static_cast(xml_memory::allocate(total + max_suffix_size)); - if (!buffer) return status_out_of_memory; - - char* write = buffer; - - for (xml_stream_chunk* chunk = static_cast*>(chunks.data); chunk; chunk = chunk->next) - { - assert(write + chunk->size <= buffer + total); - memcpy(write, chunk->data, chunk->size); - write += chunk->size; - } - - assert(write == buffer + total); - - // return buffer - *out_buffer = buffer; - *out_size = total; - - return status_ok; - } - - template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) - { - // get length of remaining data in stream - typename std::basic_istream::pos_type pos = stream.tellg(); - stream.seekg(0, std::ios::end); - std::streamoff length = stream.tellg() - pos; - stream.seekg(pos); - - if (stream.fail() || pos < 0) return status_io_error; - - // guard against huge files - size_t read_length = static_cast(length); - - if (static_cast(read_length) != length || length < 0) return status_out_of_memory; - - size_t max_suffix_size = sizeof(char_t); - - // read stream data into memory (guard against stream exceptions with buffer holder) - buffer_holder buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate); - if (!buffer.data) return status_out_of_memory; - - stream.read(static_cast(buffer.data), static_cast(read_length)); - - // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors - if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; - - // return buffer - size_t actual_length = static_cast(stream.gcount()); - assert(actual_length <= read_length); - - *out_buffer = buffer.release(); - *out_size = actual_length * sizeof(T); - - return status_ok; - } - - template PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) - { - void* buffer = 0; - size_t size = 0; - xml_parse_status status = status_ok; - - // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits) - if (stream.fail()) return make_parse_result(status_io_error); - - // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) - if (stream.tellg() < 0) - { - stream.clear(); // clear error flags that could be set by a failing tellg - status = load_stream_data_noseek(stream, &buffer, &size); - } - else - status = load_stream_data_seek(stream, &buffer, &size); - - if (status != status_ok) return make_parse_result(status); - - xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); - - return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding); - } -#endif - -#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) - { - return _wfopen(path, mode); - } -#else - PUGI__FN char* convert_path_heap(const wchar_t* str) - { - assert(str); - - // first pass: get length in utf8 characters - size_t length = strlength_wide(str); - size_t size = as_utf8_begin(str, length); - - // allocate resulting string - char* result = static_cast(xml_memory::allocate(size + 1)); - if (!result) return 0; - - // second pass: convert to utf8 - as_utf8_end(result, size, str, length); - - return result; - } - - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) - { - // there is no standard function to open wide paths, so our best bet is to try utf8 path - char* path_utf8 = convert_path_heap(path); - if (!path_utf8) return 0; - - // convert mode to ASCII (we mirror _wfopen interface) - char mode_ascii[4] = {0}; - for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); - - // try to open the utf8 path - FILE* result = fopen(path_utf8, mode_ascii); - - // free dummy buffer - xml_memory::deallocate(path_utf8); - - return result; - } -#endif - - PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) - { - if (!file) return false; - - xml_writer_file writer(file); - doc.save(writer, indent, flags, encoding); - - int result = ferror(file); - - fclose(file); - - return result == 0; - } - - PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) - { - // check input buffer - if (!contents && size) return make_parse_result(status_io_error); - - // get actual encoding - xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); - - // get private buffer - char_t* buffer = 0; - size_t length = 0; - - if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); - - // delete original buffer if we performed a conversion - if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); - - // store buffer for offset_debug - doc->buffer = buffer; - - // parse - xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); - - // remember encoding - res.encoding = buffer_encoding; - - // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself - if (own || buffer != contents) *out_buffer = buffer; - - return res; - } -PUGI__NS_END - -namespace pugi -{ - PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) - { - } - - PUGI__FN void xml_writer_file::write(const void* data, size_t size) - { - size_t result = fwrite(data, 1, size, static_cast(file)); - (void)!result; // unfortunately we can't do proper error handling here - } - -#ifndef PUGIXML_NO_STL - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) - { - } - - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) - { - } - - PUGI__FN void xml_writer_stream::write(const void* data, size_t size) - { - if (narrow_stream) - { - assert(!wide_stream); - narrow_stream->write(reinterpret_cast(data), static_cast(size)); - } - else - { - assert(wide_stream); - assert(size % sizeof(wchar_t) == 0); - - wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); - } - } -#endif - - PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) - { - } - - PUGI__FN xml_tree_walker::~xml_tree_walker() - { - } - - PUGI__FN int xml_tree_walker::depth() const - { - return _depth; - } - - PUGI__FN bool xml_tree_walker::begin(xml_node&) - { - return true; - } - - PUGI__FN bool xml_tree_walker::end(xml_node&) - { - return true; - } - - PUGI__FN xml_attribute::xml_attribute(): _attr(0) - { - } - - PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) - { - } - - PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) - { - } - - PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const - { - return _attr ? unspecified_bool_xml_attribute : 0; - } - - PUGI__FN bool xml_attribute::operator!() const - { - return !_attr; - } - - PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const - { - return (_attr == r._attr); - } - - PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const - { - return (_attr != r._attr); - } - - PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const - { - return (_attr < r._attr); - } - - PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const - { - return (_attr > r._attr); - } - - PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const - { - return (_attr <= r._attr); - } - - PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const - { - return (_attr >= r._attr); - } - - PUGI__FN xml_attribute xml_attribute::next_attribute() const - { - return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); - } - - PUGI__FN xml_attribute xml_attribute::previous_attribute() const - { - return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); - } - - PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const - { - return (_attr && _attr->value) ? _attr->value : def; - } - - PUGI__FN int xml_attribute::as_int(int def) const - { - return impl::get_value_int(_attr ? _attr->value : 0, def); - } - - PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const - { - return impl::get_value_uint(_attr ? _attr->value : 0, def); - } - - PUGI__FN double xml_attribute::as_double(double def) const - { - return impl::get_value_double(_attr ? _attr->value : 0, def); - } - - PUGI__FN float xml_attribute::as_float(float def) const - { - return impl::get_value_float(_attr ? _attr->value : 0, def); - } - - PUGI__FN bool xml_attribute::as_bool(bool def) const - { - return impl::get_value_bool(_attr ? _attr->value : 0, def); - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long xml_attribute::as_llong(long long def) const - { - return impl::get_value_llong(_attr ? _attr->value : 0, def); - } - - PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const - { - return impl::get_value_ullong(_attr ? _attr->value : 0, def); - } -#endif - - PUGI__FN bool xml_attribute::empty() const - { - return !_attr; - } - - PUGI__FN const char_t* xml_attribute::name() const - { - return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_attribute::value() const - { - return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); - } - - PUGI__FN size_t xml_attribute::hash_value() const - { - return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); - } - - PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const - { - return _attr; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) - { - set_value(rhs); - return *this; - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) - { - set_value(rhs); - return *this; - } - - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) - { - set_value(rhs); - return *this; - } -#endif - - PUGI__FN bool xml_attribute::set_name(const char_t* rhs) - { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(const char_t* rhs) - { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(int rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(unsigned int rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(double rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(float rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(bool rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN bool xml_attribute::set_value(long long rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } - - PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) - { - if (!_attr) return false; - - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); - } -#endif - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_node::xml_node(): _root(0) - { - } - - PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) - { - } - - PUGI__FN static void unspecified_bool_xml_node(xml_node***) - { - } - - PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const - { - return _root ? unspecified_bool_xml_node : 0; - } - - PUGI__FN bool xml_node::operator!() const - { - return !_root; - } - - PUGI__FN xml_node::iterator xml_node::begin() const - { - return iterator(_root ? _root->first_child : 0, _root); - } - - PUGI__FN xml_node::iterator xml_node::end() const - { - return iterator(0, _root); - } - - PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const - { - return attribute_iterator(_root ? _root->first_attribute : 0, _root); - } - - PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const - { - return attribute_iterator(0, _root); - } - - PUGI__FN xml_object_range xml_node::children() const - { - return xml_object_range(begin(), end()); - } - - PUGI__FN xml_object_range xml_node::children(const char_t* name_) const - { - return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); - } - - PUGI__FN xml_object_range xml_node::attributes() const - { - return xml_object_range(attributes_begin(), attributes_end()); - } - - PUGI__FN bool xml_node::operator==(const xml_node& r) const - { - return (_root == r._root); - } - - PUGI__FN bool xml_node::operator!=(const xml_node& r) const - { - return (_root != r._root); - } - - PUGI__FN bool xml_node::operator<(const xml_node& r) const - { - return (_root < r._root); - } - - PUGI__FN bool xml_node::operator>(const xml_node& r) const - { - return (_root > r._root); - } - - PUGI__FN bool xml_node::operator<=(const xml_node& r) const - { - return (_root <= r._root); - } - - PUGI__FN bool xml_node::operator>=(const xml_node& r) const - { - return (_root >= r._root); - } - - PUGI__FN bool xml_node::empty() const - { - return !_root; - } - - PUGI__FN const char_t* xml_node::name() const - { - return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); - } - - PUGI__FN xml_node_type xml_node::type() const - { - return _root ? PUGI__NODETYPE(_root) : node_null; - } - - PUGI__FN const char_t* xml_node::value() const - { - return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); - } - - PUGI__FN xml_node xml_node::child(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const - { - if (!_root) return xml_attribute(); - - for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) - return xml_attribute(i); - - return xml_attribute(); - } - - PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_node xml_node::next_sibling() const - { - return _root ? xml_node(_root->next_sibling) : xml_node(); - } - - PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); - - return xml_node(); - } - - PUGI__FN xml_node xml_node::previous_sibling() const - { - if (!_root) return xml_node(); - - if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); - else return xml_node(); - } - - PUGI__FN xml_node xml_node::parent() const - { - return _root ? xml_node(_root->parent) : xml_node(); - } - - PUGI__FN xml_node xml_node::root() const - { - return _root ? xml_node(&impl::get_document(_root)) : xml_node(); - } - - PUGI__FN xml_text xml_node::text() const - { - return xml_text(_root); - } - - PUGI__FN const char_t* xml_node::child_value() const - { - if (!_root) return PUGIXML_TEXT(""); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->value && impl::is_text_node(i)) - return i->value; - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const - { - return child(name_).child_value(); - } - - PUGI__FN xml_attribute xml_node::first_attribute() const - { - return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); - } - - PUGI__FN xml_attribute xml_node::last_attribute() const - { - return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); - } - - PUGI__FN xml_node xml_node::first_child() const - { - return _root ? xml_node(_root->first_child) : xml_node(); - } - - PUGI__FN xml_node xml_node::last_child() const - { - return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); - } - - PUGI__FN bool xml_node::set_name(const char_t* rhs) - { - switch (type()) - { - case node_pi: - case node_declaration: - case node_element: - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs); - - default: - return false; - } - } - - PUGI__FN bool xml_node::set_value(const char_t* rhs) - { - switch (type()) - { - case node_pi: - case node_cdata: - case node_pcdata: - case node_comment: - case node_doctype: - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs); - - default: - return false; - } - } - - PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) - { - if (!impl::allow_insert_attribute(type())) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - impl::append_attribute(a._attr, _root); - - a.set_name(name_); - - return a; - } - - PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) - { - if (!impl::allow_insert_attribute(type())) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - impl::prepend_attribute(a._attr, _root); - - a.set_name(name_); - - return a; - } - - PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) - { - if (!impl::allow_insert_attribute(type())) return xml_attribute(); - if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - impl::insert_attribute_after(a._attr, attr._attr, _root); - - a.set_name(name_); - - return a; - } - - PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) - { - if (!impl::allow_insert_attribute(type())) return xml_attribute(); - if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - - xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); - if (!a) return xml_attribute(); - - impl::insert_attribute_before(a._attr, attr._attr, _root); - - a.set_name(name_); - - return a; - } - - PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) - { - if (!proto) return xml_attribute(); - - xml_attribute result = append_attribute(proto.name()); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) - { - if (!proto) return xml_attribute(); - - xml_attribute result = prepend_attribute(proto.name()); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) - { - if (!proto) return xml_attribute(); - - xml_attribute result = insert_attribute_after(proto.name(), attr); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) - { - if (!proto) return xml_attribute(); - - xml_attribute result = insert_attribute_before(proto.name(), attr); - result.set_value(proto.value()); - - return result; - } - - PUGI__FN xml_node xml_node::append_child(xml_node_type type_) - { - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::append_node(n._root, _root); - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) - { - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::prepend_node(n._root, _root); - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) - { - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::insert_node_before(n._root, node._root); - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) - { - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::insert_node_after(n._root, node._root); - - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); - - return n; - } - - PUGI__FN xml_node xml_node::append_child(const char_t* name_) - { - xml_node result = append_child(node_element); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) - { - xml_node result = prepend_child(node_element); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) - { - xml_node result = insert_child_after(node_element, node); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) - { - xml_node result = insert_child_before(node_element, node); - - result.set_name(name_); - - return result; - } - - PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) - { - xml_node_type type_ = proto.type(); - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::append_node(n._root, _root); - impl::node_copy_tree(n._root, proto._root); - - return n; - } - - PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) - { - xml_node_type type_ = proto.type(); - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::prepend_node(n._root, _root); - impl::node_copy_tree(n._root, proto._root); - - return n; - } - - PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) - { - xml_node_type type_ = proto.type(); - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::insert_node_after(n._root, node._root); - impl::node_copy_tree(n._root, proto._root); - - return n; - } - - PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) - { - xml_node_type type_ = proto.type(); - if (!impl::allow_insert_child(type(), type_)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - - xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); - if (!n) return xml_node(); - - impl::insert_node_before(n._root, node._root); - impl::node_copy_tree(n._root, proto._root); - - return n; - } - - PUGI__FN xml_node xml_node::append_move(const xml_node& moved) - { - if (!impl::allow_move(*this, moved)) return xml_node(); - - // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers - impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; - - impl::remove_node(moved._root); - impl::append_node(moved._root, _root); - - return moved; - } - - PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved) - { - if (!impl::allow_move(*this, moved)) return xml_node(); - - // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers - impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; - - impl::remove_node(moved._root); - impl::prepend_node(moved._root, _root); - - return moved; - } - - PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) - { - if (!impl::allow_move(*this, moved)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - if (moved._root == node._root) return xml_node(); - - // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers - impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; - - impl::remove_node(moved._root); - impl::insert_node_after(moved._root, node._root); - - return moved; - } - - PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) - { - if (!impl::allow_move(*this, moved)) return xml_node(); - if (!node._root || node._root->parent != _root) return xml_node(); - if (moved._root == node._root) return xml_node(); - - // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers - impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; - - impl::remove_node(moved._root); - impl::insert_node_before(moved._root, node._root); - - return moved; - } - - PUGI__FN bool xml_node::remove_attribute(const char_t* name_) - { - return remove_attribute(attribute(name_)); - } - - PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) - { - if (!_root || !a._attr) return false; - if (!impl::is_attribute_of(a._attr, _root)) return false; - - impl::remove_attribute(a._attr, _root); - impl::destroy_attribute(a._attr, impl::get_allocator(_root)); - - return true; - } - - PUGI__FN bool xml_node::remove_child(const char_t* name_) - { - return remove_child(child(name_)); - } - - PUGI__FN bool xml_node::remove_child(const xml_node& n) - { - if (!_root || !n._root || n._root->parent != _root) return false; - - impl::remove_node(n._root); - impl::destroy_node(n._root, impl::get_allocator(_root)); - - return true; - } - - PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - // append_buffer is only valid for elements/documents - if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); - - // get document node - impl::xml_document_struct* doc = &impl::get_document(_root); - - // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense - doc->header |= impl::xml_memory_page_contents_shared_mask; - - // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) - impl::xml_memory_page* page = 0; - impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); - (void)page; - - if (!extra) return impl::make_parse_result(status_out_of_memory); - - // save name; name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level - char_t* rootname = _root->name; - _root->name = 0; - - // parse - char_t* buffer = 0; - xml_parse_result res = impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &buffer); - - // restore name - _root->name = rootname; - - // add extra buffer to the list - extra->buffer = buffer; - extra->next = doc->extra_buffers; - doc->extra_buffers = extra; - - return res; - } - - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) - { - for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT(""))) - return xml_node(i); - } - - return xml_node(); - } - - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const - { - if (!_root) return xml_node(); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT(""))) - return xml_node(i); - - return xml_node(); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN string_t xml_node::path(char_t delimiter) const - { - xml_node cursor = *this; // Make a copy. - - string_t result = cursor.name(); - - while (cursor.parent()) - { - cursor = cursor.parent(); - - string_t temp = cursor.name(); - temp += delimiter; - temp += result; - result.swap(temp); - } - - return result; - } -#endif - - PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const - { - xml_node found = *this; // Current search context. - - if (!_root || !path_ || !path_[0]) return found; - - if (path_[0] == delimiter) - { - // Absolute path; e.g. '/foo/bar' - found = found.root(); - ++path_; - } - - const char_t* path_segment = path_; - - while (*path_segment == delimiter) ++path_segment; - - const char_t* path_segment_end = path_segment; - - while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; - - if (path_segment == path_segment_end) return found; - - const char_t* next_segment = path_segment_end; - - while (*next_segment == delimiter) ++next_segment; - - if (*path_segment == '.' && path_segment + 1 == path_segment_end) - return found.first_element_by_path(next_segment, delimiter); - else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) - return found.parent().first_element_by_path(next_segment, delimiter); - else - { - for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) - { - if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) - { - xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); - - if (subsearch) return subsearch; - } - } - - return xml_node(); - } - } - - PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) - { - walker._depth = -1; - - xml_node arg_begin = *this; - if (!walker.begin(arg_begin)) return false; - - xml_node cur = first_child(); - - if (cur) - { - ++walker._depth; - - do - { - xml_node arg_for_each = cur; - if (!walker.for_each(arg_for_each)) - return false; - - if (cur.first_child()) - { - ++walker._depth; - cur = cur.first_child(); - } - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - // Borland C++ workaround - while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) - { - --walker._depth; - cur = cur.parent(); - } - - if (cur != *this) - cur = cur.next_sibling(); - } - } - while (cur && cur != *this); - } - - assert(walker._depth == -1); - - xml_node arg_end = *this; - return walker.end(arg_end); - } - - PUGI__FN size_t xml_node::hash_value() const - { - return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); - } - - PUGI__FN xml_node_struct* xml_node::internal_object() const - { - return _root; - } - - PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const - { - if (!_root) return; - - impl::xml_buffered_writer buffered_writer(writer, encoding); - - impl::node_output(buffered_writer, _root, indent, flags, depth); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const - { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding, depth); - } - - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const - { - xml_writer_stream writer(stream); - - print(writer, indent, flags, encoding_wchar, depth); - } -#endif - - PUGI__FN ptrdiff_t xml_node::offset_debug() const - { - if (!_root) return -1; - - impl::xml_document_struct& doc = impl::get_document(_root); - - // we can determine the offset reliably only if there is exactly once parse buffer - if (!doc.buffer || doc.extra_buffers) return -1; - - switch (type()) - { - case node_document: - return 0; - - case node_element: - case node_declaration: - case node_pi: - return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1; - - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; - - default: - return -1; - } - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_node& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) - { - } - - PUGI__FN xml_node_struct* xml_text::_data() const - { - if (!_root || impl::is_text_node(_root)) return _root; - - for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) - if (impl::is_text_node(node)) - return node; - - return 0; - } - - PUGI__FN xml_node_struct* xml_text::_data_new() - { - xml_node_struct* d = _data(); - if (d) return d; - - return xml_node(_root).append_child(node_pcdata).internal_object(); - } - - PUGI__FN xml_text::xml_text(): _root(0) - { - } - - PUGI__FN static void unspecified_bool_xml_text(xml_text***) - { - } - - PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const - { - return _data() ? unspecified_bool_xml_text : 0; - } - - PUGI__FN bool xml_text::operator!() const - { - return !_data(); - } - - PUGI__FN bool xml_text::empty() const - { - return _data() == 0; - } - - PUGI__FN const char_t* xml_text::get() const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? d->value : PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* xml_text::as_string(const char_t* def) const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? d->value : def; - } - - PUGI__FN int xml_text::as_int(int def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_int(d ? d->value : 0, def); - } - - PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_uint(d ? d->value : 0, def); - } - - PUGI__FN double xml_text::as_double(double def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_double(d ? d->value : 0, def); - } - - PUGI__FN float xml_text::as_float(float def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_float(d ? d->value : 0, def); - } - - PUGI__FN bool xml_text::as_bool(bool def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_bool(d ? d->value : 0, def); - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long xml_text::as_llong(long long def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_llong(d ? d->value : 0, def); - } - - PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const - { - xml_node_struct* d = _data(); - - return impl::get_value_ullong(d ? d->value : 0, def); - } -#endif - - PUGI__FN bool xml_text::set(const char_t* rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(int rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(unsigned int rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(float rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(double rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(bool rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN bool xml_text::set(long long rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } - - PUGI__FN bool xml_text::set(unsigned long long rhs) - { - xml_node_struct* dn = _data_new(); - - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; - } -#endif - - PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(int rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(double rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(float rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(bool rhs) - { - set(rhs); - return *this; - } - -#ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN xml_text& xml_text::operator=(long long rhs) - { - set(rhs); - return *this; - } - - PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs) - { - set(rhs); - return *this; - } -#endif - - PUGI__FN xml_node xml_text::data() const - { - return xml_node(_data()); - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xml_text& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN xml_node_iterator::xml_node_iterator() - { - } - - PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) - { - } - - PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) - { - } - - PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const - { - return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; - } - - PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const - { - return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; - } - - PUGI__FN xml_node& xml_node_iterator::operator*() const - { - assert(_wrap._root); - return _wrap; - } - - PUGI__FN xml_node* xml_node_iterator::operator->() const - { - assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround - } - - PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() - { - assert(_wrap._root); - _wrap._root = _wrap._root->next_sibling; - return *this; - } - - PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) - { - xml_node_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() - { - _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); - return *this; - } - - PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) - { - xml_node_iterator temp = *this; - --*this; - return temp; - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator() - { - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) - { - } - - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) - { - } - - PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const - { - return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; - } - - PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const - { - return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; - } - - PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const - { - assert(_wrap._attr); - return _wrap; - } - - PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const - { - assert(_wrap._attr); - return const_cast(&_wrap); // BCC32 workaround - } - - PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() - { - assert(_wrap._attr); - _wrap._attr = _wrap._attr->next_attribute; - return *this; - } - - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) - { - xml_attribute_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() - { - _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); - return *this; - } - - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) - { - xml_attribute_iterator temp = *this; - --*this; - return temp; - } - - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) - { - } - - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) - { - } - - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) - { - } - - PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const - { - return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; - } - - PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const - { - return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; - } - - PUGI__FN xml_node& xml_named_node_iterator::operator*() const - { - assert(_wrap._root); - return _wrap; - } - - PUGI__FN xml_node* xml_named_node_iterator::operator->() const - { - assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround - } - - PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() - { - assert(_wrap._root); - _wrap = _wrap.next_sibling(_name); - return *this; - } - - PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) - { - xml_named_node_iterator temp = *this; - ++*this; - return temp; - } - - PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--() - { - if (_wrap._root) - _wrap = _wrap.previous_sibling(_name); - else - { - _wrap = _parent.last_child(); - - if (!impl::strequal(_wrap.name(), _name)) - _wrap = _wrap.previous_sibling(_name); - } - - return *this; - } - - PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int) - { - xml_named_node_iterator temp = *this; - --*this; - return temp; - } - - PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) - { - } - - PUGI__FN xml_parse_result::operator bool() const - { - return status == status_ok; - } - - PUGI__FN const char* xml_parse_result::description() const - { - switch (status) - { - case status_ok: return "No error"; - - case status_file_not_found: return "File was not found"; - case status_io_error: return "Error reading from file/stream"; - case status_out_of_memory: return "Could not allocate memory"; - case status_internal_error: return "Internal error occurred"; - - case status_unrecognized_tag: return "Could not determine tag type"; - - case status_bad_pi: return "Error parsing document declaration/processing instruction"; - case status_bad_comment: return "Error parsing comment"; - case status_bad_cdata: return "Error parsing CDATA section"; - case status_bad_doctype: return "Error parsing document type declaration"; - case status_bad_pcdata: return "Error parsing PCDATA section"; - case status_bad_start_element: return "Error parsing start element tag"; - case status_bad_attribute: return "Error parsing element attribute"; - case status_bad_end_element: return "Error parsing end element tag"; - case status_end_element_mismatch: return "Start-end tags mismatch"; - - case status_append_invalid_root: return "Unable to append nodes: root is not an element or document"; - - case status_no_document_element: return "No document element found"; - - default: return "Unknown error"; - } - } - - PUGI__FN xml_document::xml_document(): _buffer(0) - { - create(); - } - - PUGI__FN xml_document::~xml_document() - { - destroy(); - } - - PUGI__FN void xml_document::reset() - { - destroy(); - create(); - } - - PUGI__FN void xml_document::reset(const xml_document& proto) - { - reset(); - - for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) - append_copy(cur); - } - - PUGI__FN void xml_document::create() - { - assert(!_root); - - // initialize sentinel page - PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) <= sizeof(_memory)); - - // align upwards to page boundary - void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); - - // prepare page structure - impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); - assert(page); - - page->busy_size = impl::xml_memory_page_size; - - // allocate new root - _root = new (reinterpret_cast(page) + sizeof(impl::xml_memory_page)) impl::xml_document_struct(page); - _root->prev_sibling_c = _root; - - // setup sentinel page - page->allocator = static_cast(_root); - - // verify the document allocation - assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); - } - - PUGI__FN void xml_document::destroy() - { - assert(_root); - - // destroy static storage - if (_buffer) - { - impl::xml_memory::deallocate(_buffer); - _buffer = 0; - } - - // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) - for (impl::xml_extra_buffer* extra = static_cast(_root)->extra_buffers; extra; extra = extra->next) - { - if (extra->buffer) impl::xml_memory::deallocate(extra->buffer); - } - - // destroy dynamic storage, leave sentinel page (it's in static memory) - impl::xml_memory_page* root_page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); - assert(root_page && !root_page->prev); - assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); - - for (impl::xml_memory_page* page = root_page->next; page; ) - { - impl::xml_memory_page* next = page->next; - - impl::xml_allocator::deallocate_page(page); - - page = next; - } - - _root = 0; - } - -#ifndef PUGIXML_NO_STL - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) - { - reset(); - - return impl::load_stream_impl(*this, stream, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) - { - reset(); - - return impl::load_stream_impl(*this, stream, options, encoding_wchar); - } -#endif - - PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) - { - // Force native encoding (skip autodetection) - #ifdef PUGIXML_WCHAR_MODE - xml_encoding encoding = encoding_wchar; - #else - xml_encoding encoding = encoding_utf8; - #endif - - return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) - { - return load_string(contents, options); - } - - PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) - { - reset(); - - FILE* file = fopen(path_, "rb"); - - return impl::load_file_impl(*this, file, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) - { - reset(); - - FILE* file = impl::open_file_wide(path_, L"rb"); - - return impl::load_file_impl(*this, file, options, encoding); - } - - PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - reset(); - - return impl::load_buffer_impl(static_cast(_root), _root, const_cast(contents), size, options, encoding, false, false, &_buffer); - } - - PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - reset(); - - return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, false, &_buffer); - } - - PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) - { - reset(); - - return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, true, &_buffer); - } - - PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - impl::xml_buffered_writer buffered_writer(writer, encoding); - - if ((flags & format_write_bom) && encoding != encoding_latin1) - { - // BOM always represents the codepoint U+FEFF, so just write it in native encoding - #ifdef PUGIXML_WCHAR_MODE - unsigned int bom = 0xfeff; - buffered_writer.write(static_cast(bom)); - #else - buffered_writer.write('\xef', '\xbb', '\xbf'); - #endif - } - - if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) - { - buffered_writer.write_string(PUGIXML_TEXT("'); - if (!(flags & format_raw)) buffered_writer.write('\n'); - } - - impl::node_output(buffered_writer, _root, indent, flags, 0); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding); - } - - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const - { - xml_writer_stream writer(stream); - - save(writer, indent, flags, encoding_wchar); - } -#endif - - PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb"); - return impl::save_file_impl(*this, file, indent, flags, encoding); - } - - PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const - { - FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"); - return impl::save_file_impl(*this, file, indent, flags, encoding); - } - - PUGI__FN xml_node xml_document::document_element() const - { - assert(_root); - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (PUGI__NODETYPE(i) == node_element) - return xml_node(i); - - return xml_node(); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) - { - assert(str); - - return impl::as_utf8_impl(str, impl::strlength_wide(str)); - } - - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) - { - return impl::as_utf8_impl(str.c_str(), str.size()); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) - { - assert(str); - - return impl::as_wide_impl(str, strlen(str)); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) - { - return impl::as_wide_impl(str.c_str(), str.size()); - } -#endif - - PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) - { - impl::xml_memory::allocate = allocate; - impl::xml_memory::deallocate = deallocate; - } - - PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() - { - return impl::xml_memory::allocate; - } - - PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() - { - return impl::xml_memory::deallocate; - } -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) - { - return std::bidirectional_iterator_tag(); - } - - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) - { - return std::bidirectional_iterator_tag(); - } -} -#endif - -#ifndef PUGIXML_NO_XPATH -// STL replacements -PUGI__NS_BEGIN - struct equal_to - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs == rhs; - } - }; - - struct not_equal_to - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs != rhs; - } - }; - - struct less - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs < rhs; - } - }; - - struct less_equal - { - template bool operator()(const T& lhs, const T& rhs) const - { - return lhs <= rhs; - } - }; - - template void swap(T& lhs, T& rhs) - { - T temp = lhs; - lhs = rhs; - rhs = temp; - } - - template I min_element(I begin, I end, const Pred& pred) - { - I result = begin; - - for (I it = begin + 1; it != end; ++it) - if (pred(*it, *result)) - result = it; - - return result; - } - - template void reverse(I begin, I end) - { - while (end - begin > 1) swap(*begin++, *--end); - } - - template I unique(I begin, I end) - { - // fast skip head - while (end - begin > 1 && *begin != *(begin + 1)) begin++; - - if (begin == end) return begin; - - // last written element - I write = begin++; - - // merge unique elements - while (begin != end) - { - if (*begin != *write) - *++write = *begin++; - else - begin++; - } - - // past-the-end (write points to live element) - return write + 1; - } - - template void copy_backwards(I begin, I end, I target) - { - while (begin != end) *--target = *--end; - } - - template void insertion_sort(I begin, I end, const Pred& pred, T*) - { - assert(begin != end); - - for (I it = begin + 1; it != end; ++it) - { - T val = *it; - - if (pred(val, *begin)) - { - // move to front - copy_backwards(begin, it, it + 1); - *begin = val; - } - else - { - I hole = it; - - // move hole backwards - while (pred(val, *(hole - 1))) - { - *hole = *(hole - 1); - hole--; - } - - // fill hole with element - *hole = val; - } - } - } - - // std variant for elements with == - template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) - { - I eqbeg = middle, eqend = middle + 1; - - // expand equal range - while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; - while (eqend != end && *eqend == *eqbeg) ++eqend; - - // process outer elements - I ltend = eqbeg, gtbeg = eqend; - - for (;;) - { - // find the element from the right side that belongs to the left one - for (; gtbeg != end; ++gtbeg) - if (!pred(*eqbeg, *gtbeg)) - { - if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); - else break; - } - - // find the element from the left side that belongs to the right one - for (; ltend != begin; --ltend) - if (!pred(*(ltend - 1), *eqbeg)) - { - if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); - else break; - } - - // scanned all elements - if (gtbeg == end && ltend == begin) - { - *out_eqbeg = eqbeg; - *out_eqend = eqend; - return; - } - - // make room for elements by moving equal area - if (gtbeg == end) - { - if (--ltend != --eqbeg) swap(*ltend, *eqbeg); - swap(*eqbeg, *--eqend); - } - else if (ltend == begin) - { - if (eqend != gtbeg) swap(*eqbeg, *eqend); - ++eqend; - swap(*gtbeg++, *eqbeg++); - } - else swap(*gtbeg++, *--ltend); - } - } - - template void median3(I first, I middle, I last, const Pred& pred) - { - if (pred(*middle, *first)) swap(*middle, *first); - if (pred(*last, *middle)) swap(*last, *middle); - if (pred(*middle, *first)) swap(*middle, *first); - } - - template void median(I first, I middle, I last, const Pred& pred) - { - if (last - first <= 40) - { - // median of three for small chunks - median3(first, middle, last, pred); - } - else - { - // median of nine - size_t step = (last - first + 1) / 8; - - median3(first, first + step, first + 2 * step, pred); - median3(middle - step, middle, middle + step, pred); - median3(last - 2 * step, last - step, last, pred); - median3(first + step, middle, last - step, pred); - } - } - - template void sort(I begin, I end, const Pred& pred) - { - // sort large chunks - while (end - begin > 32) - { - // find median element - I middle = begin + (end - begin) / 2; - median(begin, middle, end - 1, pred); - - // partition in three chunks (< = >) - I eqbeg, eqend; - partition(begin, middle, end, pred, &eqbeg, &eqend); - - // loop on larger half - if (eqbeg - begin > end - eqend) - { - sort(eqend, end, pred); - end = eqbeg; - } - else - { - sort(begin, eqbeg, pred); - begin = eqend; - } - } - - // insertion sort small chunk - if (begin != end) insertion_sort(begin, end, pred, &*begin); - } -PUGI__NS_END - -// Allocator used for AST and evaluation stacks -PUGI__NS_BEGIN - struct xpath_memory_block - { - xpath_memory_block* next; - size_t capacity; - - char data[ - #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE - PUGIXML_MEMORY_XPATH_PAGE_SIZE - #else - 4096 - #endif - ]; - }; - - class xpath_allocator - { - xpath_memory_block* _root; - size_t _root_size; - - public: - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf* error_handler; - #endif - - xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) - { - #ifdef PUGIXML_NO_EXCEPTIONS - error_handler = 0; - #endif - } - - void* allocate_nothrow(size_t size) - { - // align size so that we're able to store pointers in subsequent blocks - size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - if (_root_size + size <= _root->capacity) - { - void* buf = _root->data + _root_size; - _root_size += size; - return buf; - } - else - { - // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests - size_t block_capacity_base = sizeof(_root->data); - size_t block_capacity_req = size + block_capacity_base / 4; - size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req; - - size_t block_size = block_capacity + offsetof(xpath_memory_block, data); - - xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); - if (!block) return 0; - - block->next = _root; - block->capacity = block_capacity; - - _root = block; - _root_size = size; - - return block->data; - } - } - - void* allocate(size_t size) - { - void* result = allocate_nothrow(size); - - if (!result) - { - #ifdef PUGIXML_NO_EXCEPTIONS - assert(error_handler); - longjmp(*error_handler, 1); - #else - throw std::bad_alloc(); - #endif - } - - return result; - } - - void* reallocate(void* ptr, size_t old_size, size_t new_size) - { - // align size so that we're able to store pointers in subsequent blocks - old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - - // we can only reallocate the last object - assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); - - // adjust root size so that we have not allocated the object at all - bool only_object = (_root_size == old_size); - - if (ptr) _root_size -= old_size; - - // allocate a new version (this will obviously reuse the memory if possible) - void* result = allocate(new_size); - assert(result); - - // we have a new block - if (result != ptr && ptr) - { - // copy old data - assert(new_size >= old_size); - memcpy(result, ptr, old_size); - - // free the previous page if it had no other objects - if (only_object) - { - assert(_root->data == result); - assert(_root->next); - - xpath_memory_block* next = _root->next->next; - - if (next) - { - // deallocate the whole page, unless it was the first one - xml_memory::deallocate(_root->next); - _root->next = next; - } - } - } - - return result; - } - - void revert(const xpath_allocator& state) - { - // free all new pages - xpath_memory_block* cur = _root; - - while (cur != state._root) - { - xpath_memory_block* next = cur->next; - - xml_memory::deallocate(cur); - - cur = next; - } - - // restore state - _root = state._root; - _root_size = state._root_size; - } - - void release() - { - xpath_memory_block* cur = _root; - assert(cur); - - while (cur->next) - { - xpath_memory_block* next = cur->next; - - xml_memory::deallocate(cur); - - cur = next; - } - } - }; - - struct xpath_allocator_capture - { - xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) - { - } - - ~xpath_allocator_capture() - { - _target->revert(_state); - } - - xpath_allocator* _target; - xpath_allocator _state; - }; - - struct xpath_stack - { - xpath_allocator* result; - xpath_allocator* temp; - }; - - struct xpath_stack_data - { - xpath_memory_block blocks[2]; - xpath_allocator result; - xpath_allocator temp; - xpath_stack stack; - - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf error_handler; - #endif - - xpath_stack_data(): result(blocks + 0), temp(blocks + 1) - { - blocks[0].next = blocks[1].next = 0; - blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); - - stack.result = &result; - stack.temp = &temp; - - #ifdef PUGIXML_NO_EXCEPTIONS - result.error_handler = temp.error_handler = &error_handler; - #endif - } - - ~xpath_stack_data() - { - result.release(); - temp.release(); - } - }; -PUGI__NS_END - -// String class -PUGI__NS_BEGIN - class xpath_string - { - const char_t* _buffer; - bool _uses_heap; - size_t _length_heap; - - static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) - { - char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); - assert(result); - - memcpy(result, string, length * sizeof(char_t)); - result[length] = 0; - - return result; - } - - xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) - { - } - - public: - static xpath_string from_const(const char_t* str) - { - return xpath_string(str, false, 0); - } - - static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) - { - assert(begin <= end && *end == 0); - - return xpath_string(begin, true, static_cast(end - begin)); - } - - static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc) - { - assert(begin <= end); - - size_t length = static_cast(end - begin); - - return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length); - } - - xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) - { - } - - void append(const xpath_string& o, xpath_allocator* alloc) - { - // skip empty sources - if (!*o._buffer) return; - - // fast append for constant empty target and constant source - if (!*_buffer && !_uses_heap && !o._uses_heap) - { - _buffer = o._buffer; - } - else - { - // need to make heap copy - size_t target_length = length(); - size_t source_length = o.length(); - size_t result_length = target_length + source_length; - - // allocate new buffer - char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); - assert(result); - - // append first string to the new buffer in case there was no reallocation - if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); - - // append second string to the new buffer - memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); - result[result_length] = 0; - - // finalize - _buffer = result; - _uses_heap = true; - _length_heap = result_length; - } - } - - const char_t* c_str() const - { - return _buffer; - } - - size_t length() const - { - return _uses_heap ? _length_heap : strlength(_buffer); - } - - char_t* data(xpath_allocator* alloc) - { - // make private heap copy - if (!_uses_heap) - { - size_t length_ = strlength(_buffer); - - _buffer = duplicate_string(_buffer, length_, alloc); - _uses_heap = true; - _length_heap = length_; - } - - return const_cast(_buffer); - } - - bool empty() const - { - return *_buffer == 0; - } - - bool operator==(const xpath_string& o) const - { - return strequal(_buffer, o._buffer); - } - - bool operator!=(const xpath_string& o) const - { - return !strequal(_buffer, o._buffer); - } - - bool uses_heap() const - { - return _uses_heap; - } - }; -PUGI__NS_END - -PUGI__NS_BEGIN - PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) - { - while (*pattern && *string == *pattern) - { - string++; - pattern++; - } - - return *pattern == 0; - } - - PUGI__FN const char_t* find_char(const char_t* s, char_t c) - { - #ifdef PUGIXML_WCHAR_MODE - return wcschr(s, c); - #else - return strchr(s, c); - #endif - } - - PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) - { - #ifdef PUGIXML_WCHAR_MODE - // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) - return (*p == 0) ? s : wcsstr(s, p); - #else - return strstr(s, p); - #endif - } - - // Converts symbol to lower case, if it is an ASCII one - PUGI__FN char_t tolower_ascii(char_t ch) - { - return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; - } - - PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) - { - if (na.attribute()) - return xpath_string::from_const(na.attribute().value()); - else - { - xml_node n = na.node(); - - switch (n.type()) - { - case node_pcdata: - case node_cdata: - case node_comment: - case node_pi: - return xpath_string::from_const(n.value()); - - case node_document: - case node_element: - { - xpath_string result; - - xml_node cur = n.first_child(); - - while (cur && cur != n) - { - if (cur.type() == node_pcdata || cur.type() == node_cdata) - result.append(xpath_string::from_const(cur.value()), alloc); - - if (cur.first_child()) - cur = cur.first_child(); - else if (cur.next_sibling()) - cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur != n) - cur = cur.parent(); - - if (cur != n) cur = cur.next_sibling(); - } - } - - return result; - } - - default: - return xpath_string(); - } - } - } - - PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) - { - assert(ln->parent == rn->parent); - - // there is no common ancestor (the shared parent is null), nodes are from different documents - if (!ln->parent) return ln < rn; - - // determine sibling order - xml_node_struct* ls = ln; - xml_node_struct* rs = rn; - - while (ls && rs) - { - if (ls == rn) return true; - if (rs == ln) return false; - - ls = ls->next_sibling; - rs = rs->next_sibling; - } - - // if rn sibling chain ended ln must be before rn - return !rs; - } - - PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) - { - // find common ancestor at the same depth, if any - xml_node_struct* lp = ln; - xml_node_struct* rp = rn; - - while (lp && rp && lp->parent != rp->parent) - { - lp = lp->parent; - rp = rp->parent; - } - - // parents are the same! - if (lp && rp) return node_is_before_sibling(lp, rp); - - // nodes are at different depths, need to normalize heights - bool left_higher = !lp; - - while (lp) - { - lp = lp->parent; - ln = ln->parent; - } - - while (rp) - { - rp = rp->parent; - rn = rn->parent; - } - - // one node is the ancestor of the other - if (ln == rn) return left_higher; - - // find common ancestor... again - while (ln->parent != rn->parent) - { - ln = ln->parent; - rn = rn->parent; - } - - return node_is_before_sibling(ln, rn); - } - - PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) - { - while (node && node != parent) node = node->parent; - - return parent && node == parent; - } - - PUGI__FN const void* document_buffer_order(const xpath_node& xnode) - { - xml_node_struct* node = xnode.node().internal_object(); - - if (node) - { - if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0) - { - if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name; - if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; - } - - return 0; - } - - xml_attribute_struct* attr = xnode.attribute().internal_object(); - - if (attr) - { - if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0) - { - if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name; - if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; - } - - return 0; - } - - return 0; - } - - struct document_order_comparator - { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const - { - // optimized document order based check - const void* lo = document_buffer_order(lhs); - const void* ro = document_buffer_order(rhs); - - if (lo && ro) return lo < ro; - - // slow comparison - xml_node ln = lhs.node(), rn = rhs.node(); - - // compare attributes - if (lhs.attribute() && rhs.attribute()) - { - // shared parent - if (lhs.parent() == rhs.parent()) - { - // determine sibling order - for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) - if (a == rhs.attribute()) - return true; - - return false; - } - - // compare attribute parents - ln = lhs.parent(); - rn = rhs.parent(); - } - else if (lhs.attribute()) - { - // attributes go after the parent element - if (lhs.parent() == rhs.node()) return false; - - ln = lhs.parent(); - } - else if (rhs.attribute()) - { - // attributes go after the parent element - if (rhs.parent() == lhs.node()) return true; - - rn = rhs.parent(); - } - - if (ln == rn) return false; - - if (!ln || !rn) return ln < rn; - - return node_is_before(ln.internal_object(), rn.internal_object()); - } - }; - - struct duplicate_comparator - { - bool operator()(const xpath_node& lhs, const xpath_node& rhs) const - { - if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; - else return rhs.attribute() ? false : lhs.node() < rhs.node(); - } - }; - - PUGI__FN double gen_nan() - { - #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; - u[0].i = 0x7fc00000; - return u[0].f; - #else - // fallback - const volatile double zero = 0.0; - return zero / zero; - #endif - } - - PUGI__FN bool is_nan(double value) - { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) - return !!_isnan(value); - #elif defined(fpclassify) && defined(FP_NAN) - return fpclassify(value) == FP_NAN; - #else - // fallback - const volatile double v = value; - return v != v; - #endif - } - - PUGI__FN const char_t* convert_number_to_string_special(double value) - { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) - if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; - if (_isnan(value)) return PUGIXML_TEXT("NaN"); - return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) - switch (fpclassify(value)) - { - case FP_NAN: - return PUGIXML_TEXT("NaN"); - - case FP_INFINITE: - return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - - case FP_ZERO: - return PUGIXML_TEXT("0"); - - default: - return 0; - } - #else - // fallback - const volatile double v = value; - - if (v == 0) return PUGIXML_TEXT("0"); - if (v != v) return PUGIXML_TEXT("NaN"); - if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - return 0; - #endif - } - - PUGI__FN bool convert_number_to_boolean(double value) - { - return (value != 0 && !is_nan(value)); - } - - PUGI__FN void truncate_zeros(char* begin, char* end) - { - while (begin != end && end[-1] == '0') end--; - - *end = 0; - } - - // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent -#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) - { - // get base values - int sign, exponent; - _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); - - // truncate redundant zeros - truncate_zeros(buffer, buffer + strlen(buffer)); - - // fill results - *out_mantissa = buffer; - *out_exponent = exponent; - } -#else - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) - { - // get a scientific notation value with IEEE DBL_DIG decimals - sprintf(buffer, "%.*e", DBL_DIG, value); - assert(strlen(buffer) < buffer_size); - (void)!buffer_size; - - // get the exponent (possibly negative) - char* exponent_string = strchr(buffer, 'e'); - assert(exponent_string); - - int exponent = atoi(exponent_string + 1); - - // extract mantissa string: skip sign - char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; - assert(mantissa[0] != '0' && mantissa[1] == '.'); - - // divide mantissa by 10 to eliminate integer part - mantissa[1] = mantissa[0]; - mantissa++; - exponent++; - - // remove extra mantissa digits and zero-terminate mantissa - truncate_zeros(mantissa, exponent_string); - - // fill results - *out_mantissa = mantissa; - *out_exponent = exponent; - } -#endif - - PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) - { - // try special number conversion - const char_t* special = convert_number_to_string_special(value); - if (special) return xpath_string::from_const(special); - - // get mantissa + exponent form - char mantissa_buffer[32]; - - char* mantissa; - int exponent; - convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); - - // allocate a buffer of suitable length for the number - size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; - char_t* result = static_cast(alloc->allocate(sizeof(char_t) * result_size)); - assert(result); - - // make the number! - char_t* s = result; - - // sign - if (value < 0) *s++ = '-'; - - // integer part - if (exponent <= 0) - { - *s++ = '0'; - } - else - { - while (exponent > 0) - { - assert(*mantissa == 0 || static_cast(static_cast(*mantissa) - '0') <= 9); - *s++ = *mantissa ? *mantissa++ : '0'; - exponent--; - } - } - - // fractional part - if (*mantissa) - { - // decimal point - *s++ = '.'; - - // extra zeroes from negative exponent - while (exponent < 0) - { - *s++ = '0'; - exponent++; - } - - // extra mantissa digits - while (*mantissa) - { - assert(static_cast(*mantissa - '0') <= 9); - *s++ = *mantissa++; - } - } - - // zero-terminate - assert(s < result + result_size); - *s = 0; - - return xpath_string::from_heap_preallocated(result, s); - } - - PUGI__FN bool check_string_to_number_format(const char_t* string) - { - // parse leading whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; - - // parse sign - if (*string == '-') ++string; - - if (!*string) return false; - - // if there is no integer part, there should be a decimal part with at least one digit - if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; - - // parse integer part - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; - - // parse decimal part - if (*string == '.') - { - ++string; - - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; - } - - // parse trailing whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; - - return *string == 0; - } - - PUGI__FN double convert_string_to_number(const char_t* string) - { - // check string format - if (!check_string_to_number_format(string)) return gen_nan(); - - // parse string - #ifdef PUGIXML_WCHAR_MODE - return wcstod(string, 0); - #else - return atof(string); - #endif - } - - PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) - { - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) - { - // need to make dummy on-heap copy - scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!scratch) return false; - } - - // copy string to zero-terminated buffer and perform conversion - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - *out_result = convert_string_to_number(scratch); - - // free dummy buffer - if (scratch != buffer) xml_memory::deallocate(scratch); - - return true; - } - - PUGI__FN double round_nearest(double value) - { - return floor(value + 0.5); - } - - PUGI__FN double round_nearest_nzero(double value) - { - // same as round_nearest, but returns -0 for [-0.5, -0] - // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) - return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); - } - - PUGI__FN const char_t* qualified_name(const xpath_node& node) - { - return node.attribute() ? node.attribute().name() : node.node().name(); - } - - PUGI__FN const char_t* local_name(const xpath_node& node) - { - const char_t* name = qualified_name(node); - const char_t* p = find_char(name, ':'); - - return p ? p + 1 : name; - } - - struct namespace_uri_predicate - { - const char_t* prefix; - size_t prefix_length; - - namespace_uri_predicate(const char_t* name) - { - const char_t* pos = find_char(name, ':'); - - prefix = pos ? name : 0; - prefix_length = pos ? static_cast(pos - name) : 0; - } - - bool operator()(xml_attribute a) const - { - const char_t* name = a.name(); - - if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; - - return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; - } - }; - - PUGI__FN const char_t* namespace_uri(xml_node node) - { - namespace_uri_predicate pred = node.name(); - - xml_node p = node; - - while (p) - { - xml_attribute a = p.find_attribute(pred); - - if (a) return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) - { - namespace_uri_predicate pred = attr.name(); - - // Default namespace does not apply to attributes - if (!pred.prefix) return PUGIXML_TEXT(""); - - xml_node p = parent; - - while (p) - { - xml_attribute a = p.find_attribute(pred); - - if (a) return a.value(); - - p = p.parent(); - } - - return PUGIXML_TEXT(""); - } - - PUGI__FN const char_t* namespace_uri(const xpath_node& node) - { - return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); - } - - PUGI__FN char_t* normalize_space(char_t* buffer) - { - char_t* write = buffer; - - for (char_t* it = buffer; *it; ) - { - char_t ch = *it++; - - if (PUGI__IS_CHARTYPE(ch, ct_space)) - { - // replace whitespace sequence with single space - while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; - - // avoid leading spaces - if (write != buffer) *write++ = ' '; - } - else *write++ = ch; - } - - // remove trailing space - if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; - - // zero-terminate - *write = 0; - - return write; - } - - PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) - { - char_t* write = buffer; - - while (*buffer) - { - PUGI__DMC_VOLATILE char_t ch = *buffer++; - - const char_t* pos = find_char(from, ch); - - if (!pos) - *write++ = ch; // do not process - else if (static_cast(pos - from) < to_length) - *write++ = to[pos - from]; // replace - } - - // zero-terminate - *write = 0; - - return write; - } - - PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) - { - unsigned char table[128] = {0}; - - while (*from) - { - unsigned int fc = static_cast(*from); - unsigned int tc = static_cast(*to); - - if (fc >= 128 || tc >= 128) - return 0; - - // code=128 means "skip character" - if (!table[fc]) - table[fc] = static_cast(tc ? tc : 128); - - from++; - if (tc) to++; - } - - for (int i = 0; i < 128; ++i) - if (!table[i]) - table[i] = static_cast(i); - - void* result = alloc->allocate_nothrow(sizeof(table)); - - if (result) - { - memcpy(result, table, sizeof(table)); - } - - return static_cast(result); - } - - PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table) - { - char_t* write = buffer; - - while (*buffer) - { - char_t ch = *buffer++; - unsigned int index = static_cast(ch); - - if (index < 128) - { - unsigned char code = table[index]; - - // code=128 means "skip character" (table size is 128 so 128 can be a special value) - // this code skips these characters without extra branches - *write = static_cast(code); - write += 1 - (code >> 7); - } - else - { - *write++ = ch; - } - } - - // zero-terminate - *write = 0; - - return write; - } - - inline bool is_xpath_attribute(const char_t* name) - { - return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')); - } - - struct xpath_variable_boolean: xpath_variable - { - xpath_variable_boolean(): value(false) - { - } - - bool value; - char_t name[1]; - }; - - struct xpath_variable_number: xpath_variable - { - xpath_variable_number(): value(0) - { - } - - double value; - char_t name[1]; - }; - - struct xpath_variable_string: xpath_variable - { - xpath_variable_string(): value(0) - { - } - - ~xpath_variable_string() - { - if (value) xml_memory::deallocate(value); - } - - char_t* value; - char_t name[1]; - }; - - struct xpath_variable_node_set: xpath_variable - { - xpath_node_set value; - char_t name[1]; - }; - - static const xpath_node_set dummy_node_set; - - PUGI__FN unsigned int hash_string(const char_t* str) - { - // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) - unsigned int result = 0; - - while (*str) - { - result += static_cast(*str++); - result += result << 10; - result ^= result >> 6; - } - - result += result << 3; - result ^= result >> 11; - result += result << 15; - - return result; - } - - template PUGI__FN T* new_xpath_variable(const char_t* name) - { - size_t length = strlength(name); - if (length == 0) return 0; // empty variable names are invalid - - // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters - void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); - if (!memory) return 0; - - T* result = new (memory) T(); - - memcpy(result->name, name, (length + 1) * sizeof(char_t)); - - return result; - } - - PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) - { - switch (type) - { - case xpath_type_node_set: - return new_xpath_variable(name); - - case xpath_type_number: - return new_xpath_variable(name); - - case xpath_type_string: - return new_xpath_variable(name); - - case xpath_type_boolean: - return new_xpath_variable(name); - - default: - return 0; - } - } - - template PUGI__FN void delete_xpath_variable(T* var) - { - var->~T(); - xml_memory::deallocate(var); - } - - PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) - { - switch (type) - { - case xpath_type_node_set: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_number: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_string: - delete_xpath_variable(static_cast(var)); - break; - - case xpath_type_boolean: - delete_xpath_variable(static_cast(var)); - break; - - default: - assert(!"Invalid variable type"); - } - } - - PUGI__FN xpath_variable* get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end) - { - size_t length = static_cast(end - begin); - char_t* scratch = buffer; - - if (length >= sizeof(buffer) / sizeof(buffer[0])) - { - // need to make dummy on-heap copy - scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!scratch) return 0; - } - - // copy string to zero-terminated buffer and perform lookup - memcpy(scratch, begin, length * sizeof(char_t)); - scratch[length] = 0; - - xpath_variable* result = set->get(scratch); - - // free dummy buffer - if (scratch != buffer) xml_memory::deallocate(scratch); - - return result; - } -PUGI__NS_END - -// Internal node set class -PUGI__NS_BEGIN - PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) - { - if (end - begin < 2) - return xpath_node_set::type_sorted; - - document_order_comparator cmp; - - bool first = cmp(begin[0], begin[1]); - - for (const xpath_node* it = begin + 1; it + 1 < end; ++it) - if (cmp(it[0], it[1]) != first) - return xpath_node_set::type_unsorted; - - return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; - } - - PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) - { - xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; - - if (type == xpath_node_set::type_unsorted) - { - xpath_node_set::type_t sorted = xpath_get_order(begin, end); - - if (sorted == xpath_node_set::type_unsorted) - { - sort(begin, end, document_order_comparator()); - - type = xpath_node_set::type_sorted; - } - else - type = sorted; - } - - if (type != order) reverse(begin, end); - - return order; - } - - PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) - { - if (begin == end) return xpath_node(); - - switch (type) - { - case xpath_node_set::type_sorted: - return *begin; - - case xpath_node_set::type_sorted_reverse: - return *(end - 1); - - case xpath_node_set::type_unsorted: - return *min_element(begin, end, document_order_comparator()); - - default: - assert(!"Invalid node set type"); - return xpath_node(); - } - } - - class xpath_node_set_raw - { - xpath_node_set::type_t _type; - - xpath_node* _begin; - xpath_node* _end; - xpath_node* _eos; - - public: - xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) - { - } - - xpath_node* begin() const - { - return _begin; - } - - xpath_node* end() const - { - return _end; - } - - bool empty() const - { - return _begin == _end; - } - - size_t size() const - { - return static_cast(_end - _begin); - } - - xpath_node first() const - { - return xpath_first(_begin, _end, _type); - } - - void push_back_grow(const xpath_node& node, xpath_allocator* alloc); - - void push_back(const xpath_node& node, xpath_allocator* alloc) - { - if (_end != _eos) - *_end++ = node; - else - push_back_grow(node, alloc); - } - - void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) - { - if (begin_ == end_) return; - - size_t size_ = static_cast(_end - _begin); - size_t capacity = static_cast(_eos - _begin); - size_t count = static_cast(end_ - begin_); - - if (size_ + count > capacity) - { - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + size_; - _eos = data + size_ + count; - } - - memcpy(_end, begin_, count * sizeof(xpath_node)); - _end += count; - } - - void sort_do() - { - _type = xpath_sort(_begin, _end, _type, false); - } - - void truncate(xpath_node* pos) - { - assert(_begin <= pos && pos <= _end); - - _end = pos; - } - - void remove_duplicates() - { - if (_type == xpath_node_set::type_unsorted) - sort(_begin, _end, duplicate_comparator()); - - _end = unique(_begin, _end); - } - - xpath_node_set::type_t type() const - { - return _type; - } - - void set_type(xpath_node_set::type_t value) - { - _type = value; - } - }; - - PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) - { - size_t capacity = static_cast(_eos - _begin); - - // get new capacity (1.5x rule) - size_t new_capacity = capacity + capacity / 2 + 1; - - // reallocate the old array or allocate a new one - xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); - assert(data); - - // finalize - _begin = data; - _end = data + capacity; - _eos = data + new_capacity; - - // push - *_end++ = node; - } -PUGI__NS_END - -PUGI__NS_BEGIN - struct xpath_context - { - xpath_node n; - size_t position, size; - - xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) - { - } - }; - - enum lexeme_t - { - lex_none = 0, - lex_equal, - lex_not_equal, - lex_less, - lex_greater, - lex_less_or_equal, - lex_greater_or_equal, - lex_plus, - lex_minus, - lex_multiply, - lex_union, - lex_var_ref, - lex_open_brace, - lex_close_brace, - lex_quoted_string, - lex_number, - lex_slash, - lex_double_slash, - lex_open_square_brace, - lex_close_square_brace, - lex_string, - lex_comma, - lex_axis_attribute, - lex_dot, - lex_double_dot, - lex_double_colon, - lex_eof - }; - - struct xpath_lexer_string - { - const char_t* begin; - const char_t* end; - - xpath_lexer_string(): begin(0), end(0) - { - } - - bool operator==(const char_t* other) const - { - size_t length = static_cast(end - begin); - - return strequalrange(other, begin, length); - } - }; - - class xpath_lexer - { - const char_t* _cur; - const char_t* _cur_lexeme_pos; - xpath_lexer_string _cur_lexeme_contents; - - lexeme_t _cur_lexeme; - - public: - explicit xpath_lexer(const char_t* query): _cur(query) - { - next(); - } - - const char_t* state() const - { - return _cur; - } - - void next() - { - const char_t* cur = _cur; - - while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; - - // save lexeme position for error reporting - _cur_lexeme_pos = cur; - - switch (*cur) - { - case 0: - _cur_lexeme = lex_eof; - break; - - case '>': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_greater_or_equal; - } - else - { - cur += 1; - _cur_lexeme = lex_greater; - } - break; - - case '<': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_less_or_equal; - } - else - { - cur += 1; - _cur_lexeme = lex_less; - } - break; - - case '!': - if (*(cur+1) == '=') - { - cur += 2; - _cur_lexeme = lex_not_equal; - } - else - { - _cur_lexeme = lex_none; - } - break; - - case '=': - cur += 1; - _cur_lexeme = lex_equal; - - break; - - case '+': - cur += 1; - _cur_lexeme = lex_plus; - - break; - - case '-': - cur += 1; - _cur_lexeme = lex_minus; - - break; - - case '*': - cur += 1; - _cur_lexeme = lex_multiply; - - break; - - case '|': - cur += 1; - _cur_lexeme = lex_union; - - break; - - case '$': - cur += 1; - - if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - - if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname - { - cur++; // : - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_var_ref; - } - else - { - _cur_lexeme = lex_none; - } - - break; - - case '(': - cur += 1; - _cur_lexeme = lex_open_brace; - - break; - - case ')': - cur += 1; - _cur_lexeme = lex_close_brace; - - break; - - case '[': - cur += 1; - _cur_lexeme = lex_open_square_brace; - - break; - - case ']': - cur += 1; - _cur_lexeme = lex_close_square_brace; - - break; - - case ',': - cur += 1; - _cur_lexeme = lex_comma; - - break; - - case '/': - if (*(cur+1) == '/') - { - cur += 2; - _cur_lexeme = lex_double_slash; - } - else - { - cur += 1; - _cur_lexeme = lex_slash; - } - break; - - case '.': - if (*(cur+1) == '.') - { - cur += 2; - _cur_lexeme = lex_double_dot; - } - else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) - { - _cur_lexeme_contents.begin = cur; // . - - ++cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } - else - { - cur += 1; - _cur_lexeme = lex_dot; - } - break; - - case '@': - cur += 1; - _cur_lexeme = lex_axis_attribute; - - break; - - case '"': - case '\'': - { - char_t terminator = *cur; - - ++cur; - - _cur_lexeme_contents.begin = cur; - while (*cur && *cur != terminator) cur++; - _cur_lexeme_contents.end = cur; - - if (!*cur) - _cur_lexeme = lex_none; - else - { - cur += 1; - _cur_lexeme = lex_quoted_string; - } - - break; - } - - case ':': - if (*(cur+1) == ':') - { - cur += 2; - _cur_lexeme = lex_double_colon; - } - else - { - _cur_lexeme = lex_none; - } - break; - - default: - if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - - if (*cur == '.') - { - cur++; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_number; - } - else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) - { - _cur_lexeme_contents.begin = cur; - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - - if (cur[0] == ':') - { - if (cur[1] == '*') // namespace test ncname:* - { - cur += 2; // :* - } - else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname - { - cur++; // : - - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - } - } - - _cur_lexeme_contents.end = cur; - - _cur_lexeme = lex_string; - } - else - { - _cur_lexeme = lex_none; - } - } - - _cur = cur; - } - - lexeme_t current() const - { - return _cur_lexeme; - } - - const char_t* current_pos() const - { - return _cur_lexeme_pos; - } - - const xpath_lexer_string& contents() const - { - assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); - - return _cur_lexeme_contents; - } - }; - - enum ast_type_t - { - ast_unknown, - ast_op_or, // left or right - ast_op_and, // left and right - ast_op_equal, // left = right - ast_op_not_equal, // left != right - ast_op_less, // left < right - ast_op_greater, // left > right - ast_op_less_or_equal, // left <= right - ast_op_greater_or_equal, // left >= right - ast_op_add, // left + right - ast_op_subtract, // left - right - ast_op_multiply, // left * right - ast_op_divide, // left / right - ast_op_mod, // left % right - ast_op_negate, // left - right - ast_op_union, // left | right - ast_predicate, // apply predicate to set; next points to next predicate - ast_filter, // select * from left where right - ast_string_constant, // string constant - ast_number_constant, // number constant - ast_variable, // variable - ast_func_last, // last() - ast_func_position, // position() - ast_func_count, // count(left) - ast_func_id, // id(left) - ast_func_local_name_0, // local-name() - ast_func_local_name_1, // local-name(left) - ast_func_namespace_uri_0, // namespace-uri() - ast_func_namespace_uri_1, // namespace-uri(left) - ast_func_name_0, // name() - ast_func_name_1, // name(left) - ast_func_string_0, // string() - ast_func_string_1, // string(left) - ast_func_concat, // concat(left, right, siblings) - ast_func_starts_with, // starts_with(left, right) - ast_func_contains, // contains(left, right) - ast_func_substring_before, // substring-before(left, right) - ast_func_substring_after, // substring-after(left, right) - ast_func_substring_2, // substring(left, right) - ast_func_substring_3, // substring(left, right, third) - ast_func_string_length_0, // string-length() - ast_func_string_length_1, // string-length(left) - ast_func_normalize_space_0, // normalize-space() - ast_func_normalize_space_1, // normalize-space(left) - ast_func_translate, // translate(left, right, third) - ast_func_boolean, // boolean(left) - ast_func_not, // not(left) - ast_func_true, // true() - ast_func_false, // false() - ast_func_lang, // lang(left) - ast_func_number_0, // number() - ast_func_number_1, // number(left) - ast_func_sum, // sum(left) - ast_func_floor, // floor(left) - ast_func_ceiling, // ceiling(left) - ast_func_round, // round(left) - ast_step, // process set left with step - ast_step_root, // select root node - - ast_opt_translate_table, // translate(left, right, third) where right/third are constants - ast_opt_compare_attribute // @name = 'string' - }; - - enum axis_t - { - axis_ancestor, - axis_ancestor_or_self, - axis_attribute, - axis_child, - axis_descendant, - axis_descendant_or_self, - axis_following, - axis_following_sibling, - axis_namespace, - axis_parent, - axis_preceding, - axis_preceding_sibling, - axis_self - }; - - enum nodetest_t - { - nodetest_none, - nodetest_name, - nodetest_type_node, - nodetest_type_comment, - nodetest_type_pi, - nodetest_type_text, - nodetest_pi, - nodetest_all, - nodetest_all_in_namespace - }; - - enum predicate_t - { - predicate_default, - predicate_posinv, - predicate_constant, - predicate_constant_one - }; - - enum nodeset_eval_t - { - nodeset_eval_all, - nodeset_eval_any, - nodeset_eval_first - }; - - template struct axis_to_type - { - static const axis_t axis; - }; - - template const axis_t axis_to_type::axis = N; - - class xpath_ast_node - { - private: - // node type - char _type; - char _rettype; - - // for ast_step - char _axis; - - // for ast_step/ast_predicate/ast_filter - char _test; - - // tree node structure - xpath_ast_node* _left; - xpath_ast_node* _right; - xpath_ast_node* _next; - - union - { - // value for ast_string_constant - const char_t* string; - // value for ast_number_constant - double number; - // variable for ast_variable - xpath_variable* variable; - // node test for ast_step (node name/namespace/node type/pi target) - const char_t* nodetest; - // table for ast_opt_translate_table - const unsigned char* table; - } _data; - - xpath_ast_node(const xpath_ast_node&); - xpath_ast_node& operator=(const xpath_ast_node&); - - template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) - { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) - { - if (lt == xpath_type_boolean || rt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number || rt == xpath_type_number) - return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); - else if (lt == xpath_type_string || rt == xpath_type_string) - { - xpath_allocator_capture cr(stack.result); - - xpath_string ls = lhs->eval_string(c, stack); - xpath_string rs = rhs->eval_string(c, stack); - - return comp(ls, rs); - } - } - else if (lt == xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) - return true; - } - - return false; - } - else - { - if (lt == xpath_type_node_set) - { - swap(lhs, rhs); - swap(lt, rt); - } - - if (lt == xpath_type_boolean) - return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); - else if (lt == xpath_type_number) - { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } - else if (lt == xpath_type_string) - { - xpath_allocator_capture cr(stack.result); - - xpath_string l = lhs->eval_string(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, string_value(*ri, stack.result))) - return true; - } - - return false; - } - } - - assert(!"Wrong types"); - return false; - } - - static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) - { - return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; - } - - template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) - { - xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); - - if (lt != xpath_type_node_set && rt != xpath_type_node_set) - return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); - else if (lt == xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - { - xpath_allocator_capture cri(stack.result); - - double l = convert_string_to_number(string_value(*li, stack.result).c_str()); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture crii(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - } - - return false; - } - else if (lt != xpath_type_node_set && rt == xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - double l = lhs->eval_number(c, stack); - xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) - { - xpath_allocator_capture cri(stack.result); - - if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) - return true; - } - - return false; - } - else if (lt == xpath_type_node_set && rt != xpath_type_node_set) - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); - double r = rhs->eval_number(c, stack); - - for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) - { - xpath_allocator_capture cri(stack.result); - - if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) - return true; - } - - return false; - } - else - { - assert(!"Wrong types"); - return false; - } - } - - static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) - { - assert(ns.size() >= first); - assert(expr->rettype() != xpath_type_number); - - size_t i = 1; - size_t size = ns.size() - first; - - xpath_node* last = ns.begin() + first; - - // remove_if... or well, sort of - for (xpath_node* it = last; it != ns.end(); ++it, ++i) - { - xpath_context c(*it, i, size); - - if (expr->eval_boolean(c, stack)) - { - *last++ = *it; - - if (once) break; - } - } - - ns.truncate(last); - } - - static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) - { - assert(ns.size() >= first); - assert(expr->rettype() == xpath_type_number); - - size_t i = 1; - size_t size = ns.size() - first; - - xpath_node* last = ns.begin() + first; - - // remove_if... or well, sort of - for (xpath_node* it = last; it != ns.end(); ++it, ++i) - { - xpath_context c(*it, i, size); - - if (expr->eval_number(c, stack) == i) - { - *last++ = *it; - - if (once) break; - } - } - - ns.truncate(last); - } - - static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) - { - assert(ns.size() >= first); - assert(expr->rettype() == xpath_type_number); - - size_t size = ns.size() - first; - - xpath_node* last = ns.begin() + first; - - xpath_context c(xpath_node(), 1, size); - - double er = expr->eval_number(c, stack); - - if (er >= 1.0 && er <= size) - { - size_t eri = static_cast(er); - - if (er == eri) - { - xpath_node r = last[eri - 1]; - - *last++ = r; - } - } - - ns.truncate(last); - } - - void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) - { - if (ns.size() == first) return; - - assert(_type == ast_filter || _type == ast_predicate); - - if (_test == predicate_constant || _test == predicate_constant_one) - apply_predicate_number_const(ns, first, _right, stack); - else if (_right->rettype() == xpath_type_number) - apply_predicate_number(ns, first, _right, stack, once); - else - apply_predicate_boolean(ns, first, _right, stack, once); - } - - void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval) - { - if (ns.size() == first) return; - - bool last_once = eval_once(ns.type(), eval); - - for (xpath_ast_node* pred = _right; pred; pred = pred->_next) - pred->apply_predicate(ns, first, stack, !pred->_next && last_once); - } - - bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) - { - assert(a); - - const char_t* name = a->name ? a->name : PUGIXML_TEXT(""); - - switch (_test) - { - case nodetest_name: - if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) - { - ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); - return true; - } - break; - - case nodetest_type_node: - case nodetest_all: - if (is_xpath_attribute(name)) - { - ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); - return true; - } - break; - - case nodetest_all_in_namespace: - if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) - { - ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); - return true; - } - break; - - default: - ; - } - - return false; - } - - bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) - { - assert(n); - - xml_node_type type = PUGI__NODETYPE(n); - - switch (_test) - { - case nodetest_name: - if (type == node_element && n->name && strequal(n->name, _data.nodetest)) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_type_node: - ns.push_back(xml_node(n), alloc); - return true; - - case nodetest_type_comment: - if (type == node_comment) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_type_text: - if (type == node_pcdata || type == node_cdata) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_type_pi: - if (type == node_pi) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_pi: - if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_all: - if (type == node_element) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - case nodetest_all_in_namespace: - if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) - { - ns.push_back(xml_node(n), alloc); - return true; - } - break; - - default: - assert(!"Unknown axis"); - } - - return false; - } - - template void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T) - { - const axis_t axis = T::axis; - - switch (axis) - { - case axis_attribute: - { - for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) - if (step_push(ns, a, n, alloc) & once) - return; - - break; - } - - case axis_child: - { - for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) - if (step_push(ns, c, alloc) & once) - return; - - break; - } - - case axis_descendant: - case axis_descendant_or_self: - { - if (axis == axis_descendant_or_self) - if (step_push(ns, n, alloc) & once) - return; - - xml_node_struct* cur = n->first_child; - - while (cur) - { - if (step_push(ns, cur, alloc) & once) - return; - - if (cur->first_child) - cur = cur->first_child; - else - { - while (!cur->next_sibling) - { - cur = cur->parent; - - if (cur == n) return; - } - - cur = cur->next_sibling; - } - } - - break; - } - - case axis_following_sibling: - { - for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) - if (step_push(ns, c, alloc) & once) - return; - - break; - } - - case axis_preceding_sibling: - { - for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) - if (step_push(ns, c, alloc) & once) - return; - - break; - } - - case axis_following: - { - xml_node_struct* cur = n; - - // exit from this node so that we don't include descendants - while (!cur->next_sibling) - { - cur = cur->parent; - - if (!cur) return; - } - - cur = cur->next_sibling; - - while (cur) - { - if (step_push(ns, cur, alloc) & once) - return; - - if (cur->first_child) - cur = cur->first_child; - else - { - while (!cur->next_sibling) - { - cur = cur->parent; - - if (!cur) return; - } - - cur = cur->next_sibling; - } - } - - break; - } - - case axis_preceding: - { - xml_node_struct* cur = n; - - // exit from this node so that we don't include descendants - while (!cur->prev_sibling_c->next_sibling) - { - cur = cur->parent; - - if (!cur) return; - } - - cur = cur->prev_sibling_c; - - while (cur) - { - if (cur->first_child) - cur = cur->first_child->prev_sibling_c; - else - { - // leaf node, can't be ancestor - if (step_push(ns, cur, alloc) & once) - return; - - while (!cur->prev_sibling_c->next_sibling) - { - cur = cur->parent; - - if (!cur) return; - - if (!node_is_ancestor(cur, n)) - if (step_push(ns, cur, alloc) & once) - return; - } - - cur = cur->prev_sibling_c; - } - } - - break; - } - - case axis_ancestor: - case axis_ancestor_or_self: - { - if (axis == axis_ancestor_or_self) - if (step_push(ns, n, alloc) & once) - return; - - xml_node_struct* cur = n->parent; - - while (cur) - { - if (step_push(ns, cur, alloc) & once) - return; - - cur = cur->parent; - } - - break; - } - - case axis_self: - { - step_push(ns, n, alloc); - - break; - } - - case axis_parent: - { - if (n->parent) - step_push(ns, n->parent, alloc); - - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) - { - const axis_t axis = T::axis; - - switch (axis) - { - case axis_ancestor: - case axis_ancestor_or_self: - { - if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test - if (step_push(ns, a, p, alloc) & once) - return; - - xml_node_struct* cur = p; - - while (cur) - { - if (step_push(ns, cur, alloc) & once) - return; - - cur = cur->parent; - } - - break; - } - - case axis_descendant_or_self: - case axis_self: - { - if (_test == nodetest_type_node) // reject attributes based on principal node type test - step_push(ns, a, p, alloc); - - break; - } - - case axis_following: - { - xml_node_struct* cur = p; - - while (cur) - { - if (cur->first_child) - cur = cur->first_child; - else - { - while (!cur->next_sibling) - { - cur = cur->parent; - - if (!cur) return; - } - - cur = cur->next_sibling; - } - - if (step_push(ns, cur, alloc) & once) - return; - } - - break; - } - - case axis_parent: - { - step_push(ns, p, alloc); - - break; - } - - case axis_preceding: - { - // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding - step_fill(ns, p, alloc, once, v); - break; - } - - default: - assert(!"Unimplemented axis"); - } - } - - template void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) - { - const axis_t axis = T::axis; - const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); - - if (xn.node()) - step_fill(ns, xn.node().internal_object(), alloc, once, v); - else if (axis_has_attributes && xn.attribute() && xn.parent()) - step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); - } - - template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) - { - const axis_t axis = T::axis; - const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); - const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; - - bool once = - (axis == axis_attribute && _test == nodetest_name) || - (!_right && eval_once(axis_type, eval)) || - (_right && !_right->_next && _right->_test == predicate_constant_one); - - xpath_node_set_raw ns; - ns.set_type(axis_type); - - if (_left) - { - xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all); - - // self axis preserves the original order - if (axis == axis_self) ns.set_type(s.type()); - - for (const xpath_node* it = s.begin(); it != s.end(); ++it) - { - size_t size = ns.size(); - - // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes - if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); - - step_fill(ns, *it, stack.result, once, v); - if (_right) apply_predicates(ns, size, stack, eval); - } - } - else - { - step_fill(ns, c.n, stack.result, once, v); - if (_right) apply_predicates(ns, 0, stack, eval); - } - - // child, attribute and self axes always generate unique set of nodes - // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice - if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) - ns.remove_duplicates(); - - return ns; - } - - public: - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_string_constant); - _data.string = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_number_constant); - _data.number = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) - { - assert(type == ast_variable); - _data.variable = value; - } - - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) - { - } - - xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): - _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) - { - assert(type == ast_step); - _data.nodetest = contents; - } - - xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): - _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(0) - { - assert(type == ast_filter || type == ast_predicate); - } - - void set_next(xpath_ast_node* value) - { - _next = value; - } - - void set_right(xpath_ast_node* value) - { - _right = value; - } - - bool eval_boolean(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_op_or: - return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); - - case ast_op_and: - return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); - - case ast_op_equal: - return compare_eq(_left, _right, c, stack, equal_to()); - - case ast_op_not_equal: - return compare_eq(_left, _right, c, stack, not_equal_to()); - - case ast_op_less: - return compare_rel(_left, _right, c, stack, less()); - - case ast_op_greater: - return compare_rel(_right, _left, c, stack, less()); - - case ast_op_less_or_equal: - return compare_rel(_left, _right, c, stack, less_equal()); - - case ast_op_greater_or_equal: - return compare_rel(_right, _left, c, stack, less_equal()); - - case ast_func_starts_with: - { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return starts_with(lr.c_str(), rr.c_str()); - } - - case ast_func_contains: - { - xpath_allocator_capture cr(stack.result); - - xpath_string lr = _left->eval_string(c, stack); - xpath_string rr = _right->eval_string(c, stack); - - return find_substring(lr.c_str(), rr.c_str()) != 0; - } - - case ast_func_boolean: - return _left->eval_boolean(c, stack); - - case ast_func_not: - return !_left->eval_boolean(c, stack); - - case ast_func_true: - return true; - - case ast_func_false: - return false; - - case ast_func_lang: - { - if (c.n.attribute()) return false; - - xpath_allocator_capture cr(stack.result); - - xpath_string lang = _left->eval_string(c, stack); - - for (xml_node n = c.n.node(); n; n = n.parent()) - { - xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); - - if (a) - { - const char_t* value = a.value(); - - // strnicmp / strncasecmp is not portable - for (const char_t* lit = lang.c_str(); *lit; ++lit) - { - if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; - ++value; - } - - return *value == 0 || *value == '-'; - } - } - - return false; - } - - case ast_opt_compare_attribute: - { - const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string(); - - xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); - - return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_boolean) - return _data.variable->get_boolean(); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_number: - return convert_number_to_boolean(eval_number(c, stack)); - - case xpath_type_string: - { - xpath_allocator_capture cr(stack.result); - - return !eval_string(c, stack).empty(); - } - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.result); - - return !eval_node_set(c, stack, nodeset_eval_any).empty(); - } - - default: - assert(!"Wrong expression for return type boolean"); - return false; - } - } - } - } - - double eval_number(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_op_add: - return _left->eval_number(c, stack) + _right->eval_number(c, stack); - - case ast_op_subtract: - return _left->eval_number(c, stack) - _right->eval_number(c, stack); - - case ast_op_multiply: - return _left->eval_number(c, stack) * _right->eval_number(c, stack); - - case ast_op_divide: - return _left->eval_number(c, stack) / _right->eval_number(c, stack); - - case ast_op_mod: - return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); - - case ast_op_negate: - return -_left->eval_number(c, stack); - - case ast_number_constant: - return _data.number; - - case ast_func_last: - return static_cast(c.size); - - case ast_func_position: - return static_cast(c.position); - - case ast_func_count: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); - } - - case ast_func_string_length_0: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(string_value(c.n, stack.result).length()); - } - - case ast_func_string_length_1: - { - xpath_allocator_capture cr(stack.result); - - return static_cast(_left->eval_string(c, stack).length()); - } - - case ast_func_number_0: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(string_value(c.n, stack.result).c_str()); - } - - case ast_func_number_1: - return _left->eval_number(c, stack); - - case ast_func_sum: - { - xpath_allocator_capture cr(stack.result); - - double r = 0; - - xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); - - for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) - { - xpath_allocator_capture cri(stack.result); - - r += convert_string_to_number(string_value(*it, stack.result).c_str()); - } - - return r; - } - - case ast_func_floor: - { - double r = _left->eval_number(c, stack); - - return r == r ? floor(r) : r; - } - - case ast_func_ceiling: - { - double r = _left->eval_number(c, stack); - - return r == r ? ceil(r) : r; - } - - case ast_func_round: - return round_nearest_nzero(_left->eval_number(c, stack)); - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_number) - return _data.variable->get_number(); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_boolean: - return eval_boolean(c, stack) ? 1 : 0; - - case xpath_type_string: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.result); - - return convert_string_to_number(eval_string(c, stack).c_str()); - } - - default: - assert(!"Wrong expression for return type number"); - return 0; - } - - } - } - } - - xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) - { - assert(_type == ast_func_concat); - - xpath_allocator_capture ct(stack.temp); - - // count the string number - size_t count = 1; - for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; - - // gather all strings - xpath_string static_buffer[4]; - xpath_string* buffer = static_buffer; - - // allocate on-heap for large concats - if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) - { - buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); - assert(buffer); - } - - // evaluate all strings to temporary stack - xpath_stack swapped_stack = {stack.temp, stack.result}; - - buffer[0] = _left->eval_string(c, swapped_stack); - - size_t pos = 1; - for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); - assert(pos == count); - - // get total length - size_t length = 0; - for (size_t i = 0; i < count; ++i) length += buffer[i].length(); - - // create final string - char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); - assert(result); - - char_t* ri = result; - - for (size_t j = 0; j < count; ++j) - for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) - *ri++ = *bi; - - *ri = 0; - - return xpath_string::from_heap_preallocated(result, ri); - } - - xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) - { - switch (_type) - { - case ast_string_constant: - return xpath_string::from_const(_data.string); - - case ast_func_local_name_0: - { - xpath_node na = c.n; - - return xpath_string::from_const(local_name(na)); - } - - case ast_func_local_name_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); - xpath_node na = ns.first(); - - return xpath_string::from_const(local_name(na)); - } - - case ast_func_name_0: - { - xpath_node na = c.n; - - return xpath_string::from_const(qualified_name(na)); - } - - case ast_func_name_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); - xpath_node na = ns.first(); - - return xpath_string::from_const(qualified_name(na)); - } - - case ast_func_namespace_uri_0: - { - xpath_node na = c.n; - - return xpath_string::from_const(namespace_uri(na)); - } - - case ast_func_namespace_uri_1: - { - xpath_allocator_capture cr(stack.result); - - xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); - xpath_node na = ns.first(); - - return xpath_string::from_const(namespace_uri(na)); - } - - case ast_func_string_0: - return string_value(c.n, stack.result); - - case ast_func_string_1: - return _left->eval_string(c, stack); - - case ast_func_concat: - return eval_string_concat(c, stack); - - case ast_func_substring_before: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - - return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); - } - - case ast_func_substring_after: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - xpath_string p = _right->eval_string(c, swapped_stack); - - const char_t* pos = find_substring(s.c_str(), p.c_str()); - if (!pos) return xpath_string(); - - const char_t* rbegin = pos + p.length(); - const char_t* rend = s.c_str() + s.length(); - - return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); - } - - case ast_func_substring_2: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - - if (is_nan(first)) return xpath_string(); // NaN - else if (first >= s_length + 1) return xpath_string(); - - size_t pos = first < 1 ? 1 : static_cast(first); - assert(1 <= pos && pos <= s_length + 1); - - const char_t* rbegin = s.c_str() + (pos - 1); - const char_t* rend = s.c_str() + s.length(); - - return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); - } - - case ast_func_substring_3: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, swapped_stack); - size_t s_length = s.length(); - - double first = round_nearest(_right->eval_number(c, stack)); - double last = first + round_nearest(_right->_next->eval_number(c, stack)); - - if (is_nan(first) || is_nan(last)) return xpath_string(); - else if (first >= s_length + 1) return xpath_string(); - else if (first >= last) return xpath_string(); - else if (last < 1) return xpath_string(); - - size_t pos = first < 1 ? 1 : static_cast(first); - size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); - - assert(1 <= pos && pos <= end && end <= s_length + 1); - const char_t* rbegin = s.c_str() + (pos - 1); - const char_t* rend = s.c_str() + (end - 1); - - return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result); - } - - case ast_func_normalize_space_0: - { - xpath_string s = string_value(c.n, stack.result); - - char_t* begin = s.data(stack.result); - char_t* end = normalize_space(begin); - - return xpath_string::from_heap_preallocated(begin, end); - } - - case ast_func_normalize_space_1: - { - xpath_string s = _left->eval_string(c, stack); - - char_t* begin = s.data(stack.result); - char_t* end = normalize_space(begin); - - return xpath_string::from_heap_preallocated(begin, end); - } - - case ast_func_translate: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_string s = _left->eval_string(c, stack); - xpath_string from = _right->eval_string(c, swapped_stack); - xpath_string to = _right->_next->eval_string(c, swapped_stack); - - char_t* begin = s.data(stack.result); - char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); - - return xpath_string::from_heap_preallocated(begin, end); - } - - case ast_opt_translate_table: - { - xpath_string s = _left->eval_string(c, stack); - - char_t* begin = s.data(stack.result); - char_t* end = translate_table(begin, _data.table); - - return xpath_string::from_heap_preallocated(begin, end); - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_string) - return xpath_string::from_const(_data.variable->get_string()); - - // fallthrough to type conversion - } - - default: - { - switch (_rettype) - { - case xpath_type_boolean: - return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - - case xpath_type_number: - return convert_number_to_string(eval_number(c, stack), stack.result); - - case xpath_type_node_set: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); - return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); - } - - default: - assert(!"Wrong expression for return type string"); - return xpath_string(); - } - } - } - } - - xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval) - { - switch (_type) - { - case ast_op_union: - { - xpath_allocator_capture cr(stack.temp); - - xpath_stack swapped_stack = {stack.temp, stack.result}; - - xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack, eval); - xpath_node_set_raw rs = _right->eval_node_set(c, stack, eval); - - // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother - rs.set_type(xpath_node_set::type_unsorted); - - rs.append(ls.begin(), ls.end(), stack.result); - rs.remove_duplicates(); - - return rs; - } - - case ast_filter: - { - xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all); - - // either expression is a number or it contains position() call; sort by document order - if (_test != predicate_posinv) set.sort_do(); - - bool once = eval_once(set.type(), eval); - - apply_predicate(set, 0, stack, once); - - return set; - } - - case ast_func_id: - return xpath_node_set_raw(); - - case ast_step: - { - switch (_axis) - { - case axis_ancestor: - return step_do(c, stack, eval, axis_to_type()); - - case axis_ancestor_or_self: - return step_do(c, stack, eval, axis_to_type()); - - case axis_attribute: - return step_do(c, stack, eval, axis_to_type()); - - case axis_child: - return step_do(c, stack, eval, axis_to_type()); - - case axis_descendant: - return step_do(c, stack, eval, axis_to_type()); - - case axis_descendant_or_self: - return step_do(c, stack, eval, axis_to_type()); - - case axis_following: - return step_do(c, stack, eval, axis_to_type()); - - case axis_following_sibling: - return step_do(c, stack, eval, axis_to_type()); - - case axis_namespace: - // namespaced axis is not supported - return xpath_node_set_raw(); - - case axis_parent: - return step_do(c, stack, eval, axis_to_type()); - - case axis_preceding: - return step_do(c, stack, eval, axis_to_type()); - - case axis_preceding_sibling: - return step_do(c, stack, eval, axis_to_type()); - - case axis_self: - return step_do(c, stack, eval, axis_to_type()); - - default: - assert(!"Unknown axis"); - return xpath_node_set_raw(); - } - } - - case ast_step_root: - { - assert(!_right); // root step can't have any predicates - - xpath_node_set_raw ns; - - ns.set_type(xpath_node_set::type_sorted); - - if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); - else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); - - return ns; - } - - case ast_variable: - { - assert(_rettype == _data.variable->type()); - - if (_rettype == xpath_type_node_set) - { - const xpath_node_set& s = _data.variable->get_node_set(); - - xpath_node_set_raw ns; - - ns.set_type(s.type()); - ns.append(s.begin(), s.end(), stack.result); - - return ns; - } - - // fallthrough to type conversion - } - - default: - assert(!"Wrong expression for return type node set"); - return xpath_node_set_raw(); - } - } - - void optimize(xpath_allocator* alloc) - { - if (_left) _left->optimize(alloc); - if (_right) _right->optimize(alloc); - if (_next) _next->optimize(alloc); - - // Rewrite [position()=expr] with [expr] - // Note that this step has to go before classification to recognize [position()=1] - if ((_type == ast_filter || _type == ast_predicate) && - _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number) - { - _right = _right->_right; - } - - // Classify filter/predicate ops to perform various optimizations during evaluation - if (_type == ast_filter || _type == ast_predicate) - { - assert(_test == predicate_default); - - if (_right->_type == ast_number_constant && _right->_data.number == 1.0) - _test = predicate_constant_one; - else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last)) - _test = predicate_constant; - else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr()) - _test = predicate_posinv; - } - - // Rewrite descendant-or-self::node()/child::foo with descendant::foo - // The former is a full form of //foo, the latter is much faster since it executes the node test immediately - // Do a similar kind of rewrite for self/descendant/descendant-or-self axes - // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1]) - if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left && - _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right && - is_posinv_step()) - { - if (_axis == axis_child || _axis == axis_descendant) - _axis = axis_descendant; - else - _axis = axis_descendant_or_self; - - _left = _left->_left; - } - - // Use optimized lookup table implementation for translate() with constant arguments - if (_type == ast_func_translate && _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant) - { - unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string); - - if (table) - { - _type = ast_opt_translate_table; - _data.table = table; - } - } - - // Use optimized path for @attr = 'value' or @attr = $value - if (_type == ast_op_equal && - _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right && - (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) - { - _type = ast_opt_compare_attribute; - } - } - - bool is_posinv_expr() const - { - switch (_type) - { - case ast_func_position: - case ast_func_last: - return false; - - case ast_string_constant: - case ast_number_constant: - case ast_variable: - return true; - - case ast_step: - case ast_step_root: - return true; - - case ast_predicate: - case ast_filter: - return true; - - default: - if (_left && !_left->is_posinv_expr()) return false; - - for (xpath_ast_node* n = _right; n; n = n->_next) - if (!n->is_posinv_expr()) return false; - - return true; - } - } - - bool is_posinv_step() const - { - assert(_type == ast_step); - - for (xpath_ast_node* n = _right; n; n = n->_next) - { - assert(n->_type == ast_predicate); - - if (n->_test != predicate_posinv) - return false; - } - - return true; - } - - xpath_value_type rettype() const - { - return static_cast(_rettype); - } - }; - - struct xpath_parser - { - xpath_allocator* _alloc; - xpath_lexer _lexer; - - const char_t* _query; - xpath_variable_set* _variables; - - xpath_parse_result* _result; - - char_t _scratch[32]; - - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf _error_handler; - #endif - - void throw_error(const char* message) - { - _result->error = message; - _result->offset = _lexer.current_pos() - _query; - - #ifdef PUGIXML_NO_EXCEPTIONS - longjmp(_error_handler, 1); - #else - throw xpath_exception(*_result); - #endif - } - - void throw_error_oom() - { - #ifdef PUGIXML_NO_EXCEPTIONS - throw_error("Out of memory"); - #else - throw std::bad_alloc(); - #endif - } - - void* alloc_node() - { - void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); - - if (!result) throw_error_oom(); - - return result; - } - - const char_t* alloc_string(const xpath_lexer_string& value) - { - if (value.begin) - { - size_t length = static_cast(value.end - value.begin); - - char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); - if (!c) throw_error_oom(); - assert(c); // workaround for clang static analysis - - memcpy(c, value.begin, length * sizeof(char_t)); - c[length] = 0; - - return c; - } - else return 0; - } - - xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) - { - assert(argc <= 1); - - if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - - return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); - } - - xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) - { - switch (name.begin[0]) - { - case 'b': - if (name == PUGIXML_TEXT("boolean") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); - - break; - - case 'c': - if (name == PUGIXML_TEXT("count") && argc == 1) - { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); - } - else if (name == PUGIXML_TEXT("contains") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); - else if (name == PUGIXML_TEXT("concat") && argc >= 2) - return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("ceiling") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); - - break; - - case 'f': - if (name == PUGIXML_TEXT("false") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); - else if (name == PUGIXML_TEXT("floor") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); - - break; - - case 'i': - if (name == PUGIXML_TEXT("id") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); - - break; - - case 'l': - if (name == PUGIXML_TEXT("last") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); - else if (name == PUGIXML_TEXT("lang") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("local-name") && argc <= 1) - return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); - - break; - - case 'n': - if (name == PUGIXML_TEXT("name") && argc <= 1) - return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); - else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) - return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); - else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("not") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("number") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); - - break; - - case 'p': - if (name == PUGIXML_TEXT("position") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); - - break; - - case 'r': - if (name == PUGIXML_TEXT("round") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); - - break; - - case 's': - if (name == PUGIXML_TEXT("string") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); - else if (name == PUGIXML_TEXT("string-length") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); - else if (name == PUGIXML_TEXT("starts-with") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-before") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-after") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) - return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("sum") && argc == 1) - { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); - } - - break; - - case 't': - if (name == PUGIXML_TEXT("translate") && argc == 3) - return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("true") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); - - break; - - default: - break; - } - - throw_error("Unrecognized function or wrong parameter count"); - - return 0; - } - - axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) - { - specified = true; - - switch (name.begin[0]) - { - case 'a': - if (name == PUGIXML_TEXT("ancestor")) - return axis_ancestor; - else if (name == PUGIXML_TEXT("ancestor-or-self")) - return axis_ancestor_or_self; - else if (name == PUGIXML_TEXT("attribute")) - return axis_attribute; - - break; - - case 'c': - if (name == PUGIXML_TEXT("child")) - return axis_child; - - break; - - case 'd': - if (name == PUGIXML_TEXT("descendant")) - return axis_descendant; - else if (name == PUGIXML_TEXT("descendant-or-self")) - return axis_descendant_or_self; - - break; - - case 'f': - if (name == PUGIXML_TEXT("following")) - return axis_following; - else if (name == PUGIXML_TEXT("following-sibling")) - return axis_following_sibling; - - break; - - case 'n': - if (name == PUGIXML_TEXT("namespace")) - return axis_namespace; - - break; - - case 'p': - if (name == PUGIXML_TEXT("parent")) - return axis_parent; - else if (name == PUGIXML_TEXT("preceding")) - return axis_preceding; - else if (name == PUGIXML_TEXT("preceding-sibling")) - return axis_preceding_sibling; - - break; - - case 's': - if (name == PUGIXML_TEXT("self")) - return axis_self; - - break; - - default: - break; - } - - specified = false; - return axis_child; - } - - nodetest_t parse_node_test_type(const xpath_lexer_string& name) - { - switch (name.begin[0]) - { - case 'c': - if (name == PUGIXML_TEXT("comment")) - return nodetest_type_comment; - - break; - - case 'n': - if (name == PUGIXML_TEXT("node")) - return nodetest_type_node; - - break; - - case 'p': - if (name == PUGIXML_TEXT("processing-instruction")) - return nodetest_type_pi; - - break; - - case 't': - if (name == PUGIXML_TEXT("text")) - return nodetest_type_text; - - break; - - default: - break; - } - - return nodetest_none; - } - - // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall - xpath_ast_node* parse_primary_expression() - { - switch (_lexer.current()) - { - case lex_var_ref: - { - xpath_lexer_string name = _lexer.contents(); - - if (!_variables) - throw_error("Unknown variable: variable set is not provided"); - - xpath_variable* var = get_variable_scratch(_scratch, _variables, name.begin, name.end); - - if (!var) - throw_error("Unknown variable: variable set does not contain the given name"); - - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); - } - - case lex_open_brace: - { - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (_lexer.current() != lex_close_brace) - throw_error("Unmatched braces"); - - _lexer.next(); - - return n; - } - - case lex_quoted_string: - { - const char_t* value = alloc_string(_lexer.contents()); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); - _lexer.next(); - - return n; - } - - case lex_number: - { - double value = 0; - - if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) - throw_error_oom(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); - _lexer.next(); - - return n; - } - - case lex_string: - { - xpath_ast_node* args[2] = {0}; - size_t argc = 0; - - xpath_lexer_string function = _lexer.contents(); - _lexer.next(); - - xpath_ast_node* last_arg = 0; - - if (_lexer.current() != lex_open_brace) - throw_error("Unrecognized function call"); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - args[argc++] = parse_expression(); - - while (_lexer.current() != lex_close_brace) - { - if (_lexer.current() != lex_comma) - throw_error("No comma between function arguments"); - _lexer.next(); - - xpath_ast_node* n = parse_expression(); - - if (argc < 2) args[argc] = n; - else last_arg->set_next(n); - - argc++; - last_arg = n; - } - - _lexer.next(); - - return parse_function(function, argc, args); - } - - default: - throw_error("Unrecognizable primary expression"); - - return 0; - } - } - - // FilterExpr ::= PrimaryExpr | FilterExpr Predicate - // Predicate ::= '[' PredicateExpr ']' - // PredicateExpr ::= Expr - xpath_ast_node* parse_filter_expression() - { - xpath_ast_node* n = parse_primary_expression(); - - while (_lexer.current() == lex_open_square_brace) - { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); - - n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - - _lexer.next(); - } - - return n; - } - - // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep - // AxisSpecifier ::= AxisName '::' | '@'? - // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' - // NameTest ::= '*' | NCName ':' '*' | QName - // AbbreviatedStep ::= '.' | '..' - xpath_ast_node* parse_step(xpath_ast_node* set) - { - if (set && set->rettype() != xpath_type_node_set) - throw_error("Step has to be applied to node set"); - - bool axis_specified = false; - axis_t axis = axis_child; // implied child axis - - if (_lexer.current() == lex_axis_attribute) - { - axis = axis_attribute; - axis_specified = true; - - _lexer.next(); - } - else if (_lexer.current() == lex_dot) - { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); - } - else if (_lexer.current() == lex_double_dot) - { - _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); - } - - nodetest_t nt_type = nodetest_none; - xpath_lexer_string nt_name; - - if (_lexer.current() == lex_string) - { - // node name test - nt_name = _lexer.contents(); - _lexer.next(); - - // was it an axis name? - if (_lexer.current() == lex_double_colon) - { - // parse axis name - if (axis_specified) throw_error("Two axis specifiers in one step"); - - axis = parse_axis_name(nt_name, axis_specified); - - if (!axis_specified) throw_error("Unknown axis"); - - // read actual node test - _lexer.next(); - - if (_lexer.current() == lex_multiply) - { - nt_type = nodetest_all; - nt_name = xpath_lexer_string(); - _lexer.next(); - } - else if (_lexer.current() == lex_string) - { - nt_name = _lexer.contents(); - _lexer.next(); - } - else throw_error("Unrecognized node test"); - } - - if (nt_type == nodetest_none) - { - // node type test or processing-instruction - if (_lexer.current() == lex_open_brace) - { - _lexer.next(); - - if (_lexer.current() == lex_close_brace) - { - _lexer.next(); - - nt_type = parse_node_test_type(nt_name); - - if (nt_type == nodetest_none) throw_error("Unrecognized node type"); - - nt_name = xpath_lexer_string(); - } - else if (nt_name == PUGIXML_TEXT("processing-instruction")) - { - if (_lexer.current() != lex_quoted_string) - throw_error("Only literals are allowed as arguments to processing-instruction()"); - - nt_type = nodetest_pi; - nt_name = _lexer.contents(); - _lexer.next(); - - if (_lexer.current() != lex_close_brace) - throw_error("Unmatched brace near processing-instruction()"); - _lexer.next(); - } - else - throw_error("Unmatched brace near node type test"); - - } - // QName or NCName:* - else - { - if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* - { - nt_name.end--; // erase * - - nt_type = nodetest_all_in_namespace; - } - else nt_type = nodetest_name; - } - } - } - else if (_lexer.current() == lex_multiply) - { - nt_type = nodetest_all; - _lexer.next(); - } - else throw_error("Unrecognized node test"); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); - - xpath_ast_node* last = 0; - - while (_lexer.current() == lex_open_square_brace) - { - _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - - xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); - - if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - _lexer.next(); - - if (last) last->set_next(pred); - else n->set_right(pred); - - last = pred; - } - - return n; - } - - // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step - xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) - { - xpath_ast_node* n = parse_step(set); - - while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) - { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - - n = parse_step(n); - } - - return n; - } - - // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath - // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath - xpath_ast_node* parse_location_path() - { - if (_lexer.current() == lex_slash) - { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); - - // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path - lexeme_t l = _lexer.current(); - - if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) - return parse_relative_location_path(n); - else - return n; - } - else if (_lexer.current() == lex_double_slash) - { - _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - - return parse_relative_location_path(n); - } - - // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 - return parse_relative_location_path(0); - } - - // PathExpr ::= LocationPath - // | FilterExpr - // | FilterExpr '/' RelativeLocationPath - // | FilterExpr '//' RelativeLocationPath - // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr - // UnaryExpr ::= UnionExpr | '-' UnaryExpr - xpath_ast_node* parse_path_or_unary_expression() - { - // Clarification. - // PathExpr begins with either LocationPath or FilterExpr. - // FilterExpr begins with PrimaryExpr - // PrimaryExpr begins with '$' in case of it being a variable reference, - // '(' in case of it being an expression, string literal, number constant or - // function call. - - if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || - _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || - _lexer.current() == lex_string) - { - if (_lexer.current() == lex_string) - { - // This is either a function call, or not - if not, we shall proceed with location path - const char_t* state = _lexer.state(); - - while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; - - if (*state != '(') return parse_location_path(); - - // This looks like a function call; however this still can be a node-test. Check it. - if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); - } - - xpath_ast_node* n = parse_filter_expression(); - - if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) - { - lexeme_t l = _lexer.current(); - _lexer.next(); - - if (l == lex_double_slash) - { - if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); - - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - } - - // select from location path - return parse_relative_location_path(n); - } - - return n; - } - else if (_lexer.current() == lex_minus) - { - _lexer.next(); - - // precedence 7+ - only parses union expressions - xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); - - return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); - } - else - return parse_location_path(); - } - - struct binary_op_t - { - ast_type_t asttype; - xpath_value_type rettype; - int precedence; - - binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0) - { - } - - binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_) - { - } - - static binary_op_t parse(xpath_lexer& lexer) - { - switch (lexer.current()) - { - case lex_string: - if (lexer.contents() == PUGIXML_TEXT("or")) - return binary_op_t(ast_op_or, xpath_type_boolean, 1); - else if (lexer.contents() == PUGIXML_TEXT("and")) - return binary_op_t(ast_op_and, xpath_type_boolean, 2); - else if (lexer.contents() == PUGIXML_TEXT("div")) - return binary_op_t(ast_op_divide, xpath_type_number, 6); - else if (lexer.contents() == PUGIXML_TEXT("mod")) - return binary_op_t(ast_op_mod, xpath_type_number, 6); - else - return binary_op_t(); - - case lex_equal: - return binary_op_t(ast_op_equal, xpath_type_boolean, 3); - - case lex_not_equal: - return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3); - - case lex_less: - return binary_op_t(ast_op_less, xpath_type_boolean, 4); - - case lex_greater: - return binary_op_t(ast_op_greater, xpath_type_boolean, 4); - - case lex_less_or_equal: - return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4); - - case lex_greater_or_equal: - return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4); - - case lex_plus: - return binary_op_t(ast_op_add, xpath_type_number, 5); - - case lex_minus: - return binary_op_t(ast_op_subtract, xpath_type_number, 5); - - case lex_multiply: - return binary_op_t(ast_op_multiply, xpath_type_number, 6); - - case lex_union: - return binary_op_t(ast_op_union, xpath_type_node_set, 7); - - default: - return binary_op_t(); - } - } - }; - - xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit) - { - binary_op_t op = binary_op_t::parse(_lexer); - - while (op.asttype != ast_unknown && op.precedence >= limit) - { - _lexer.next(); - - xpath_ast_node* rhs = parse_path_or_unary_expression(); - - binary_op_t nextop = binary_op_t::parse(_lexer); - - while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) - { - rhs = parse_expression_rec(rhs, nextop.precedence); - - nextop = binary_op_t::parse(_lexer); - } - - if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) - throw_error("Union operator has to be applied to node sets"); - - lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs); - - op = binary_op_t::parse(_lexer); - } - - return lhs; - } - - // Expr ::= OrExpr - // OrExpr ::= AndExpr | OrExpr 'or' AndExpr - // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr - // EqualityExpr ::= RelationalExpr - // | EqualityExpr '=' RelationalExpr - // | EqualityExpr '!=' RelationalExpr - // RelationalExpr ::= AdditiveExpr - // | RelationalExpr '<' AdditiveExpr - // | RelationalExpr '>' AdditiveExpr - // | RelationalExpr '<=' AdditiveExpr - // | RelationalExpr '>=' AdditiveExpr - // AdditiveExpr ::= MultiplicativeExpr - // | AdditiveExpr '+' MultiplicativeExpr - // | AdditiveExpr '-' MultiplicativeExpr - // MultiplicativeExpr ::= UnaryExpr - // | MultiplicativeExpr '*' UnaryExpr - // | MultiplicativeExpr 'div' UnaryExpr - // | MultiplicativeExpr 'mod' UnaryExpr - xpath_ast_node* parse_expression() - { - return parse_expression_rec(parse_path_or_unary_expression(), 0); - } - - xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) - { - } - - xpath_ast_node* parse() - { - xpath_ast_node* result = parse_expression(); - - if (_lexer.current() != lex_eof) - { - // there are still unparsed tokens left, error - throw_error("Incorrect query"); - } - - return result; - } - - static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) - { - xpath_parser parser(query, variables, alloc, result); - - #ifdef PUGIXML_NO_EXCEPTIONS - int error = setjmp(parser._error_handler); - - return (error == 0) ? parser.parse() : 0; - #else - return parser.parse(); - #endif - } - }; - - struct xpath_query_impl - { - static xpath_query_impl* create() - { - void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); - - return new (memory) xpath_query_impl(); - } - - static void destroy(void* ptr) - { - if (!ptr) return; - - // free all allocated pages - static_cast(ptr)->alloc.release(); - - // free allocator memory (with the first page) - xml_memory::deallocate(ptr); - } - - xpath_query_impl(): root(0), alloc(&block) - { - block.next = 0; - block.capacity = sizeof(block.data); - } - - xpath_ast_node* root; - xpath_allocator alloc; - xpath_memory_block block; - }; - - PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) - { - if (!impl) return xpath_string(); - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_string(); - #endif - - xpath_context c(n, 1, 1); - - return impl->root->eval_string(c, sd.stack); - } - - PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) - { - if (!impl) return 0; - - if (impl->root->rettype() != xpath_type_node_set) - { - #ifdef PUGIXML_NO_EXCEPTIONS - return 0; - #else - xpath_parse_result res; - res.error = "Expression does not evaluate to node set"; - - throw xpath_exception(res); - #endif - } - - return impl->root; - } -PUGI__NS_END - -namespace pugi -{ -#ifndef PUGIXML_NO_EXCEPTIONS - PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) - { - assert(_result.error); - } - - PUGI__FN const char* xpath_exception::what() const throw() - { - return _result.error; - } - - PUGI__FN const xpath_parse_result& xpath_exception::result() const - { - return _result; - } -#endif - - PUGI__FN xpath_node::xpath_node() - { - } - - PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) - { - } - - PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) - { - } - - PUGI__FN xml_node xpath_node::node() const - { - return _attribute ? xml_node() : _node; - } - - PUGI__FN xml_attribute xpath_node::attribute() const - { - return _attribute; - } - - PUGI__FN xml_node xpath_node::parent() const - { - return _attribute ? _node : _node.parent(); - } - - PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) - { - } - - PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const - { - return (_node || _attribute) ? unspecified_bool_xpath_node : 0; - } - - PUGI__FN bool xpath_node::operator!() const - { - return !(_node || _attribute); - } - - PUGI__FN bool xpath_node::operator==(const xpath_node& n) const - { - return _node == n._node && _attribute == n._attribute; - } - - PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const - { - return _node != n._node || _attribute != n._attribute; - } - -#ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) - { - return (bool)lhs && rhs; - } - - PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) - { - return (bool)lhs || rhs; - } -#endif - - PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_) - { - assert(begin_ <= end_); - - size_t size_ = static_cast(end_ - begin_); - - if (size_ <= 1) - { - // deallocate old buffer - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - - // use internal buffer - if (begin_ != end_) _storage = *begin_; - - _begin = &_storage; - _end = &_storage + size_; - } - else - { - // make heap copy - xpath_node* storage = static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); - - if (!storage) - { - #ifdef PUGIXML_NO_EXCEPTIONS - return; - #else - throw std::bad_alloc(); - #endif - } - - memcpy(storage, begin_, size_ * sizeof(xpath_node)); - - // deallocate old buffer - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - - // finalize - _begin = storage; - _end = storage + size_; - } - } - - PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) - { - } - - PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage) - { - _assign(begin_, end_); - } - - PUGI__FN xpath_node_set::~xpath_node_set() - { - if (_begin != &_storage) impl::xml_memory::deallocate(_begin); - } - - PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) - { - _assign(ns._begin, ns._end); - } - - PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) - { - if (this == &ns) return *this; - - _type = ns._type; - _assign(ns._begin, ns._end); - - return *this; - } - - PUGI__FN xpath_node_set::type_t xpath_node_set::type() const - { - return _type; - } - - PUGI__FN size_t xpath_node_set::size() const - { - return _end - _begin; - } - - PUGI__FN bool xpath_node_set::empty() const - { - return _begin == _end; - } - - PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const - { - assert(index < size()); - return _begin[index]; - } - - PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const - { - return _begin; - } - - PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const - { - return _end; - } - - PUGI__FN void xpath_node_set::sort(bool reverse) - { - _type = impl::xpath_sort(_begin, _end, _type, reverse); - } - - PUGI__FN xpath_node xpath_node_set::first() const - { - return impl::xpath_first(_begin, _end, _type); - } - - PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) - { - } - - PUGI__FN xpath_parse_result::operator bool() const - { - return error == 0; - } - - PUGI__FN const char* xpath_parse_result::description() const - { - return error ? error : "No error"; - } - - PUGI__FN xpath_variable::xpath_variable(): _type(xpath_type_none), _next(0) - { - } - - PUGI__FN const char_t* xpath_variable::name() const - { - switch (_type) - { - case xpath_type_node_set: - return static_cast(this)->name; - - case xpath_type_number: - return static_cast(this)->name; - - case xpath_type_string: - return static_cast(this)->name; - - case xpath_type_boolean: - return static_cast(this)->name; - - default: - assert(!"Invalid variable type"); - return 0; - } - } - - PUGI__FN xpath_value_type xpath_variable::type() const - { - return _type; - } - - PUGI__FN bool xpath_variable::get_boolean() const - { - return (_type == xpath_type_boolean) ? static_cast(this)->value : false; - } - - PUGI__FN double xpath_variable::get_number() const - { - return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); - } - - PUGI__FN const char_t* xpath_variable::get_string() const - { - const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; - return value ? value : PUGIXML_TEXT(""); - } - - PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const - { - return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; - } - - PUGI__FN bool xpath_variable::set(bool value) - { - if (_type != xpath_type_boolean) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN bool xpath_variable::set(double value) - { - if (_type != xpath_type_number) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN bool xpath_variable::set(const char_t* value) - { - if (_type != xpath_type_string) return false; - - impl::xpath_variable_string* var = static_cast(this); - - // duplicate string - size_t size = (impl::strlength(value) + 1) * sizeof(char_t); - - char_t* copy = static_cast(impl::xml_memory::allocate(size)); - if (!copy) return false; - - memcpy(copy, value, size); - - // replace old string - if (var->value) impl::xml_memory::deallocate(var->value); - var->value = copy; - - return true; - } - - PUGI__FN bool xpath_variable::set(const xpath_node_set& value) - { - if (_type != xpath_type_node_set) return false; - - static_cast(this)->value = value; - return true; - } - - PUGI__FN xpath_variable_set::xpath_variable_set() - { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; - } - - PUGI__FN xpath_variable_set::~xpath_variable_set() - { - for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) - { - xpath_variable* var = _data[i]; - - while (var) - { - xpath_variable* next = var->_next; - - impl::delete_xpath_variable(var->_type, var); - - var = next; - } - } - } - - PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const - { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = impl::hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (impl::strequal(var->name(), name)) - return var; - - return 0; - } - - PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) - { - const size_t hash_size = sizeof(_data) / sizeof(_data[0]); - size_t hash = impl::hash_string(name) % hash_size; - - // look for existing variable - for (xpath_variable* var = _data[hash]; var; var = var->_next) - if (impl::strequal(var->name(), name)) - return var->type() == type ? var : 0; - - // add new variable - xpath_variable* result = impl::new_xpath_variable(type, name); - - if (result) - { - result->_type = type; - result->_next = _data[hash]; - - _data[hash] = result; - } - - return result; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) - { - xpath_variable* var = add(name, xpath_type_boolean); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) - { - xpath_variable* var = add(name, xpath_type_number); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) - { - xpath_variable* var = add(name, xpath_type_string); - return var ? var->set(value) : false; - } - - PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) - { - xpath_variable* var = add(name, xpath_type_node_set); - return var ? var->set(value) : false; - } - - PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) - { - return find(name); - } - - PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const - { - return find(name); - } - - PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) - { - impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); - - if (!qimpl) - { - #ifdef PUGIXML_NO_EXCEPTIONS - _result.error = "Out of memory"; - #else - throw std::bad_alloc(); - #endif - } - else - { - impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy); - - qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); - - if (qimpl->root) - { - qimpl->root->optimize(&qimpl->alloc); - - _impl = static_cast(impl_holder.release()); - _result.error = 0; - } - } - } - - PUGI__FN xpath_query::~xpath_query() - { - impl::xpath_query_impl::destroy(_impl); - } - - PUGI__FN xpath_value_type xpath_query::return_type() const - { - if (!_impl) return xpath_type_none; - - return static_cast(_impl)->root->rettype(); - } - - PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const - { - if (!_impl) return false; - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return false; - #endif - - return static_cast(_impl)->root->eval_boolean(c, sd.stack); - } - - PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const - { - if (!_impl) return impl::gen_nan(); - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return impl::gen_nan(); - #endif - - return static_cast(_impl)->root->eval_number(c, sd.stack); - } - -#ifndef PUGIXML_NO_STL - PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const - { - impl::xpath_stack_data sd; - - impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); - - return string_t(r.c_str(), r.length()); - } -#endif - - PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const - { - impl::xpath_stack_data sd; - - impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); - - size_t full_size = r.length() + 1; - - if (capacity > 0) - { - size_t size = (full_size < capacity) ? full_size : capacity; - assert(size > 0); - - memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); - buffer[size - 1] = 0; - } - - return full_size; - } - - PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const - { - impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); - if (!root) return xpath_node_set(); - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node_set(); - #endif - - impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); - - return xpath_node_set(r.begin(), r.end(), r.type()); - } - - PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const - { - impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); - if (!root) return xpath_node(); - - impl::xpath_context c(n, 1, 1); - impl::xpath_stack_data sd; - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node(); - #endif - - impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); - - return r.first(); - } - - PUGI__FN const xpath_parse_result& xpath_query::result() const - { - return _result; - } - - PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) - { - } - - PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const - { - return _impl ? unspecified_bool_xpath_query : 0; - } - - PUGI__FN bool xpath_query::operator!() const - { - return !_impl; - } - - PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const - { - xpath_query q(query, variables); - return select_node(q); - } - - PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const - { - return query.evaluate_node(*this); - } - - PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const - { - xpath_query q(query, variables); - return select_nodes(q); - } - - PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const - { - return query.evaluate_node_set(*this); - } - - PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const - { - xpath_query q(query, variables); - return select_single_node(q); - } - - PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const - { - return query.evaluate_node(*this); - } -} - -#endif - -#ifdef __BORLANDC__ -# pragma option pop -#endif - -// Intel C++ does not properly keep warning state for function templates, -// so popping warning state at the end of translation unit leads to warnings in the middle. -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) -# pragma warning(pop) -#endif - -// Undefine all local macros (makes sure we're not leaking macros in header-only mode) -#undef PUGI__NO_INLINE -#undef PUGI__UNLIKELY -#undef PUGI__STATIC_ASSERT -#undef PUGI__DMC_VOLATILE -#undef PUGI__MSVC_CRT_VERSION -#undef PUGI__NS_BEGIN -#undef PUGI__NS_END -#undef PUGI__FN -#undef PUGI__FN_NO_INLINE -#undef PUGI__NODETYPE -#undef PUGI__IS_CHARTYPE_IMPL -#undef PUGI__IS_CHARTYPE -#undef PUGI__IS_CHARTYPEX -#undef PUGI__ENDSWITH -#undef PUGI__SKIPWS -#undef PUGI__OPTSET -#undef PUGI__PUSHNODE -#undef PUGI__POPNODE -#undef PUGI__SCANFOR -#undef PUGI__SCANWHILE -#undef PUGI__SCANWHILE_UNROLL -#undef PUGI__ENDSEG -#undef PUGI__THROW_ERROR -#undef PUGI__CHECK_ERROR - -#endif - -/** - * Copyright (c) 2006-2015 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.hpp b/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.hpp deleted file mode 100644 index d59f8640398..00000000000 --- a/addons/ofxProjectGenerator/libs/pugixml/src/pugixml.hpp +++ /dev/null @@ -1,1366 +0,0 @@ -/** - * pugixml parser - version 1.6 - * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at http://pugixml.org/ - * - * This library is distributed under the MIT License. See notice at the end - * of this file. - * - * This work is based on the pugxml parser, which is: - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) - */ - -#ifndef PUGIXML_VERSION -// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons -# define PUGIXML_VERSION 160 -#endif - -// Include user configuration file (this can define various configuration macros) -#include "pugiconfig.hpp" - -#ifndef HEADER_PUGIXML_HPP -#define HEADER_PUGIXML_HPP - -// Include stddef.h for size_t and ptrdiff_t -#include - -// Include exception header for XPath -#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) -# include -#endif - -// Include STL headers -#ifndef PUGIXML_NO_STL -# include -# include -# include -#endif - -// Macro for deprecated features -#ifndef PUGIXML_DEPRECATED -# if defined(__GNUC__) -# define PUGIXML_DEPRECATED __attribute__((deprecated)) -# elif defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGIXML_DEPRECATED __declspec(deprecated) -# else -# define PUGIXML_DEPRECATED -# endif -#endif - -// If no API is defined, assume default -#ifndef PUGIXML_API -# define PUGIXML_API -#endif - -// If no API for classes is defined, assume default -#ifndef PUGIXML_CLASS -# define PUGIXML_CLASS PUGIXML_API -#endif - -// If no API for functions is defined, assume default -#ifndef PUGIXML_FUNCTION -# define PUGIXML_FUNCTION PUGIXML_API -#endif - -// If the platform is known to have long long support, enable long long functions -#ifndef PUGIXML_HAS_LONG_LONG -# if defined(__cplusplus) && __cplusplus >= 201103 -# define PUGIXML_HAS_LONG_LONG -# elif defined(_MSC_VER) && _MSC_VER >= 1400 -# define PUGIXML_HAS_LONG_LONG -# endif -#endif - -// Character interface macros -#ifdef PUGIXML_WCHAR_MODE -# define PUGIXML_TEXT(t) L ## t -# define PUGIXML_CHAR wchar_t -#else -# define PUGIXML_TEXT(t) t -# define PUGIXML_CHAR char -#endif - -namespace pugi -{ - // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE - typedef PUGIXML_CHAR char_t; - -#ifndef PUGIXML_NO_STL - // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE - typedef std::basic_string, std::allocator > string_t; -#endif -} - -// The PugiXML namespace -namespace pugi -{ - // Tree node types - enum xml_node_type - { - node_null, // Empty (null) node handle - node_document, // A document tree's absolute root - node_element, // Element tag, i.e. '' - node_pcdata, // Plain character data, i.e. 'text' - node_cdata, // Character data, i.e. '' - node_comment, // Comment tag, i.e. '' - node_pi, // Processing instruction, i.e. '' - node_declaration, // Document declaration, i.e. '' - node_doctype // Document type declaration, i.e. '' - }; - - // Parsing options - - // Minimal parsing mode (equivalent to turning all other flags off). - // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. - const unsigned int parse_minimal = 0x0000; - - // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. - const unsigned int parse_pi = 0x0001; - - // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. - const unsigned int parse_comments = 0x0002; - - // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. - const unsigned int parse_cdata = 0x0004; - - // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. - // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. - const unsigned int parse_ws_pcdata = 0x0008; - - // This flag determines if character and entity references are expanded during parsing. This flag is on by default. - const unsigned int parse_escapes = 0x0010; - - // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. - const unsigned int parse_eol = 0x0020; - - // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. - const unsigned int parse_wconv_attribute = 0x0040; - - // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. - const unsigned int parse_wnorm_attribute = 0x0080; - - // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. - const unsigned int parse_declaration = 0x0100; - - // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. - const unsigned int parse_doctype = 0x0200; - - // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only - // of whitespace is added to the DOM tree. - // This flag is off by default; turning it on may result in slower parsing and more memory consumption. - const unsigned int parse_ws_pcdata_single = 0x0400; - - // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default. - const unsigned int parse_trim_pcdata = 0x0800; - - // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document - // is a valid document. This flag is off by default. - const unsigned int parse_fragment = 0x1000; - - // The default parsing mode. - // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; - - // The full parsing mode. - // Nodes of all types are added to the DOM tree, character/reference entities are expanded, - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. - const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; - - // These flags determine the encoding of input data for XML document - enum xml_encoding - { - encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range - { - public: - typedef It const_iterator; - typedef It iterator; - - xml_object_range(It b, It e): _begin(b), _end(e) - { - } - - It begin() const { return _begin; } - It end() const { return _end; } - - private: - It _begin, _end; - }; - - // Writer interface for node printing (see xml_node::print) - class PUGIXML_CLASS xml_writer - { - public: - virtual ~xml_writer() {} - - // Write memory chunk into stream/file/whatever - virtual void write(const void* data, size_t size) = 0; - }; - - // xml_writer implementation for FILE* - class PUGIXML_CLASS xml_writer_file: public xml_writer - { - public: - // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio - xml_writer_file(void* file); - - virtual void write(const void* data, size_t size); - - private: - void* file; - }; - - #ifndef PUGIXML_NO_STL - // xml_writer implementation for streams - class PUGIXML_CLASS xml_writer_stream: public xml_writer - { - public: - // Construct writer from an output stream object - xml_writer_stream(std::basic_ostream >& stream); - xml_writer_stream(std::basic_ostream >& stream); - - virtual void write(const void* data, size_t size); - - private: - std::basic_ostream >* narrow_stream; - std::basic_ostream >* wide_stream; - }; - #endif - - // A light-weight handle for manipulating attributes in DOM tree - class PUGIXML_CLASS xml_attribute - { - friend class xml_attribute_iterator; - friend class xml_node; - - private: - xml_attribute_struct* _attr; - - typedef void (*unspecified_bool_type)(xml_attribute***); - - public: - // Default constructor. Constructs an empty attribute. - xml_attribute(); - - // Constructs attribute from internal pointer - explicit xml_attribute(xml_attribute_struct* attr); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped attribute pointers) - bool operator==(const xml_attribute& r) const; - bool operator!=(const xml_attribute& r) const; - bool operator<(const xml_attribute& r) const; - bool operator>(const xml_attribute& r) const; - bool operator<=(const xml_attribute& r) const; - bool operator>=(const xml_attribute& r) const; - - // Check if attribute is empty - bool empty() const; - - // Get attribute name/value, or "" if attribute is empty - const char_t* name() const; - const char_t* value() const; - - // Get attribute value, or the default value if attribute is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - - // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty - int as_int(int def = 0) const; - unsigned int as_uint(unsigned int def = 0) const; - double as_double(double def = 0) const; - float as_float(float def = 0) const; - - #ifdef PUGIXML_HAS_LONG_LONG - long long as_llong(long long def = 0) const; - unsigned long long as_ullong(unsigned long long def = 0) const; - #endif - - // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty - bool as_bool(bool def = false) const; - - // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") - bool set_value(int rhs); - bool set_value(unsigned int rhs); - bool set_value(double rhs); - bool set_value(float rhs); - bool set_value(bool rhs); - - #ifdef PUGIXML_HAS_LONG_LONG - bool set_value(long long rhs); - bool set_value(unsigned long long rhs); - #endif - - // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(const char_t* rhs); - xml_attribute& operator=(int rhs); - xml_attribute& operator=(unsigned int rhs); - xml_attribute& operator=(double rhs); - xml_attribute& operator=(float rhs); - xml_attribute& operator=(bool rhs); - - #ifdef PUGIXML_HAS_LONG_LONG - xml_attribute& operator=(long long rhs); - xml_attribute& operator=(unsigned long long rhs); - #endif - - // Get next/previous attribute in the attribute list of the parent node - xml_attribute next_attribute() const; - xml_attribute previous_attribute() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_attribute_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); -#endif - - // A light-weight handle for manipulating nodes in DOM tree - class PUGIXML_CLASS xml_node - { - friend class xml_attribute_iterator; - friend class xml_node_iterator; - friend class xml_named_node_iterator; - - protected: - xml_node_struct* _root; - - typedef void (*unspecified_bool_type)(xml_node***); - - public: - // Default constructor. Constructs an empty node. - xml_node(); - - // Constructs node from internal pointer - explicit xml_node(xml_node_struct* p); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators (compares wrapped node pointers) - bool operator==(const xml_node& r) const; - bool operator!=(const xml_node& r) const; - bool operator<(const xml_node& r) const; - bool operator>(const xml_node& r) const; - bool operator<=(const xml_node& r) const; - bool operator>=(const xml_node& r) const; - - // Check if node is empty. - bool empty() const; - - // Get node type - xml_node_type type() const; - - // Get node name, or "" if node is empty or it has no name - const char_t* name() const; - - // Get node value, or "" if node is empty or it has no value - // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. - const char_t* value() const; - - // Get attribute list - xml_attribute first_attribute() const; - xml_attribute last_attribute() const; - - // Get children list - xml_node first_child() const; - xml_node last_child() const; - - // Get next/previous sibling in the children list of the parent node - xml_node next_sibling() const; - xml_node previous_sibling() const; - - // Get parent node - xml_node parent() const; - - // Get root of DOM tree this node belongs to - xml_node root() const; - - // Get text object for the current node - xml_text text() const; - - // Get child, attribute or next/previous sibling with the specified name - xml_node child(const char_t* name) const; - xml_attribute attribute(const char_t* name) const; - xml_node next_sibling(const char_t* name) const; - xml_node previous_sibling(const char_t* name) const; - - // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA - const char_t* child_value() const; - - // Get child value of child with specified name. Equivalent to child(name).child_value(). - const char_t* child_value(const char_t* name) const; - - // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); - - // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(const char_t* name); - xml_attribute prepend_attribute(const char_t* name); - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); - - // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. - xml_attribute append_copy(const xml_attribute& proto); - xml_attribute prepend_copy(const xml_attribute& proto); - xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); - xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); - - // Add child node with specified type. Returns added node, or empty node on errors. - xml_node append_child(xml_node_type type = node_element); - xml_node prepend_child(xml_node_type type = node_element); - xml_node insert_child_after(xml_node_type type, const xml_node& node); - xml_node insert_child_before(xml_node_type type, const xml_node& node); - - // Add child element with specified name. Returns added node, or empty node on errors. - xml_node append_child(const char_t* name); - xml_node prepend_child(const char_t* name); - xml_node insert_child_after(const char_t* name, const xml_node& node); - xml_node insert_child_before(const char_t* name, const xml_node& node); - - // Add a copy of the specified node as a child. Returns added node, or empty node on errors. - xml_node append_copy(const xml_node& proto); - xml_node prepend_copy(const xml_node& proto); - xml_node insert_copy_after(const xml_node& proto, const xml_node& node); - xml_node insert_copy_before(const xml_node& proto, const xml_node& node); - - // Move the specified node to become a child of this node. Returns moved node, or empty node on errors. - xml_node append_move(const xml_node& moved); - xml_node prepend_move(const xml_node& moved); - xml_node insert_move_after(const xml_node& moved, const xml_node& node); - xml_node insert_move_before(const xml_node& moved, const xml_node& node); - - // Remove specified attribute - bool remove_attribute(const xml_attribute& a); - bool remove_attribute(const char_t* name); - - // Remove specified child - bool remove_child(const xml_node& n); - bool remove_child(const char_t* name); - - // Parses buffer as an XML document fragment and appends all nodes as children of the current node. - // Copies/converts the buffer, so it may be deleted or changed after the function returns. - // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. - xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Find attribute using predicate. Returns first attribute for which predicate returned true. - template xml_attribute find_attribute(Predicate pred) const - { - if (!_root) return xml_attribute(); - - for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) - if (pred(attrib)) - return attrib; - - return xml_attribute(); - } - - // Find child node using predicate. Returns first child for which predicate returned true. - template xml_node find_child(Predicate pred) const - { - if (!_root) return xml_node(); - - for (xml_node node = first_child(); node; node = node.next_sibling()) - if (pred(node)) - return node; - - return xml_node(); - } - - // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. - template xml_node find_node(Predicate pred) const - { - if (!_root) return xml_node(); - - xml_node cur = first_child(); - - while (cur._root && cur._root != _root) - { - if (pred(cur)) return cur; - - if (cur.first_child()) cur = cur.first_child(); - else if (cur.next_sibling()) cur = cur.next_sibling(); - else - { - while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); - - if (cur._root != _root) cur = cur.next_sibling(); - } - } - - return xml_node(); - } - - // Find child node by attribute name/value - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; - - #ifndef PUGIXML_NO_STL - // Get the absolute node path from root as a text string. - string_t path(char_t delimiter = '/') const; - #endif - - // Search for a node by path consisting of node names and . or .. elements. - xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; - - // Recursively traverse subtree with xml_tree_walker - bool traverse(xml_tree_walker& walker); - - #ifndef PUGIXML_NO_XPATH - // Select single node by evaluating XPath query. Returns first node from the resulting node set. - xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node select_node(const xpath_query& query) const; - - // Select node set by evaluating XPath query - xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node_set select_nodes(const xpath_query& query) const; - - // (deprecated: use select_node instead) Select single node by evaluating XPath query. - xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node select_single_node(const xpath_query& query) const; - - #endif - - // Print subtree using a writer object - void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - - #ifndef PUGIXML_NO_STL - // Print subtree to stream - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; - #endif - - // Child nodes iterators - typedef xml_node_iterator iterator; - - iterator begin() const; - iterator end() const; - - // Attribute iterators - typedef xml_attribute_iterator attribute_iterator; - - attribute_iterator attributes_begin() const; - attribute_iterator attributes_end() const; - - // Range-based for support - xml_object_range children() const; - xml_object_range children(const char_t* name) const; - xml_object_range attributes() const; - - // Get node offset in parsed file/string (in char_t units) for debugging purposes - ptrdiff_t offset_debug() const; - - // Get hash value (unique for handles to the same object) - size_t hash_value() const; - - // Get internal pointer - xml_node_struct* internal_object() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); -#endif - - // A helper for working with text inside PCDATA nodes - class PUGIXML_CLASS xml_text - { - friend class xml_node; - - xml_node_struct* _root; - - typedef void (*unspecified_bool_type)(xml_text***); - - explicit xml_text(xml_node_struct* root); - - xml_node_struct* _data_new(); - xml_node_struct* _data() const; - - public: - // Default constructor. Constructs an empty object. - xml_text(); - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Check if text object is empty - bool empty() const; - - // Get text, or "" if object is empty - const char_t* get() const; - - // Get text, or the default value if object is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - - // Get text as a number, or the default value if conversion did not succeed or object is empty - int as_int(int def = 0) const; - unsigned int as_uint(unsigned int def = 0) const; - double as_double(double def = 0) const; - float as_float(float def = 0) const; - - #ifdef PUGIXML_HAS_LONG_LONG - long long as_llong(long long def = 0) const; - unsigned long long as_ullong(unsigned long long def = 0) const; - #endif - - // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty - bool as_bool(bool def = false) const; - - // Set text (returns false if object is empty or there is not enough memory) - bool set(const char_t* rhs); - - // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") - bool set(int rhs); - bool set(unsigned int rhs); - bool set(double rhs); - bool set(float rhs); - bool set(bool rhs); - - #ifdef PUGIXML_HAS_LONG_LONG - bool set(long long rhs); - bool set(unsigned long long rhs); - #endif - - // Set text (equivalent to set without error checking) - xml_text& operator=(const char_t* rhs); - xml_text& operator=(int rhs); - xml_text& operator=(unsigned int rhs); - xml_text& operator=(double rhs); - xml_text& operator=(float rhs); - xml_text& operator=(bool rhs); - - #ifdef PUGIXML_HAS_LONG_LONG - xml_text& operator=(long long rhs); - xml_text& operator=(unsigned long long rhs); - #endif - - // Get the data node (node_pcdata or node_cdata) for this object - xml_node data() const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); -#endif - - // Child node iterator (a bidirectional iterator over a collection of xml_node) - class PUGIXML_CLASS xml_node_iterator - { - friend class xml_node; - - private: - mutable xml_node _wrap; - xml_node _parent; - - xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_node value_type; - typedef xml_node* pointer; - typedef xml_node& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_node_iterator(); - - // Construct an iterator which points to the specified node - xml_node_iterator(const xml_node& node); - - // Iterator operators - bool operator==(const xml_node_iterator& rhs) const; - bool operator!=(const xml_node_iterator& rhs) const; - - xml_node& operator*() const; - xml_node* operator->() const; - - const xml_node_iterator& operator++(); - xml_node_iterator operator++(int); - - const xml_node_iterator& operator--(); - xml_node_iterator operator--(int); - }; - - // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) - class PUGIXML_CLASS xml_attribute_iterator - { - friend class xml_node; - - private: - mutable xml_attribute _wrap; - xml_node _parent; - - xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_attribute value_type; - typedef xml_attribute* pointer; - typedef xml_attribute& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_attribute_iterator(); - - // Construct an iterator which points to the specified attribute - xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); - - // Iterator operators - bool operator==(const xml_attribute_iterator& rhs) const; - bool operator!=(const xml_attribute_iterator& rhs) const; - - xml_attribute& operator*() const; - xml_attribute* operator->() const; - - const xml_attribute_iterator& operator++(); - xml_attribute_iterator operator++(int); - - const xml_attribute_iterator& operator--(); - xml_attribute_iterator operator--(int); - }; - - // Named node range helper - class PUGIXML_CLASS xml_named_node_iterator - { - friend class xml_node; - - public: - // Iterator traits - typedef ptrdiff_t difference_type; - typedef xml_node value_type; - typedef xml_node* pointer; - typedef xml_node& reference; - - #ifndef PUGIXML_NO_STL - typedef std::bidirectional_iterator_tag iterator_category; - #endif - - // Default constructor - xml_named_node_iterator(); - - // Construct an iterator which points to the specified node - xml_named_node_iterator(const xml_node& node, const char_t* name); - - // Iterator operators - bool operator==(const xml_named_node_iterator& rhs) const; - bool operator!=(const xml_named_node_iterator& rhs) const; - - xml_node& operator*() const; - xml_node* operator->() const; - - const xml_named_node_iterator& operator++(); - xml_named_node_iterator operator++(int); - - const xml_named_node_iterator& operator--(); - xml_named_node_iterator operator--(int); - - private: - mutable xml_node _wrap; - xml_node _parent; - const char_t* _name; - - xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); - }; - - // Abstract tree walker class (see xml_node::traverse) - class PUGIXML_CLASS xml_tree_walker - { - friend class xml_node; - - private: - int _depth; - - protected: - // Get current traversal depth - int depth() const; - - public: - xml_tree_walker(); - virtual ~xml_tree_walker(); - - // Callback that is called when traversal begins - virtual bool begin(xml_node& node); - - // Callback that is called for each node traversed - virtual bool for_each(xml_node& node) = 0; - - // Callback that is called when traversal ends - virtual bool end(xml_node& node); - }; - - // Parsing status, returned as part of xml_parse_result object - enum xml_parse_status - { - status_ok = 0, // No error - - status_file_not_found, // File was not found during load_file() - status_io_error, // Error reading from file/stream - status_out_of_memory, // Could not allocate memory - status_internal_error, // Internal error occurred - - status_unrecognized_tag, // Parser could not determine tag type - - status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction - status_bad_comment, // Parsing error occurred while parsing comment - status_bad_cdata, // Parsing error occurred while parsing CDATA section - status_bad_doctype, // Parsing error occurred while parsing document type declaration - status_bad_pcdata, // Parsing error occurred while parsing PCDATA section - status_bad_start_element, // Parsing error occurred while parsing start element tag - status_bad_attribute, // Parsing error occurred while parsing element attribute - status_bad_end_element, // Parsing error occurred while parsing end element tag - status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) - - status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer) - - status_no_document_element // Parsing resulted in a document without element nodes - }; - - // Parsing result - struct PUGIXML_CLASS xml_parse_result - { - // Parsing status (see xml_parse_status) - xml_parse_status status; - - // Last parsed offset (in char_t units from start of input data) - ptrdiff_t offset; - - // Source document encoding - xml_encoding encoding; - - // Default constructor, initializes object to failed state - xml_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // Document class (DOM tree root) - class PUGIXML_CLASS xml_document: public xml_node - { - private: - char_t* _buffer; - - char _memory[192]; - - // Non-copyable semantics - xml_document(const xml_document&); - const xml_document& operator=(const xml_document&); - - void create(); - void destroy(); - - public: - // Default constructor, makes empty document - xml_document(); - - // Destructor, invalidates all node/attribute handles to this document - ~xml_document(); - - // Removes all nodes, leaving the empty document - void reset(); - - // Removes all nodes, then copies the entire contents of the specified document - void reset(const xml_document& proto); - - #ifndef PUGIXML_NO_STL - // Load document from stream. - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); - #endif - - // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. - xml_parse_result load(const char_t* contents, unsigned int options = parse_default); - - // Load document from zero-terminated string. No encoding conversions are applied. - xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); - - // Load document from file - xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. - xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. - xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). - // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). - xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - - // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). - void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - #ifndef PUGIXML_NO_STL - // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; - #endif - - // Save XML to file - bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - - // Get document element - xml_node document_element() const; - }; - -#ifndef PUGIXML_NO_XPATH - // XPath query return type - enum xpath_value_type - { - xpath_type_none, // Unknown type (query failed to compile) - xpath_type_node_set, // Node set (xpath_node_set) - xpath_type_number, // Number - xpath_type_string, // String - xpath_type_boolean // Boolean - }; - - // XPath parsing result - struct PUGIXML_CLASS xpath_parse_result - { - // Error message (0 if no error) - const char* error; - - // Last parsed offset (in char_t units from string start) - ptrdiff_t offset; - - // Default constructor, initializes object to failed state - xpath_parse_result(); - - // Cast to bool operator - operator bool() const; - - // Get error description - const char* description() const; - }; - - // A single XPath variable - class PUGIXML_CLASS xpath_variable - { - friend class xpath_variable_set; - - protected: - xpath_value_type _type; - xpath_variable* _next; - - xpath_variable(); - - // Non-copyable semantics - xpath_variable(const xpath_variable&); - xpath_variable& operator=(const xpath_variable&); - - public: - // Get variable name - const char_t* name() const; - - // Get variable type - xpath_value_type type() const; - - // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error - bool get_boolean() const; - double get_number() const; - const char_t* get_string() const; - const xpath_node_set& get_node_set() const; - - // Set variable value; no type conversion is performed, false is returned on type mismatch error - bool set(bool value); - bool set(double value); - bool set(const char_t* value); - bool set(const xpath_node_set& value); - }; - - // A set of XPath variables - class PUGIXML_CLASS xpath_variable_set - { - private: - xpath_variable* _data[64]; - - // Non-copyable semantics - xpath_variable_set(const xpath_variable_set&); - xpath_variable_set& operator=(const xpath_variable_set&); - - xpath_variable* find(const char_t* name) const; - - public: - // Default constructor/destructor - xpath_variable_set(); - ~xpath_variable_set(); - - // Add a new variable or get the existing one, if the types match - xpath_variable* add(const char_t* name, xpath_value_type type); - - // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch - bool set(const char_t* name, bool value); - bool set(const char_t* name, double value); - bool set(const char_t* name, const char_t* value); - bool set(const char_t* name, const xpath_node_set& value); - - // Get existing variable by name - xpath_variable* get(const char_t* name); - const xpath_variable* get(const char_t* name) const; - }; - - // A compiled XPath query object - class PUGIXML_CLASS xpath_query - { - private: - void* _impl; - xpath_parse_result _result; - - typedef void (*unspecified_bool_type)(xpath_query***); - - // Non-copyable semantics - xpath_query(const xpath_query&); - xpath_query& operator=(const xpath_query&); - - public: - // Construct a compiled object from XPath expression. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. - explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); - - // Destructor - ~xpath_query(); - - // Get query expression return type - xpath_value_type return_type() const; - - // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - bool evaluate_boolean(const xpath_node& n) const; - - // Evaluate expression as double value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - double evaluate_number(const xpath_node& n) const; - - #ifndef PUGIXML_NO_STL - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - string_t evaluate_string(const xpath_node& n) const; - #endif - - // Evaluate expression as string value in the specified context; performs type conversion if necessary. - // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. - size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; - - // Evaluate expression as node set in the specified context. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. - xpath_node_set evaluate_node_set(const xpath_node& n) const; - - // Evaluate expression as node set in the specified context. - // Return first node in document order, or empty node if node set is empty. - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead. - xpath_node evaluate_node(const xpath_node& n) const; - - // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) - const xpath_parse_result& result() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - }; - - #ifndef PUGIXML_NO_EXCEPTIONS - // XPath exception class - class PUGIXML_CLASS xpath_exception: public std::exception - { - private: - xpath_parse_result _result; - - public: - // Construct exception from parse result - explicit xpath_exception(const xpath_parse_result& result); - - // Get error message - virtual const char* what() const throw(); - - // Get parse result - const xpath_parse_result& result() const; - }; - #endif - - // XPath node class (either xml_node or xml_attribute) - class PUGIXML_CLASS xpath_node - { - private: - xml_node _node; - xml_attribute _attribute; - - typedef void (*unspecified_bool_type)(xpath_node***); - - public: - // Default constructor; constructs empty XPath node - xpath_node(); - - // Construct XPath node from XML node/attribute - xpath_node(const xml_node& node); - xpath_node(const xml_attribute& attribute, const xml_node& parent); - - // Get node/attribute, if any - xml_node node() const; - xml_attribute attribute() const; - - // Get parent of contained node/attribute - xml_node parent() const; - - // Safe bool conversion operator - operator unspecified_bool_type() const; - - // Borland C++ workaround - bool operator!() const; - - // Comparison operators - bool operator==(const xpath_node& n) const; - bool operator!=(const xpath_node& n) const; - }; - -#ifdef __BORLANDC__ - // Borland C++ workaround - bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); - bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); -#endif - - // A fixed-size collection of XPath nodes - class PUGIXML_CLASS xpath_node_set - { - public: - // Collection type - enum type_t - { - type_unsorted, // Not ordered - type_sorted, // Sorted by document order (ascending) - type_sorted_reverse // Sorted by document order (descending) - }; - - // Constant iterator type - typedef const xpath_node* const_iterator; - - // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work - typedef const xpath_node* iterator; - - // Default constructor. Constructs empty set. - xpath_node_set(); - - // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful - xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); - - // Destructor - ~xpath_node_set(); - - // Copy constructor/assignment operator - xpath_node_set(const xpath_node_set& ns); - xpath_node_set& operator=(const xpath_node_set& ns); - - // Get collection type - type_t type() const; - - // Get collection size - size_t size() const; - - // Indexing operator - const xpath_node& operator[](size_t index) const; - - // Collection iterators - const_iterator begin() const; - const_iterator end() const; - - // Sort the collection in ascending/descending order by document order - void sort(bool reverse = false); - - // Get first node in the collection by document order - xpath_node first() const; - - // Check if collection is empty - bool empty() const; - - private: - type_t _type; - - xpath_node _storage; - - xpath_node* _begin; - xpath_node* _end; - - void _assign(const_iterator begin, const_iterator end); - }; -#endif - -#ifndef PUGIXML_NO_STL - // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); - - // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); -#endif - - // Memory allocation function interface; returns pointer to allocated memory or NULL on failure - typedef void* (*allocation_function)(size_t size); - - // Memory deallocation function interface - typedef void (*deallocation_function)(void* ptr); - - // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. - void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); - - // Get current memory management functions - allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); - deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); -} - -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) -namespace std -{ - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); -} -#endif - -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) -namespace std -{ - // Workarounds for (non-standard) iterator category detection - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); -} -#endif - -#endif - -// Make sure implementation is included in header-only mode -// Use macro expansion in #include to work around QMake (QTBUG-11923) -#if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE) -# define PUGIXML_SOURCE "pugixml.cpp" -# include PUGIXML_SOURCE -#endif - -/** - * Copyright (c) 2006-2015 Arseny Kapoulkine - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ diff --git a/addons/ofxProjectGenerator/src/addons/ofAddon.cpp b/addons/ofxProjectGenerator/src/addons/ofAddon.cpp deleted file mode 100644 index 5613ff963a9..00000000000 --- a/addons/ofxProjectGenerator/src/addons/ofAddon.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* - * ofAddon.cpp - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#include "ofAddon.h" -#include "ofUtils.h" -#include "ofFileUtils.h" -#include "Utils.h" -#include "Poco/String.h" -#include "Poco/RegularExpression.h" -#include - -ofAddon::ofAddon(){ - pathToOF = "../../../"; - currentParseState = Unknown; -} - -ofAddon::ConfigParseState ofAddon::stateFromString(string name){ - if(name=="meta") return Meta; - if(name=="common") return Common; - if(name=="linux64") return Linux64; - if(name=="linux") return Linux; - if(name=="win_cb") return WinCB; - if(name=="vs") return VS; - if(name=="linuxarmv6l") return LinuxARMv6; - if(name=="linuxarmv7l") return LinuxARMv7; - if(name=="android/armeabi") return AndroidARMv5; - if(name=="android/armeabi-v7a") return AndroidARMv7; - if(name=="ios") return iOS; - if(name=="osx") return OSX; - return Unknown; -} - -string ofAddon::stateName(ofAddon::ConfigParseState state){ - switch(state){ - case Meta: - return "meta"; - case Common: - return "common"; - case Linux: - return "linux"; - case Linux64: - return "linux64"; - case WinCB: - return "win_cb"; - case VS: - return "vs"; - case LinuxARMv6: - return "linuxarmv6"; - case LinuxARMv7: - return "linuxarmv7"; - case AndroidARMv5: - return "android/armeabi"; - case AndroidARMv7: - return "android/armeabi-v7a"; - case iOS: - return "ios"; - case OSX: - return "osx"; - case Unknown: - default: - return "unknown"; - } - -} - -bool ofAddon::checkCorrectPlatform(ConfigParseState state){ - switch(state){ - case Meta: - return true; - case Common: - return true; - case Linux: - case Linux64: - case WinCB: - case VS: - case LinuxARMv6: - case LinuxARMv7: - case AndroidARMv5: - case AndroidARMv7: - case iOS: - case OSX: - return platform==stateName(state); - case Unknown: - default: - return false; - } -} - - -bool ofAddon::checkCorrectVariable(string variable, ConfigParseState state){ - switch(state){ - case Meta: - return (variable=="ADDON_NAME" || variable=="ADDON_DESCRIPTION" || variable=="ADDON_AUTHOR" || variable=="ADDON_TAGS" || variable=="ADDON_URL"); - case Common: - case Linux: - case Linux64: - case WinCB: - case VS: - case LinuxARMv6: - case LinuxARMv7: - case AndroidARMv5: - case AndroidARMv7: - case iOS: - case OSX: - return (variable == "ADDON_DEPENDENCIES" || variable == "ADDON_INCLUDES" || variable == "ADDON_CFLAGS" || variable == "ADDON_CPPFLAGS" || variable == "ADDON_LDFLAGS" || variable == "ADDON_LIBS" || variable == "ADDON_PKG_CONFIG_LIBRARIES" || - variable == "ADDON_FRAMEWORKS" || variable == "ADDON_SOURCES" || variable == "ADDON_DATA" || variable == "ADDON_LIBS_EXCLUDE" || variable == "ADDON_SOURCES_EXCLUDE" || variable == "ADDON_INCLUDES_EXCLUDE" || variable == "ADDON_DLLS_TO_COPY"); - case Unknown: - default: - return false; - } -} - -void ofAddon::addReplaceString(string & variable, string value, bool addToVariable){ - if(addToVariable) variable += value; - else variable = value; -} - -void ofAddon::addReplaceStringVector(vector & variable, string value, string prefix, bool addToVariable){ - vector values; - if(value.find("\"")!=string::npos){ - values = ofSplitString(value,"\"",true,true); - }else{ - values = ofSplitString(value," ",true,true); - } - - if(!addToVariable) variable.clear(); - Poco::RegularExpression regEX("(?<=\\$\\()[^\\)]*"); - for(int i=0;i<(int)values.size();i++){ - if(values[i]!=""){ - Poco::RegularExpression::Match match; - if(int pos = regEX.match(values[i],match)){ - string varName = values[i].substr(match.offset,match.length); - string varValue; - if(getenv(varName.c_str())){ - varValue = getenv(varName.c_str()); - } - ofStringReplace(values[i],"$("+varName+")",varValue); - cout << varName << endl << values[i] << endl; - } - - if(prefix=="" || values[i].find(pathToOF)==0 || ofFilePath::isAbsolute(values[i])) variable.push_back(values[i]); - else variable.push_back(ofFilePath::join(prefix,values[i])); - } - } -} - -void ofAddon::parseVariableValue(string variable, string value, bool addToValue, string line, int lineNum){ - if(variable == "ADDON_NAME"){ - if(value!=name){ - ofLogError() << "Error parsing " << name << " addon_config.mk" << "\n\t\t" - << "line " << lineNum << ": " << line << "\n\t\t" - << "addon name in filesystem " << name << " doesn't match with addon_config.mk " << value; - } - return; - } - - string addonRelPath = ofFilePath::addTrailingSlash(pathToOF) + "addons/" + name; - - if(variable == "ADDON_DESCRIPTION"){ - addReplaceString(description,value,addToValue); - return; - } - - if(variable == "ADDON_AUTHOR"){ - addReplaceString(author,value,addToValue); - return; - } - - if(variable == "ADDON_TAGS"){ - addReplaceStringVector(tags,value,"",addToValue); - return; - } - - if(variable == "ADDON_URL"){ - addReplaceString(url,value,addToValue); - return; - } - - if(variable == "ADDON_DEPENDENCIES"){ - addReplaceStringVector(dependencies,value,"",addToValue); - } - - if(variable == "ADDON_INCLUDES"){ - addReplaceStringVector(includePaths,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_CFLAGS"){ - addReplaceStringVector(cflags,value,"",addToValue); - } - - if(variable == "ADDON_CPPFLAGS"){ - addReplaceStringVector(cppflags,value,"",addToValue); - } - - if(variable == "ADDON_LDFLAGS"){ - addReplaceStringVector(ldflags,value,"",addToValue); - } - - if(variable == "ADDON_LIBS"){ - addReplaceStringVector(libs,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_DLLS_TO_COPY"){ - addReplaceStringVector(dllsToCopy,value,"",addToValue); - } - - if(variable == "ADDON_PKG_CONFIG_LIBRARIES"){ - addReplaceStringVector(pkgConfigLibs,value,"",addToValue); - } - - if(variable == "ADDON_FRAMEWORKS"){ - addReplaceStringVector(frameworks,value,"",addToValue); - } - - if(variable == "ADDON_SOURCES"){ - addReplaceStringVector(srcFiles,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_C_SOURCES"){ - addReplaceStringVector(csrcFiles,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_CPP_SOURCES"){ - addReplaceStringVector(cppsrcFiles,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_HEADER_SOURCES"){ - addReplaceStringVector(headersrcFiles,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_OBJC_SOURCES"){ - addReplaceStringVector(objcsrcFiles,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_DATA"){ - addReplaceStringVector(data,value,addonRelPath,addToValue); - } - - if(variable == "ADDON_LIBS_EXCLUDE"){ - addReplaceStringVector(excludeLibs,value,"",addToValue); - } - - if(variable == "ADDON_SOURCES_EXCLUDE"){ - addReplaceStringVector(excludeSources,value,"",addToValue); - } - - if(variable == "ADDON_INCLUDES_EXCLUDE"){ - addReplaceStringVector(excludeIncludes,value,"",addToValue); - } -} - -void ofAddon::exclude(vector & variable, vector exclusions){ - for(int i=0;i<(int)exclusions.size();i++){ - string exclusion = exclusions[i]; - //ofStringReplace(exclusion,"/","\\/"); - ofStringReplace(exclusion,"\\","\\\\"); - ofStringReplace(exclusion,".","\\."); - ofStringReplace(exclusion,"%",".*"); - exclusion =".*"+ exclusion; - Poco::RegularExpression regExp(exclusion); - for(int j=0;j<(int)variable.size();j++){ - if(regExp.match(variable[j])){ - variable.erase(variable.begin()+j); - j--; - } - } - } -} - -void ofAddon::parseConfig(){ - ofFile addonConfig(ofFilePath::join(addonPath,"addon_config.mk")); - - if(!addonConfig.exists()) return; - - string line, originalLine; - int lineNum = 0; - while(addonConfig.good()){ - lineNum++; - getline(addonConfig,originalLine); - line = originalLine; - ofStringReplace(line,"\r",""); - ofStringReplace(line,"\n",""); - Poco::trimInPlace(line); - - // discard comments - if(line[0]=='#' || line == ""){ - continue; - } - - // found section? - if(line[line.size()-1]==':'){ - ofStringReplace(line,":",""); - currentParseState = stateFromString(line); - if(currentParseState == Unknown){ - ofLogError() << "Error parsing " << name << " addon_config.mk" << "\n\t\t" - << "line " << lineNum << ": " << originalLine << "\n\t\t" - << "sectionName " << stateName(currentParseState) << " not recognized"; - } - continue; - } - - // found Variable - if(line.find("=")!=string::npos){ - bool addToValue = false; - string variable, value; - vector varValue; - if(line.find("+=")!=string::npos){ - addToValue = true; - varValue = ofSplitString(line,"+="); - }else{ - addToValue = false; - varValue = ofSplitString(line,"="); - } - variable = Poco::trim(varValue[0]); - value = Poco::trim(varValue[1]); - - if(!checkCorrectPlatform(currentParseState)){ - continue; - } - - if(!checkCorrectVariable(variable,currentParseState)){ - ofLogError() << "Error parsing " << name << " addon_config.mk" << "\n\t\t" - << "line " << lineNum << ": " << originalLine << "\n\t\t" - << "variable " << variable << " not recognized for section " << stateName(currentParseState); - continue; - } - parseVariableValue(variable, value, addToValue, originalLine, lineNum); - } - } - - exclude(includePaths,excludeIncludes); - exclude(srcFiles,excludeSources); - exclude(csrcFiles,excludeSources); - exclude(cppsrcFiles,excludeSources); - exclude(objcsrcFiles,excludeSources); - exclude(headersrcFiles,excludeSources); - exclude(libs,excludeLibs); -} - -void ofAddon::fromFS(string path, string platform){ - - - - clear(); - this->platform = platform; - name = ofFilePath::getFileName(path); - addonPath = ofFilePath::join(getAddonsRoot(),name); - - string filePath = path + "/src"; - string ofRootPath = ofFilePath::addTrailingSlash(getOFRoot()); //we need to add a trailing slash for the erase to work properly - - ofLogVerbose() << "in fromFS, trying src " << filePath; - - - getFilesRecursively(filePath, srcFiles); - - for(int i=0;i<(int)srcFiles.size();i++){ - srcFiles[i].erase (srcFiles[i].begin(), srcFiles[i].begin()+ofRootPath.length()); - //ofLogVerbose() << " srcFiles " << srcFiles[i]; - int init = 0; -#ifdef TARGET_WIN32 - int end = srcFiles[i].rfind("\\"); -#else - int end = srcFiles[i].rfind("/"); -#endif - string folder = srcFiles[i].substr(init,end); - srcFiles[i] = pathToOF + srcFiles[i]; - filesToFolders[srcFiles[i]] = folder; - } - - string libsPath = path + "/libs"; - vector < string > libFiles; - - - if (ofDirectory::doesDirectoryExist(libsPath)){ - getLibsRecursively(libsPath, libFiles, libs, platform); - - if (platform == "osx" || platform == "ios"){ - getFrameworksRecursively(libsPath, frameworks, platform); - - } - - } - - - // I need to add libFiles to srcFiles - for (int i = 0; i < (int)libFiles.size(); i++){ - libFiles[i].erase (libFiles[i].begin(), libFiles[i].begin()+ofRootPath.length()); - //ofLogVerbose() << " libFiles " << libFiles[i]; - int init = 0; -#ifdef TARGET_WIN32 - int end = libFiles[i].rfind("\\"); -#else - int end = libFiles[i].rfind("/"); -#endif - if (end > 0){ - string folder = libFiles[i].substr(init,end); - libFiles[i] = pathToOF + libFiles[i]; - srcFiles.push_back(libFiles[i]); - filesToFolders[libFiles[i]] = folder; - } - - } - - for (int i = 0; i < (int)libs.size(); i++){ - - // does libs[] have any path ? let's fix if so. -#ifdef TARGET_WIN32 - int end = libs[i].rfind("\\"); -#else - int end = libs[i].rfind("/"); -#endif - if (end > 0){ - - libs[i].erase (libs[i].begin(), libs[i].begin()+ofRootPath.length()); - libs[i] = pathToOF + libs[i]; - } - - } - - for (int i = 0; i < (int)frameworks.size(); i++){ - - // does libs[] have any path ? let's fix if so. -#ifdef TARGET_WIN32 - int end = frameworks[i].rfind("\\"); -#else - int end = frameworks[i].rfind("/"); -#endif - if (end > 0){ - - frameworks[i].erase (frameworks[i].begin(), frameworks[i].begin()+ofRootPath.length()); - frameworks[i] = pathToOF + frameworks[i]; - } - - } - - - - // get a unique list of the paths that are needed for the includes. - list < string > paths; - for (int i = 0; i < (int)srcFiles.size(); i++){ - size_t found; -#ifdef TARGET_WIN32 - found = srcFiles[i].find_last_of("\\"); -#else - found = srcFiles[i].find_last_of("/"); -#endif - paths.push_back(srcFiles[i].substr(0,found)); - } - - // get every folder in addon/src and addon/libs - - vector < string > libFolders; - ofLogVerbose() << "trying get folders recursively " << (path + "/libs"); - - // the dirList verbosity is crazy, so I'm setting this off for now. - getFoldersRecursively(path + "/libs", libFolders, platform); - vector < string > srcFolders; - getFoldersRecursively(path + "/src", srcFolders, platform); - - for (int i = 0; i < (int)libFolders.size(); i++){ - libFolders[i].erase (libFolders[i].begin(), libFolders[i].begin()+ofRootPath.length()); - libFolders[i] = pathToOF + libFolders[i]; - paths.push_back(libFolders[i]); - } - - for (int i = 0; i < (int)srcFolders.size(); i++){ - srcFolders[i].erase (srcFolders[i].begin(), srcFolders[i].begin()+ofRootPath.length()); - srcFolders[i] = pathToOF + srcFolders[i]; - paths.push_back(srcFolders[i]); - } - - paths.sort(); - paths.unique(); - for (list::iterator it=paths.begin(); it!=paths.end(); ++it){ - includePaths.push_back(*it); - } - - parseConfig(); - -} - -void ofAddon::fromXML(string installXmlName){ - clear(); - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(ofToDataPath(installXmlName).c_str()); - - // this is src to add: - pugi::xpath_node_set add = doc.select_nodes("//add/src/folder/file"); - for (pugi::xpath_node_set::const_iterator it = add.begin(); it != add.end(); ++it){ - pugi::xpath_node node = *it; - //std::cout << "folder name " << node.node().parent().attribute("name").value() << " : "; - //std::cout << "src: " << node.node().child_value() << endl; - } - - - add = doc.select_nodes("//include/path"); - for (pugi::xpath_node_set::const_iterator it = add.begin(); it != add.end(); ++it){ - pugi::xpath_node node = *it; - //std::cout << "include: " << node.node().child_value() << endl; - } - - - add = doc.select_nodes("//link/lib[@compiler='codeblocks']"); - // this has to be smarter I guess... - for (pugi::xpath_node_set::const_iterator it = add.begin(); it != add.end(); ++it){ - pugi::xpath_node node = *it; - //std::cout << "link: " << node.node().child_value() << endl; - } - - -} - - -void ofAddon::clear(){ - filesToFolders.clear(); - srcFiles.clear(); - libs.clear(); - includePaths.clear(); - name.clear(); -} diff --git a/addons/ofxProjectGenerator/src/addons/ofAddon.h b/addons/ofxProjectGenerator/src/addons/ofAddon.h deleted file mode 100644 index 351940c4683..00000000000 --- a/addons/ofxProjectGenerator/src/addons/ofAddon.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ofAddon.h - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#ifndef OFADDON_H_ -#define OFADDON_H_ - -#include -#include "ofConstants.h" - -class ofAddon { - -public: - - ofAddon(); - - void fromFS(string path, string platform); - void fromXML(string installXmlName); - void clear(); - - // this is source files: - map < string, string > filesToFolders; //the addons has had, for each file, - //sometimes a listing of what folder to put it in, such as "addons/ofxOsc/src" - - vector < string > srcFiles; - vector < string > csrcFiles; - vector < string > cppsrcFiles; - vector < string > headersrcFiles; - vector < string > objcsrcFiles; - vector < string > libs; - vector < string > dllsToCopy; - vector < string > includePaths; - - // From addon_config.mk - vector < string > dependencies; - vector < string > cflags; // C_FLAGS - vector < string > cppflags; // CXX_FLAGS - vector < string > ldflags; - vector < string > pkgConfigLibs; // linux only - vector < string > frameworks; // osx only - vector < string > data; - - // metadata - string name; - string description; - string author; - vector tags; - string url; - - - string pathToOF; - - bool operator <(const ofAddon & addon) const{ - return addon.name < name; - } - -private: - - enum ConfigParseState{ - Meta, - Common, - Linux, - Linux64, - WinCB, - VS, - LinuxARMv6, - LinuxARMv7, - AndroidARMv5, - AndroidARMv7, - iOS, - OSX, - Unknown - } currentParseState; - - void parseConfig(); - void parseVariableValue(string variable, string value, bool addToValue, string line, int lineNum); - void addReplaceString(string & variable, string value, bool addToVariable); - void addReplaceStringVector(vector & variable, string value, string prefix, bool addToVariable); - void exclude(vector & variable, vector exclusions); - ConfigParseState stateFromString(string name); - string stateName(ConfigParseState state); - bool checkCorrectVariable(string variable, ConfigParseState state); - bool checkCorrectPlatform(ConfigParseState state); - - string platform; - - vector excludeLibs; - vector excludeSources; - vector excludeIncludes; - - string addonPath; -}; - -#endif /* OFADDON_H_ */ diff --git a/addons/ofxProjectGenerator/src/projects/CBLinuxProject.cpp b/addons/ofxProjectGenerator/src/projects/CBLinuxProject.cpp deleted file mode 100644 index 63d518c9611..00000000000 --- a/addons/ofxProjectGenerator/src/projects/CBLinuxProject.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * CBLinuxProject.cpp - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#include "CBLinuxProject.h" -#include "ofFileUtils.h" -#include "ofLog.h" -#include "Utils.h" - -string CBLinuxProject::LOG_NAME = "CBLinuxProject"; - -void CBLinuxProject::setup() { - templatePath = ofFilePath::join(getOFRoot(),"scripts/linux/template/"+target); -} - -bool CBLinuxProject::createProjectFile(){ - ofDirectory dir(projectDir); - if(!dir.exists()) dir.create(true); - - ofFile project(ofFilePath::join(projectDir, projectName + ".cbp")); - string src = ofFilePath::join(templatePath,"emptyExample_" + target + ".cbp"); - string dst = project.path(); - bool ret; - - if(!project.exists()){ - ret = ofFile::copyFromTo(src,dst); - if(!ret){ - ofLogError(LOG_NAME) << "error copying cbp template from " << src << " to " << dst; - return false; - }else{ - findandreplaceInTexfile(dst, "emptyExample", projectName); - } - } - - ofFile workspace(ofFilePath::join(projectDir, projectName + ".workspace")); - if(!workspace.exists()){ - src = ofFilePath::join(templatePath,"emptyExample_" + target + ".workspace"); - dst = workspace.path(); - ret = ofFile::copyFromTo(src,dst); - if(!ret){ - ofLogError(LOG_NAME) << "error copying workspace template from "<< src << " to " << dst; - return false; - }else{ - findandreplaceInTexfile(dst, "emptyExample", projectName); - } - } - - ofFile makefile(ofFilePath::join(projectDir,"Makefile")); - if(!makefile.exists()){ - src = ofFilePath::join(templatePath,"Makefile"); - dst = makefile.path(); - ret = ofFile::copyFromTo(src,dst); - if(!ret){ - ofLogError(LOG_NAME) << "error copying Makefile template from " << src << " to " << dst; - return false; - } - } - - ofFile config(ofFilePath::join(projectDir,"config.make")); - if(!config.exists()){ - src = ofFilePath::join(templatePath,"config.make"); - dst = config.path(); - ret = ofFile::copyFromTo(src,dst); - if(!ret){ - ofLogError(LOG_NAME) << "error copying config.make template from " << src << " to " << dst; - return false; - } - } - - - // handle the relative roots. - string relRoot = getOFRelPath(ofFilePath::removeTrailingSlash(projectDir)); - if (relRoot != "../../../"){ - string relPath2 = relRoot; - relPath2.erase(relPath2.end()-1); - findandreplaceInTexfile(projectDir + "config.make", "../../..", relPath2); - findandreplaceInTexfile(ofFilePath::join(projectDir , projectName + ".workspace"), "../../../", relRoot); - findandreplaceInTexfile(ofFilePath::join(projectDir , projectName + ".cbp"), "../../../", relRoot); - } - - return true; -} diff --git a/addons/ofxProjectGenerator/src/projects/CBLinuxProject.h b/addons/ofxProjectGenerator/src/projects/CBLinuxProject.h deleted file mode 100644 index beba546a7f7..00000000000 --- a/addons/ofxProjectGenerator/src/projects/CBLinuxProject.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * CBLinuxProject.h - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#ifndef CBLINUXPROJECT_H_ -#define CBLINUXPROJECT_H_ - -#include "ofConstants.h" -#include "ofAddon.h" -#include "CBWinProject.h" - -class CBLinuxProject: public CBWinProject { -public: - - enum Arch{ - Linux, - Linux64 - }; - - void setup(); - - bool createProjectFile(); - void addInclude(string includeName){}; - void addLibrary(string libraryName, LibType libType = RELEASE_LIB){}; - - static string LOG_NAME; - -private: - - Arch arch; -}; - -#endif /* CBLINUXPROJECT_H_ */ diff --git a/addons/ofxProjectGenerator/src/projects/CBWinProject.cpp b/addons/ofxProjectGenerator/src/projects/CBWinProject.cpp deleted file mode 100644 index 84cfde9ed2c..00000000000 --- a/addons/ofxProjectGenerator/src/projects/CBWinProject.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * CBWinProject.cpp - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#include "CBWinProject.h" -#include "ofFileUtils.h" -#include "ofLog.h" -#include "Utils.h" - -string CBWinProject::LOG_NAME = "CBWinProject"; - -void CBWinProject::setup() { - ; -} - -bool CBWinProject::createProjectFile(){ - - string project = projectDir + projectName + ".cbp"; - string workspace = projectDir + projectName + ".workspace"; - - - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.cbp"),project, false, true); - - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.workspace"),workspace, false, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"icon.rc"), projectDir + "icon.rc", false, true); - - //let's do some renaming: - string relRoot = getOFRelPath(ofFilePath::removeTrailingSlash(projectDir)); - - if (relRoot != "../../../"){ - - string relRootWindows = relRoot; - // let's make it windows friendly: - for(int i = 0; i < relRootWindows.length(); i++) { - if( relRootWindows[i] == '/' ) - relRootWindows[i] = '\\'; - } - - findandreplaceInTexfile(workspace, "../../../", relRoot); - findandreplaceInTexfile(project, "../../../", relRoot); - - findandreplaceInTexfile(workspace, "..\\..\\..\\", relRootWindows); - findandreplaceInTexfile(project, "..\\..\\..\\", relRootWindows); - } - - return true; -} - -bool CBWinProject::loadProjectFile(){ - - //project.open(ofFilePath::join(projectDir , projectName + ".cbp")); - - ofFile project(projectDir + projectName + ".cbp"); - if(!project.exists()){ - ofLogError(LOG_NAME) << "error loading" << project.path() << "doesn't exist"; - return false; - } - pugi::xml_parse_result result = doc.load(project); - bLoaded =result.status==pugi::status_ok; - return bLoaded; -} - -bool CBWinProject::saveProjectFile(){ - - findandreplaceInTexfile(ofFilePath::join(projectDir , projectName + ".workspace"),"emptyExample",projectName); - pugi::xpath_node_set title = doc.select_nodes("//Option[@title]"); - if(!title.empty()){ - if(!title[0].node().attribute("title").set_value(projectName.c_str())){ - ofLogError(LOG_NAME) << "can't set title"; - } - } - return doc.save_file((projectDir + projectName + ".cbp").c_str()); -} - -void CBWinProject::addSrc(string srcName, string folder, SrcType type){ - pugi::xml_node node = appendValue(doc, "Unit", "filename", srcName); - if(!node.empty()){ - node.child("Option").attribute("virtualFolder").set_value(folder.c_str()); - } -} - -void CBWinProject::addInclude(string includeName){ - ofLogNotice() << "adding include " << includeName; - appendValue(doc, "Add", "directory", includeName); -} - -void CBWinProject::addLibrary(string libraryName, LibType libType){ - ofLogNotice() << "adding library " << libraryName; - appendValue(doc, "Add", "library", libraryName, true); - // overwriteMultiple for a lib if it's there (so libsorder.make will work) - // this is because we might need to say libosc, then ws2_32 -} - -string CBWinProject::getName(){ - return projectName; -} - -string CBWinProject::getPath(){ - return projectDir; -} diff --git a/addons/ofxProjectGenerator/src/projects/CBWinProject.h b/addons/ofxProjectGenerator/src/projects/CBWinProject.h deleted file mode 100644 index ac83aecdb54..00000000000 --- a/addons/ofxProjectGenerator/src/projects/CBWinProject.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * CBLinuxProject.h - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#ifndef CBWINPROJECT_H_ -#define CBWINPROJECT_H_ - -#include "ofConstants.h" -#include "ofAddon.h" -#include "baseProject.h" - -class CBWinProject: virtual public baseProject { -public: - - void setup(); - - bool createProjectFile(); - bool loadProjectFile(); - bool saveProjectFile(); - - void addSrc(string srcName, string folder, SrcType type=DEFAULT); - void addInclude(string includeName); - void addLibrary(string libraryName, LibType libType = RELEASE_LIB); - - string getName(); - string getPath(); - - static string LOG_NAME; - -private: - -}; - -#endif /* CBLINUXPROJECT_H_ */ diff --git a/addons/ofxProjectGenerator/src/projects/baseProject.cpp b/addons/ofxProjectGenerator/src/projects/baseProject.cpp deleted file mode 100644 index 86cc308b20b..00000000000 --- a/addons/ofxProjectGenerator/src/projects/baseProject.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// -// baseProject.cpp -// projectGenerator -// -// Created by molmol on 3/12/12. -// Copyright (c) 2012 __MyCompanyName__. All rights reserved. -// - -#include "baseProject.h" -#include "ofFileUtils.h" -#include "ofLog.h" - -void baseProject::setup(string _target){ - target = _target; - templatePath = ofFilePath::join(getOFRoot(),"scripts/" + target + "/template/"); - setup(); // call the inherited class setup(), now that target is set. -} - -bool baseProject::create(string path){ - - addons.clear(); - - projectDir = ofFilePath::addTrailingSlash(path); - projectName = ofFilePath::getFileName(path); - bool bDoesDirExist = false; - - ofDirectory project(ofFilePath::join(projectDir,"src")); // this is a directory, really? - if(project.exists()){ - bDoesDirExist = true; - }else{ - ofDirectory project(projectDir); - ofDirectory(ofFilePath::join(templatePath,"src")).copyTo(ofFilePath::join(projectDir,"src")); - ofDirectory(ofFilePath::join(templatePath,"bin")).copyTo(ofFilePath::join(projectDir,"bin")); - } - - // if overwrite then ask for permission... - - bool ret = createProjectFile(); - if(!ret) return false; - - ret = loadProjectFile(); - if(!ret) return false; - - if (bDoesDirExist){ - vector < string > fileNames; - getFilesRecursively(ofFilePath::join(projectDir , "src"), fileNames); - - for (int i = 0; i < (int)fileNames.size(); i++){ - - fileNames[i].erase(fileNames[i].begin(), fileNames[i].begin() + projectDir.length()); - - string first, last; -#ifdef TARGET_WIN32 - splitFromLast(fileNames[i], "\\", first, last); -#else - splitFromLast(fileNames[i], "/", first, last); -#endif - if (fileNames[i] != "src/ofApp.cpp" && - fileNames[i] != "src/ofApp.h" && - fileNames[i] != "src/main.cpp" && - fileNames[i] != "src/ofApp.mm" && - fileNames[i] != "src/main.mm"){ - addSrc(fileNames[i], first); - } - } - -// if( target == "ios" ){ -// getFilesRecursively(ofFilePath::join(projectDir , "bin/data"), fileNames); -// -// for (int i = 0; i < (int)fileNames.size(); i++){ -// fileNames[i].erase(fileNames[i].begin(), fileNames[i].begin() + projectDir.length()); -// -// string first, last; -// splitFromLast(fileNames[i], "/", first, last); -// if (fileNames[i] != "Default.png" && -// fileNames[i] != "src/ofApp.h" && -// fileNames[i] != "src/main.cpp" && -// fileNames[i] != "src/ofApp.mm" && -// fileNames[i] != "src/main.mm"){ -// addSrc(fileNames[i], first); -// } -// } -// } - -#if defined(TARGET_LINUX) || defined(TARGET_OSX) - parseAddons(); -#endif - // get a unique list of the paths that are needed for the includes. - list < string > paths; - vector < string > includePaths; - for (int i = 0; i < (int)fileNames.size(); i++){ - size_t found; - #ifdef TARGET_WIN32 - found = fileNames[i].find_last_of("\\"); - #else - found = fileNames[i].find_last_of("/"); - #endif - paths.push_back(fileNames[i].substr(0,found)); - } - - paths.sort(); - paths.unique(); - for (list::iterator it=paths.begin(); it!=paths.end(); ++it){ - includePaths.push_back(*it); - } - - for (int i = 0; i < includePaths.size(); i++){ - addInclude(includePaths[i]); - } - } - return true; -} - -bool baseProject::save(bool createMakeFile){ - - // only save an addons.make file if requested on ANY platform - // this way we don't thrash the git repo for our examples, but - // we do make the addons.make file for any new projects...that - // way it can be distributed and re-used by others with the PG - - if(createMakeFile){ - ofFile addonsMake(ofFilePath::join(projectDir,"addons.make"), ofFile::WriteOnly); - for(int i = 0; i < addons.size(); i++){ - addonsMake << addons[i].name << endl; - } - } - - return saveProjectFile(); -} - -void baseProject::addAddon(ofAddon & addon){ - for(int i=0;i<(int)addons.size();i++){ - if(addons[i].name==addon.name) return; - } - - addons.push_back(addon); - - for(int i=0;i<(int)addon.includePaths.size();i++){ - ofLogVerbose() << "adding addon include path: " << addon.includePaths[i]; - addInclude(addon.includePaths[i]); - } - for(int i=0;i<(int)addon.libs.size();i++){ - ofLogVerbose() << "adding addon libs: " << addon.libs[i]; - addLibrary(addon.libs[i]); - } - for(int i=0;i<(int)addon.cflags.size();i++){ - ofLogVerbose() << "adding addon cflags: " << addon.cflags[i]; - addCFLAG(addon.cflags[i]); - } - for(int i=0;i<(int)addon.cppflags.size();i++){ - ofLogVerbose() << "adding addon cppflags: " << addon.cppflags[i]; - addCPPFLAG(addon.cppflags[i]); - } - for(int i=0;i<(int)addon.ldflags.size();i++){ - ofLogVerbose() << "adding addon ldflags: " << addon.ldflags[i]; - addLDFLAG(addon.ldflags[i]); - } - for(int i=0;i<(int)addon.srcFiles.size(); i++){ - ofLogVerbose() << "adding addon srcFiles: " << addon.srcFiles[i]; - addSrc(addon.srcFiles[i],addon.filesToFolders[addon.srcFiles[i]]); - } - for(int i=0;i<(int)addon.csrcFiles.size(); i++){ - ofLogVerbose() << "adding addon c srcFiles: " << addon.csrcFiles[i]; - addSrc(addon.csrcFiles[i],addon.filesToFolders[addon.csrcFiles[i]],C); - } - for(int i=0;i<(int)addon.cppsrcFiles.size(); i++){ - ofLogVerbose() << "adding addon cpp srcFiles: " << addon.cppsrcFiles[i]; - addSrc(addon.cppsrcFiles[i],addon.filesToFolders[addon.cppsrcFiles[i]],CPP); - } - for(int i=0;i<(int)addon.objcsrcFiles.size(); i++){ - ofLogVerbose() << "adding addon objc srcFiles: " << addon.objcsrcFiles[i]; - addSrc(addon.objcsrcFiles[i],addon.filesToFolders[addon.objcsrcFiles[i]],OBJC); - } - for(int i=0;i<(int)addon.headersrcFiles.size(); i++){ - ofLogVerbose() << "adding addon header srcFiles: " << addon.headersrcFiles[i]; - addSrc(addon.headersrcFiles[i],addon.filesToFolders[addon.headersrcFiles[i]],HEADER); - } -} - -void baseProject::parseAddons(){ - ofFile addonsMake(ofFilePath::join(projectDir,"addons.make")); - ofBuffer addonsMakeMem; - addonsMake >> addonsMakeMem; - while(!addonsMakeMem.isLastLine()){ - string line = addonsMakeMem.getNextLine(); - if(line[0] == '#') continue; - ofAddon addon; - cout << projectDir << endl; - addon.pathToOF = getOFRelPath(projectDir); - cout << addon.pathToOF << endl; - addon.fromFS(ofFilePath::join(ofFilePath::join(getOFRoot(), "addons"), line),target); - addAddon(addon); - } -} diff --git a/addons/ofxProjectGenerator/src/projects/baseProject.h b/addons/ofxProjectGenerator/src/projects/baseProject.h deleted file mode 100644 index b333addff89..00000000000 --- a/addons/ofxProjectGenerator/src/projects/baseProject.h +++ /dev/null @@ -1,80 +0,0 @@ - - -#pragma once - -#include - -#include "ofAddon.h" -#include "Utils.h" - -class baseProject { - -public: - - enum LibType{ - DEBUG_LIB = 0, - RELEASE_LIB - }; - - enum SrcType{ - DEFAULT, - HEADER, - CPP, - C, - OBJC - }; - - baseProject(){ - bLoaded = false; - }; - - virtual ~baseProject(){}; - - void setup(string _target); - - bool create(string path); - bool save(bool createMakeFile); - - // this shouldn't be called by anyone. call "create(...), save" etc -private: - - virtual void setup()=0; - virtual bool createProjectFile()=0; - virtual bool loadProjectFile()=0; - virtual bool saveProjectFile()=0; - - // virtual void renameProject(); - // this should get called at the end. - -public: - - virtual void addSrc(string srcFile, string folder, SrcType type=DEFAULT) = 0; - virtual void addInclude(string includeName) = 0; - virtual void addLibrary(string libraryName, LibType libType = RELEASE_LIB) = 0; - virtual void addLDFLAG(string ldflag, LibType libType = RELEASE_LIB){} - virtual void addCFLAG(string cflag, LibType libType = RELEASE_LIB){}; // C_FLAGS - virtual void addCPPFLAG(string cppflag, LibType libType = RELEASE_LIB){}; // CXX_FLAGS - - virtual void addAddon(ofAddon & addon); - - string getName() { return projectName;}; - string getPath() { return projectDir; }; - - pugi::xml_document doc; - bool bLoaded; - - string projectDir; - string projectName; - string templatePath; - string target; - -private: - - void parseAddons(); - -protected: - - vector addons; -}; - - diff --git a/addons/ofxProjectGenerator/src/projects/visualStudioProject.cpp b/addons/ofxProjectGenerator/src/projects/visualStudioProject.cpp deleted file mode 100644 index 5cf94e4062c..00000000000 --- a/addons/ofxProjectGenerator/src/projects/visualStudioProject.cpp +++ /dev/null @@ -1,469 +0,0 @@ - - - -#include "visualStudioProject.h" -#include "Utils.h" - -string visualStudioProject::LOG_NAME = "visualStudioProjectFile"; - -void visualStudioProject::setup() { - ; -} - -bool visualStudioProject::createProjectFile(){ - - string project = ofFilePath::join(projectDir,projectName + ".vcxproj"); - string user = ofFilePath::join(projectDir,projectName + ".vcxproj.user"); - string solution = ofFilePath::join(projectDir,projectName + ".sln"); - string filters = ofFilePath::join(projectDir, projectName + ".vcxproj.filters"); - - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.vcxproj"),project,false, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.vcxproj.user"),user, false, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.sln"),solution, false, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.vcxproj.filters"),filters, false, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"icon.rc"), projectDir + "icon.rc", false, true); - - ofFile filterFile(filters); - string temp = filterFile.readToBuffer(); - pugi::xml_parse_result result = filterXmlDoc.load(temp.c_str()); - if (result.status==pugi::status_ok) ofLogVerbose() << "loaded filter "; - else ofLogVerbose() << "problem loading filter "; - - findandreplaceInTexfile(solution,"emptyExample",projectName); - findandreplaceInTexfile(user,"emptyExample",projectName); - findandreplaceInTexfile(project,"emptyExample",projectName); - - string relRoot = getOFRelPath(ofFilePath::removeTrailingSlash(projectDir)); - if (relRoot != "../../../"){ - - string relRootWindows = relRoot; - // let's make it windows friendly: - for(int i = 0; i < relRootWindows.length(); i++) { - if( relRootWindows[i] == '/' ) - relRootWindows[i] = '\\'; - } - - // sln has windows paths: - findandreplaceInTexfile(solution, "..\\..\\..\\", relRootWindows); - - // vcx has unixy paths: - //..\..\..\libs - findandreplaceInTexfile(project, "..\\..\\..\\", relRoot); - } - - return true; -} - - -bool visualStudioProject::loadProjectFile(){ - - ofFile project(projectDir + projectName + ".vcxproj"); - if(!project.exists()){ - ofLogError(LOG_NAME) << "error loading " << project.path() << " doesn't exist"; - return false; - } - pugi::xml_parse_result result = doc.load(project); - bLoaded = result.status==pugi::status_ok; - return bLoaded; -} - - -bool visualStudioProject::saveProjectFile(){ - - string filters = projectDir + projectName + ".vcxproj.filters"; - filterXmlDoc.save_file(filters.c_str()); - - - return doc.save_file((projectDir + projectName + ".vcxproj").c_str()); -} - - -void visualStudioProject::appendFilter(string folderName){ - - - fixSlashOrder(folderName); - - string uuid = generateUUID(folderName); - - string tag = "//ItemGroup[Filter]/Filter[@Include=\"" + folderName + "\"]"; - pugi::xpath_node_set set = filterXmlDoc.select_nodes(tag.c_str()); - if (set.size() > 0){ - - //pugi::xml_node node = set[0].node(); - } else { - - - pugi::xml_node node = filterXmlDoc.select_single_node("//ItemGroup[Filter]/Filter").node().parent(); - pugi::xml_node nodeAdded = node.append_child("Filter"); - nodeAdded.append_attribute("Include").set_value(folderName.c_str()); - pugi::xml_node nodeAdded2 = nodeAdded.append_child("UniqueIdentifier"); - - uuid.insert(8,"-"); - uuid.insert(8+4+1,"-"); - uuid.insert(8+4+4+2,"-"); - uuid.insert(8+4+4+4+3,"-"); - - //d8376475-7454-4a24-b08a-aac121d3ad6f - - string uuidAltered = "{" + uuid + "}"; - nodeAdded2.append_child(pugi::node_pcdata).set_value(uuidAltered.c_str()); - } -} - -void visualStudioProject::addSrc(string srcFile, string folder, SrcType type){ - - fixSlashOrder(folder); - fixSlashOrder(srcFile); - - vector < string > folderSubNames = ofSplitString(folder, "\\"); - string folderName = ""; - for (int i = 0; i < folderSubNames.size(); i++){ - if (i != 0) folderName += "\\"; - folderName += folderSubNames[i]; - appendFilter(folderName); - } - - if(type==DEFAULT){ - if (ofIsStringInString(srcFile, ".h") || ofIsStringInString(srcFile, ".hpp")){ - appendValue(doc, "ClInclude", "Include", srcFile); - - pugi::xml_node node = filterXmlDoc.select_single_node("//ItemGroup[ClInclude]").node(); - pugi::xml_node nodeAdded = node.append_child("ClInclude"); - nodeAdded.append_attribute("Include").set_value(srcFile.c_str()); - nodeAdded.append_child("Filter").append_child(pugi::node_pcdata).set_value(folder.c_str()); - - } else { - appendValue(doc, "ClCompile", "Include", srcFile); - - pugi::xml_node nodeFilters = filterXmlDoc.select_single_node("//ItemGroup[ClCompile]").node(); - pugi::xml_node nodeAdded = nodeFilters.append_child("ClCompile"); - nodeAdded.append_attribute("Include").set_value(srcFile.c_str()); - nodeAdded.append_child("Filter").append_child(pugi::node_pcdata).set_value(folder.c_str()); - } - }else{ - switch(type){ - case CPP:{ - appendValue(doc, "ClCompile", "Include", srcFile); - - pugi::xml_node nodeFilters = filterXmlDoc.select_single_node("//ItemGroup[ClCompile]").node(); - pugi::xml_node nodeAdded = nodeFilters.append_child("ClCompile"); - nodeAdded.append_attribute("Include").set_value(srcFile.c_str()); - nodeAdded.append_child("Filter").append_child(pugi::node_pcdata).set_value(folder.c_str()); - break; - } - case C:{ - pugi::xml_node node = appendValue(doc, "ClCompile", "Include", srcFile); - - if(!node.child("CompileAs")){ - pugi::xml_node compileAs = node.append_child("CompileAs"); - compileAs.append_attribute("Condition").set_value("'$(Configuration)|$(Platform)'=='Debug|Win32'"); - compileAs.set_value("Default"); - - compileAs = node.append_child("CompileAs"); - compileAs.append_attribute("Condition").set_value("'$(Configuration)|$(Platform)'=='Release|Win32'"); - compileAs.set_value("Default"); - } - - pugi::xml_node nodeFilters = filterXmlDoc.select_single_node("//ItemGroup[ClCompile]").node(); - pugi::xml_node nodeAdded = nodeFilters.append_child("ClCompile"); - nodeAdded.append_attribute("Include").set_value(srcFile.c_str()); - nodeAdded.append_child("Filter").append_child(pugi::node_pcdata).set_value(folder.c_str()); - break; - } - case HEADER:{ - appendValue(doc, "ClInclude", "Include", srcFile); - - pugi::xml_node node = filterXmlDoc.select_single_node("//ItemGroup[ClInclude]").node(); - pugi::xml_node nodeAdded = node.append_child("ClInclude"); - nodeAdded.append_attribute("Include").set_value(srcFile.c_str()); - nodeAdded.append_child("Filter").append_child(pugi::node_pcdata).set_value(folder.c_str()); - break; - } - case OBJC:{ - ofLogError() << "objective c type not supported on vs for " << srcFile; - break; - } - default:{ - ofLogError() << "explicit source type " << type << " not supported yet on osx for " << srcFile; - break; - } - } - } - - - -} - -void visualStudioProject::addInclude(string includeName){ - - - fixSlashOrder(includeName); - - pugi::xpath_node_set source = doc.select_nodes("//ClCompile/AdditionalIncludeDirectories"); - for (pugi::xpath_node_set::const_iterator it = source.begin(); it != source.end(); ++it){ - pugi::xpath_node node = *it; - string includes = node.node().first_child().value(); - vector < string > strings = ofSplitString(includes, ";"); - bool bAdd = true; - for (int i = 0; i < (int)strings.size(); i++){ - if (strings[i].compare(includeName) == 0){ - bAdd = false; - } - } - if (bAdd == true){ - strings.push_back(includeName); - string includesNew = unsplitString(strings, ";"); - node.node().first_child().set_value(includesNew.c_str()); - } - - } - //appendValue(doc, "Add", "directory", includeName); -} - -void visualStudioProject::addLibrary(string libraryName, LibType libType){ - - cout << "adding library " << libType << " " << libraryName << endl; - fixSlashOrder(libraryName); - - // ok first, split path and library name. - size_t found = libraryName.find_last_of("\\"); - string libFolder = libraryName.substr(0,found); - string libName = libraryName.substr(found+1); - - // do the path, then the library - - // paths for libraries - pugi::xpath_node_set source = doc.select_nodes("//Link/AdditionalLibraryDirectories"); - for (pugi::xpath_node_set::const_iterator it = source.begin(); it != source.end(); ++it){ - pugi::xpath_node node = *it; - string includes = node.node().first_child().value(); - vector < string > strings = ofSplitString(includes, ";"); - bool bAdd = true; - for (int i = 0; i < (int)strings.size(); i++){ - if (strings[i].compare(libFolder) == 0){ - bAdd = false; - } - } - if (bAdd == true){ - strings.push_back(libFolder); - string libPathsNew = unsplitString(strings, ";"); - node.node().first_child().set_value(libPathsNew.c_str()); - } - } - - // libs - source = doc.select_nodes("//Link/AdditionalDependencies"); - int platformCounter = 0; - for (pugi::xpath_node_set::const_iterator it = source.begin(); it != source.end(); ++it){ - - // still ghetto, but getting better - // TODO: iterate by - // instead of making the weak assumption that VS projects do Debug|Win32 then Release|Win32 - - if(libType != platformCounter){ - platformCounter++; - continue; - } - - pugi::xpath_node node = *it; - string includes = node.node().first_child().value(); - vector < string > strings = ofSplitString(includes, ";"); - bool bAdd = true; - for (int i = 0; i < (int)strings.size(); i++){ - if (strings[i].compare(libName) == 0){ - bAdd = false; - } - } - - if (bAdd == true){ - strings.push_back(libName); - string libsNew = unsplitString(strings, ";"); - node.node().first_child().set_value(libsNew.c_str()); - } - platformCounter++; - - } - -} - -void visualStudioProject::addCFLAG(string cflag, LibType libType){ - pugi::xpath_node_set items = doc.select_nodes("//ItemDefinitionGroup"); - for(int i=0;i this is not great as many - // libs compile with the d somewhere in the middle of the name... - - vector debugLibs; - vector releaseLibs; - - vector possibleReleaseOrDebugOnlyLibs; - - for(int i = 0; i < addon.libs.size(); i++){ - - size_t found = 0; - - // get the full lib name -#ifdef TARGET_WIN32 - found = addon.libs[i].find_last_of("\\"); -#else - found = addon.libs[i].find_last_of("/"); -#endif - - string libName = addon.libs[i].substr(found+1); - // get the first part of a lib name ie., libodd.lib -> libodd OR liboddd.lib -> liboddd - found = libName.find_last_of("."); - string firstPart = libName.substr(0,found); - - // check this lib name against every other lib name - for(int j = 0; j < addon.libs.size(); j++){ - // check if this lib name is contained within another lib name and is not the same name - if(ofIsStringInString(addon.libs[j], firstPart) && addon.libs[i] != addon.libs[j]){ - // if it is then add respecitive libs to debug and release - if(!isInVector(addon.libs[j], debugLibs)){ - //cout << "adding to DEBUG " << addon.libs[j] << endl; - debugLibs.push_back(addon.libs[j]); - } - if(!isInVector(addon.libs[i], releaseLibs)){ - //cout << "adding to RELEASE " << addon.libs[i] << endl; - releaseLibs.push_back(addon.libs[i]); - } - // stop searching - break; - }else{ - // if we only have a release or only have a debug lib - // we'll want to add it to both releaseLibs and debugLibs - // NB: all debug libs will get added to this vector, - // but we catch that once all pairs have been added - // since we cannot guarantee the order of parsing libs - // although this is innefficient it fixes issues on linux - if(!isInVector(addon.libs[i], possibleReleaseOrDebugOnlyLibs)){ - possibleReleaseOrDebugOnlyLibs.push_back(addon.libs[i]); - } - // keep searching... - } - } - } - - for(int i=0;i<(int)possibleReleaseOrDebugOnlyLibs.size();i++){ - if(!isInVector(possibleReleaseOrDebugOnlyLibs[i], debugLibs) && !isInVector(possibleReleaseOrDebugOnlyLibs[i], releaseLibs)){ - ofLogVerbose() << "RELEASE ONLY LIBS FOUND " << possibleReleaseOrDebugOnlyLibs[i] << endl; - debugLibs.push_back(possibleReleaseOrDebugOnlyLibs[i]); - releaseLibs.push_back(possibleReleaseOrDebugOnlyLibs[i]); - } - } - - for(int i=0;i<(int)debugLibs.size();i++){ - ofLogVerbose() << "adding addon debug libs: " << debugLibs[i]; - addLibrary(debugLibs[i], DEBUG_LIB); - } - - for(int i=0;i<(int)releaseLibs.size();i++){ - ofLogVerbose() << "adding addon release libs: " << releaseLibs[i]; - addLibrary(releaseLibs[i], RELEASE_LIB); - } - - for(int i=0;i<(int)addon.srcFiles.size(); i++){ - ofLogVerbose() << "adding addon srcFiles: " << addon.srcFiles[i]; - if(addon.filesToFolders[addon.srcFiles[i]]=="") addon.filesToFolders[addon.srcFiles[i]]="other"; - addSrc(addon.srcFiles[i],addon.filesToFolders[addon.srcFiles[i]]); - } - - for(int i=0;i<(int)addon.csrcFiles.size(); i++){ - ofLogVerbose() << "adding addon c srcFiles: " << addon.csrcFiles[i]; - if(addon.filesToFolders[addon.csrcFiles[i]]=="") addon.filesToFolders[addon.csrcFiles[i]]="other"; - addSrc(addon.csrcFiles[i],addon.filesToFolders[addon.csrcFiles[i]],C); - } - - for(int i=0;i<(int)addon.cppsrcFiles.size(); i++){ - ofLogVerbose() << "adding addon cpp srcFiles: " << addon.cppsrcFiles[i]; - if(addon.filesToFolders[addon.cppsrcFiles[i]]=="") addon.filesToFolders[addon.cppsrcFiles[i]]="other"; - addSrc(addon.cppsrcFiles[i],addon.filesToFolders[addon.cppsrcFiles[i]],C); - } - - for(int i=0;i<(int)addon.headersrcFiles.size(); i++){ - ofLogVerbose() << "adding addon header srcFiles: " << addon.headersrcFiles[i]; - if(addon.filesToFolders[addon.headersrcFiles[i]]=="") addon.filesToFolders[addon.headersrcFiles[i]]="other"; - addSrc(addon.headersrcFiles[i],addon.filesToFolders[addon.headersrcFiles[i]],C); - } - - for(int i=0;i<(int)addon.objcsrcFiles.size(); i++){ - ofLogVerbose() << "adding addon objc srcFiles: " << addon.objcsrcFiles[i]; - if(addon.filesToFolders[addon.objcsrcFiles[i]]=="") addon.filesToFolders[addon.objcsrcFiles[i]]="other"; - addSrc(addon.objcsrcFiles[i],addon.filesToFolders[addon.objcsrcFiles[i]],C); - } - - for(int i=0;i<(int)addon.dllsToCopy.size();i++){ - ofLogVerbose() << "adding addon dlls to bin: " << addon.dllsToCopy[i]; - string dll = ofFilePath::join("addons/" + addon.name, addon.dllsToCopy[i]); - ofFile(ofFilePath::join(getOFRoot(),dll)).copyTo(ofFilePath::join(projectDir,"bin/"),false,true); - } - - for(int i=0;i<(int)addon.cflags.size();i++){ - ofLogVerbose() << "adding addon cflags: " << addon.cflags[i]; - addCFLAG(addon.cflags[i],RELEASE_LIB); - addCFLAG(addon.cflags[i],DEBUG_LIB); - } - - for(int i=0;i<(int)addon.cppflags.size();i++){ - ofLogVerbose() << "adding addon cppflags: " << addon.cppflags[i]; - addCPPFLAG(addon.cppflags[i],RELEASE_LIB); - addCPPFLAG(addon.cppflags[i],DEBUG_LIB); - } -} diff --git a/addons/ofxProjectGenerator/src/projects/visualStudioProject.h b/addons/ofxProjectGenerator/src/projects/visualStudioProject.h deleted file mode 100644 index 8f2fd28f55a..00000000000 --- a/addons/ofxProjectGenerator/src/projects/visualStudioProject.h +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef VSWINPROJECT_H_ -#define VSWINPROJECT_H_ - -#include "ofConstants.h" -#include "ofAddon.h" -#include "baseProject.h" - -class visualStudioProject : public baseProject { - -public: - - void setup(string ofRoot= "../../../"); - - void setup(); - - bool createProjectFile(); - bool loadProjectFile(); - bool saveProjectFile(); - - void addSrc(string srcFile, string folder, SrcType type=DEFAULT); - void addInclude(string includeName); - void addLibrary(string libraryName, LibType libType); - void addCFLAG(string cflag, LibType libType = RELEASE_LIB); // C - void addCPPFLAG(string cppflag, LibType libType = RELEASE_LIB); // C++ - - void addAddon(ofAddon & addon); - - static string LOG_NAME; - - pugi::xml_document filterXmlDoc; - - - void appendFilter(string folderName); - -private: - -}; - -#endif diff --git a/addons/ofxProjectGenerator/src/projects/xcodeProject.cpp b/addons/ofxProjectGenerator/src/projects/xcodeProject.cpp deleted file mode 100644 index 21b6c8cf743..00000000000 --- a/addons/ofxProjectGenerator/src/projects/xcodeProject.cpp +++ /dev/null @@ -1,1046 +0,0 @@ -#include "xcodeProject.h" -#include - - - -/* - -xcode project files are plists but we can convert to xml, using plutil: - -plutil -convert xml1 -o - myproj.xcodeproj/project.pbxproj - -as an XML file, it's very odd and fairly unreadable, which is why this code is pretty gnarly. - -some additional things that might be useful to try in the future: - -(json parsing) http://emilloer.com/2011/08/15/dealing-with-project-dot-pbxproj-in-ruby/ -(objective c) https://github.com/expanz/xcode-editor -(plist c++) https://github.com/animetrics/PlistCpp - -*/ - - - - -// we are going to use POCO for computing the MD5 Hash of file names and paths, etc: - - - -// to add things to the xcode project file, we need some template XML around -// these are common things we'll want to add - -#define STRINGIFY(A) #A - -//----------------------------------------------------------------- -const char PBXGroup[] = -STRINGIFY( - - GROUPUUID - - children - - - isa - PBXGroup - name - GROUPNAME - sourceTree - <group> // or SOURCE_ROOT, etc - - -); - -//----------------------------------------------------------------- -const char PBXFileReference[] = -STRINGIFY( - - FILEUUID - - explicitFileType - FILETYPE - fileEncoding - 30 - isa - PBXFileReference - name - FILENAME - path - FILEPATH - sourceTree - SOURCE_ROOT - - -); - - -//----------------------------------------------------------------- -const char PBXFileReferenceXib[] = -STRINGIFY( - - FILEUUID - - lastKnownFileType - FILETYPE - fileEncoding - 4 - isa - PBXFileReference - name - FILENAME - path - FILEPATH - sourceTree - SOURCE_ROOT - - -); - -//----------------------------------------------------------------- -const char PBXBuildFile[] = -STRINGIFY( - - BUILDUUID - - fileRef - FILEUUID - isa - PBXBuildFile - - -); - -//----------------------------------------------------------------- -const char HeaderSearchPath[] = -STRINGIFY( - - HEADER_SEARCH_PATHS - - $(OF_CORE_HEADERS) - - -); - - -//----------------------------------------------------------------- -const char LDFlags[] = -STRINGIFY( - - OTHER_LDFLAGS - - $(OF_CORE_FRAMEWORKS) $(OF_CORE_LIBS) - - -); - -//----------------------------------------------------------------- -const char CPPFlags[] = -STRINGIFY( - - OTHER_CPLUSPLUSFLAGS - - "-D__MACOSX_CORE__" - "-mtune=native" - - -); - -//----------------------------------------------------------------- -const char CFlags[] = -STRINGIFY( - - OTHER_CFLAGS - - - -); - -const char workspace[] = -STRINGIFY( - - - - - - - -); - - -void xcodeProject::setup(){ - if( target == "osx" ){ - srcUUID = "E4B69E1C0A3A1BDC003C02F2"; - addonUUID = "BB4B014C10F69532006C3DED"; - buildPhaseUUID = "E4B69E200A3A1BDC003C02F2"; - resourcesUUID = ""; - frameworksUUID = "E7E077E715D3B6510020DFD4"; //PBXFrameworksBuildPhase - }else{ - srcUUID = "E4D8936A11527B74007E1F53"; - addonUUID = "BB16F26B0F2B646B00518274"; - buildPhaseUUID = "E4D8936E11527B74007E1F53"; - resourcesUUID = "BB24DD8F10DA77E000E9C588"; - buildPhaseResourcesUUID = "BB24DDCA10DA781C00E9C588"; - frameworksUUID = "E7E077E715D3B6510020DFD4"; //PBXFrameworksBuildPhase // todo: check this? - } -} - - -void xcodeProject::saveScheme(){ - - string schemeFolder = projectDir + projectName + ".xcodeproj" + "/xcshareddata/xcschemes/"; - ofDirectory::removeDirectory(schemeFolder, true); - ofDirectory::createDirectory(schemeFolder, false, true); - - string schemeToD = projectDir + projectName + ".xcodeproj" + "/xcshareddata/xcschemes/" + projectName + " Debug.xcscheme"; - ofFile::copyFromTo(templatePath + "emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Debug.xcscheme", schemeToD); - - string schemeToR = projectDir + projectName + ".xcodeproj" + "/xcshareddata/xcschemes/" + projectName + " Release.xcscheme"; - ofFile::copyFromTo(templatePath + "emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Release.xcscheme", schemeToR); - - findandreplaceInTexfile(schemeToD, "emptyExample", projectName); - findandreplaceInTexfile(schemeToR, "emptyExample", projectName); - - //TODO: do we still need this? - //string xcsettings = projectDir + projectName + ".xcodeproj" + "/xcshareddata/WorkspaceSettings.xcsettings"; - //ofFile::copyFromTo(templatePath + "emptyExample.xcodeproj/xcshareddata/WorkspaceSettings.xcsettings", xcsettings); - -} - - -void xcodeProject::saveWorkspaceXML(){ - - string workspaceFolder = projectDir + projectName + ".xcodeproj" + "/project.xcworkspace/"; - string xcodeProjectWorkspace = workspaceFolder + "contents.xcworkspacedata"; - - ofFile::removeFile(xcodeProjectWorkspace); - ofDirectory::removeDirectory(workspaceFolder, true); - ofDirectory::createDirectory(workspaceFolder, false, true); - ofFile::copyFromTo(templatePath + "/emptyExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata", xcodeProjectWorkspace); - findandreplaceInTexfile(xcodeProjectWorkspace, "PROJECTNAME", projectName); - -} - -void xcodeProject::saveMakefile(){ - string makefile = ofFilePath::join(projectDir,"Makefile"); - ofFile::copyFromTo(templatePath + "Makefile", makefile, true, true); - - string configmake = ofFilePath::join(projectDir,"config.make"); - ofFile::copyFromTo(templatePath + "config.make", configmake, true, true); -} - - -bool xcodeProject::createProjectFile(){ - // todo: some error checking. - - string xcodeProject = ofFilePath::join(projectDir , projectName + ".xcodeproj"); - ofDirectory::removeDirectory(xcodeProject, true); - - ofDirectory xcodeDir(xcodeProject); - xcodeDir.create(true); - xcodeDir.close(); - - ofFile::copyFromTo(ofFilePath::join(templatePath,"emptyExample.xcodeproj/project.pbxproj"), - ofFilePath::join(xcodeProject, "project.pbxproj"), true, true); - - ofFile::copyFromTo(ofFilePath::join(templatePath,"Project.xcconfig"),projectDir, true, true); - - if( target == "osx" ){ - ofFile::copyFromTo(ofFilePath::join(templatePath,"openFrameworks-Info.plist"),projectDir, true, true); - - ofDirectory binDirectory(ofFilePath::join(projectDir, "bin")); - if (!binDirectory.exists()){ - ofDirectory dataDirectory(ofFilePath::join(projectDir, "bin/data")); - dataDirectory.create(true); - } - if(binDirectory.exists()){ - ofDirectory dataDirectory(ofFilePath::join(binDirectory.path(), "data")); - if (!dataDirectory.exists()){ - dataDirectory.create(false); - } - } - - }else{ - ofFile::copyFromTo(ofFilePath::join(templatePath,"ofxiOS-Info.plist"),projectDir, true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"ofxiOS_Prefix.pch"),projectDir, true, true); - - ofDirectory binDirectory(ofFilePath::join(projectDir, "bin")); - if (!binDirectory.exists()){ - ofDirectory dataDirectory(ofFilePath::join(projectDir, "bin/data")); - dataDirectory.create(true); - } - if(binDirectory.exists()){ - ofDirectory dataDirectory(ofFilePath::join(binDirectory.path(), "data")); - if (!dataDirectory.exists()){ - dataDirectory.create(false); - } - } - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default-568h@2x~iphone.png"),projectDir + "/bin/data/Default-568h@2x~iphone.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default.png"),projectDir + "/bin/data/Default.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default@2x.png"),projectDir + "/bin/data/Default@2x.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default@2x~ipad.png"),projectDir + "/bin/data/Default@2x~ipad.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default@2x~iphone.png"),projectDir + "/bin/data/Default@2x~iphone.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default~ipad.png"),projectDir + "/bin/data/Default~ipad.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Default~iphone.png"),projectDir + "/bin/data/Default~iphone.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Icon-72.png"),projectDir + "/bin/data/Icon-72.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Icon-72@2x.png"),projectDir + "/bin/data/Icon-72@2x.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Icon.png"),projectDir + "/bin/data/Icon.png", true, true); - ofFile::copyFromTo(ofFilePath::join(templatePath,"bin/data/Icon@2x.png"),projectDir + "/bin/data/Icon@2x.png", true, true); - } - - // this is for xcode 4 scheme issues. but I'm not sure this is right. - - saveWorkspaceXML(); - saveScheme(); - saveMakefile(); - - // make everything relative the right way. - string relRoot = getOFRelPath(ofFilePath::removeTrailingSlash(projectDir)); - if (relRoot != "../../../"){ - string relPath2 = relRoot; - relPath2.erase(relPath2.end()-1); - findandreplaceInTexfile(projectDir + projectName + ".xcodeproj/project.pbxproj", "../../..", relPath2); - findandreplaceInTexfile(projectDir + "Project.xcconfig", "../../../", relRoot); - findandreplaceInTexfile(projectDir + "Project.xcconfig", "../../..", relPath2); - } - - return true; -} - - - -void xcodeProject::renameProject(){ - - pugi::xpath_node_set uuidSet = doc.select_nodes("//string[contains(.,'emptyExample')]"); - for (pugi::xpath_node_set::const_iterator it = uuidSet.begin(); it != uuidSet.end(); ++it){ - pugi::xpath_node node = *it; - string val = it->node().first_child().value(); - findandreplace(val, "emptyExample", projectName); - it->node().first_child().set_value(val.c_str()); - } -} - - -bool xcodeProject::loadProjectFile(){ - string fileName = projectDir + projectName + ".xcodeproj/project.pbxproj"; - renameProject(); - pugi::xml_parse_result result = doc.load_file(ofToDataPath(fileName).c_str()); - - return result.status==pugi::status_ok; - -} - - - -bool xcodeProject::saveProjectFile(){ - - - - // does this belong here? - - renameProject(); - - // save the project out: - - string fileName = projectDir + projectName + ".xcodeproj/project.pbxproj"; - bool bOk = doc.save_file(ofToDataPath(fileName).c_str()); - - return bOk; - -} - - -bool xcodeProject::findArrayForUUID(string UUID, pugi::xml_node & nodeMe){ - char query[255]; - sprintf(query, "//string[contains(.,'%s')]", UUID.c_str()); - pugi::xpath_node_set uuidSet = doc.select_nodes(query); - for (pugi::xpath_node_set::const_iterator it = uuidSet.begin(); it != uuidSet.end(); ++it){ - pugi::xpath_node node = *it; - if (strcmp(node.node().parent().name(), "array") == 0){ - nodeMe = node.node().parent(); - return true; - } else { - } - } - return false; -} - - - - -pugi::xml_node xcodeProject::findOrMakeFolderSet(pugi::xml_node nodeToAddTo, vector < string > & folders, string pathForHash){ - - - - - char query[255]; - sprintf(query, "//key[contains(.,'%s')]/following-sibling::node()[1]//array/string", nodeToAddTo.previous_sibling().first_child().value()); - pugi::xpath_node_set array = doc.select_nodes(query); - - bool bAnyNodeWithThisName = false; - pugi::xml_node nodeWithThisName; - string name = folders[0]; - - - for (pugi::xpath_node_set::const_iterator it = array.begin(); it != array.end(); ++it){ - - pugi::xpath_node node = *it; - //node.node().first_child().print(std::cout); - - // this long thing checks, is this a pbxgroup, and if so, what's it's name. - // do it once for path and once for name, since ROOT level pbxgroups have a path name. ugh. - - char querypbx[255]; - sprintf(querypbx, "//key[contains(.,'%s')]/following-sibling::node()[1]//string[contains(.,'PBXGroup')]/parent::node()[1]//key[contains(.,'path')]/following-sibling::node()[1]", node.node().first_child().value()); - if (doc.select_single_node(querypbx).node() != NULL){ - - if (strcmp(doc.select_single_node(querypbx).node().first_child().value(), folders[0].c_str()) == 0){ - printf("found matching node \n"); - bAnyNodeWithThisName = true; - nodeWithThisName = doc.select_single_node(querypbx).node().parent(); - } - } - - sprintf(querypbx, "//key[contains(.,'%s')]/following-sibling::node()[1]//string[contains(.,'PBXGroup')]/parent::node()[1]//key[contains(.,'name')]/following-sibling::node()[1]", node.node().first_child().value()); - - if (doc.select_single_node(querypbx).node() != NULL){ - if (strcmp(doc.select_single_node(querypbx).node().first_child().value(), folders[0].c_str()) == 0){ - bAnyNodeWithThisName = true; - nodeWithThisName = doc.select_single_node(querypbx).node().parent(); - } - } - - } - - - - // now, if we have a pbxgroup with the right name, pop this name off the folder set, and keep going. - // else, let's add a folder set, boom. - - if (bAnyNodeWithThisName == false){ - - // make a new UUID - // todo get the full path here somehow... - - pathForHash += "/" + folders[0]; - - string UUID = generateUUID(pathForHash); - - // add a new node - string PBXGroupStr = string(PBXGroup); - findandreplace( PBXGroupStr, "GROUPUUID", UUID); - findandreplace( PBXGroupStr, "GROUPNAME", folders[0]); - - pugi::xml_document pbxDoc; - pugi::xml_parse_result result = pbxDoc.load_buffer(PBXGroupStr.c_str(), strlen(PBXGroupStr.c_str())); - - - nodeWithThisName = doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(pbxDoc.first_child().next_sibling()); - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(pbxDoc.first_child()); - - - - // add to array - char queryArray[255]; - sprintf(queryArray, "//key[contains(.,'%s')]/following-sibling::node()[1]//array", nodeToAddTo.previous_sibling().first_child().value()); - doc.select_single_node(queryArray).node().append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - //array.begin()->node().parent().append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - - - } else { - - pathForHash += "/" + folders[0]; - } - - - folders.erase(folders.begin()); - - if (folders.size() > 0){ - return findOrMakeFolderSet(nodeWithThisName, folders, pathForHash); - } else { - return nodeWithThisName; - } - -} - -// todo: frameworks -// -void xcodeProject::addFramework(string name, string path){ - - - /* - //----------------------------------------------------------------- - const char PBXFileReference[] = - STRINGIFY( - - FILEUUID - - explicitFileType - FILETYPE - fileEncoding - 30 - isa - PBXFileReference - name - FILENAME - path - FILEPATH - sourceTree - SOURCE_ROOT - - - ); - */ - -// FDA58C7417AD2D5A00BC9CD1 -// -// isa -// PBXFileReference -// lastKnownFileType -// wrapper.framework -// name -// AudioToolbox.framework -// path -// ../../../../../../../../System/Library/Frameworks/AudioToolbox.framework -// sourceTree -// <group> -// -// FDA58C7517AD2D5A00BC9CD1 -// -// fileRef -// FDA58C7417AD2D5A00BC9CD1 -// isa -// PBXBuildFile -// -// - - - string buildUUID; - - //----------------------------------------------------------------- - // based on the extension make some choices about what to do: - //----------------------------------------------------------------- - - //bool addToResources = true; - bool addToBuild = true; - - //----------------------------------------------------------------- - // (A) make a FILE REF - //----------------------------------------------------------------- - - string pbxfileref = string(PBXFileReference); - string UUID = generateUUID( name ); - - findandreplace( pbxfileref, "FILEUUID", UUID); - findandreplace( pbxfileref, "FILENAME", name); - findandreplace( pbxfileref, "FILEPATH", path); - findandreplace( pbxfileref, "SOURCE_ROOT", "<group>"); - findandreplace( pbxfileref, "explicitFileType", "lastKnownFileType"); - findandreplace( pbxfileref, "FILETYPE", "wrapper.framework"); - - pugi::xml_document fileRefDoc; - pugi::xml_parse_result result = fileRefDoc.load_buffer(pbxfileref.c_str(), strlen(pbxfileref.c_str())); - - // insert it at - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child().next_sibling()); // UUID FIRST - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child()); // DICT SECOND - - - buildUUID = generateUUID(name + "-build"); - string pbxbuildfile = string(PBXBuildFile); - findandreplace( pbxbuildfile, "FILEUUID", UUID); - findandreplace( pbxbuildfile, "BUILDUUID", buildUUID); - fileRefDoc.load_buffer(pbxbuildfile.c_str(), strlen(pbxbuildfile.c_str())); - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child().next_sibling()); // UUID FIRST - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child()); // DICT SECOND - - - // add it to the system frameworks array.... - pugi::xml_node array; - findArrayForUUID(frameworksUUID, array); // this is the build array (all build refs get added here) - array.append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - - // add it to the build phases... - pugi::xml_node arrayBuild; - findArrayForUUID(frameworksBuildPhaseUUID, arrayBuild); // this is the build array (all build refs get added here) - arrayBuild.append_child("string").append_child(pugi::node_pcdata).set_value(buildUUID.c_str()); - -} - - - - -void xcodeProject::addSrc(string srcFile, string folder, SrcType type){ - - string buildUUID; - - //----------------------------------------------------------------- - // find the extension for the file that's passed in. - //----------------------------------------------------------------- - - size_t found = srcFile.find_last_of("."); - string ext = srcFile.substr(found+1); - - //----------------------------------------------------------------- - // based on the extension make some choices about what to do: - //----------------------------------------------------------------- - - bool addToResources = true; - bool addToBuild = true; - bool addToBuildResource = false; - string fileKind = "file"; - bool bAddFolder = true; - - if(type==DEFAULT){ - if( ext == "cpp" || ext == "cc" || ext =="cxx" ){ - fileKind = "sourcecode.cpp.cpp"; - addToResources = false; - } - else if( ext == "c" ){ - fileKind = "sourcecode.c.c"; - addToResources = false; - } - else if(ext == "h" || ext == "hpp"){ - fileKind = "sourcecode.c.h"; - addToBuild = false; - addToResources = false; - } - else if(ext == "mm" || ext == "m"){ - addToResources = false; - fileKind = "sourcecode.cpp.objcpp"; - } - else if(ext == "xib"){ - fileKind = "file.xib"; - addToBuild = false; - addToBuildResource = true; - addToResources = true; - }else if( target == "ios" ){ - fileKind = "file"; - addToBuild = false; - addToResources = true; - } - }else{ - switch(type){ - case CPP: - fileKind = "sourcecode.cpp.cpp"; - addToResources = false; - break; - case C: - fileKind = "sourcecode.c.c"; - addToResources = false; - break; - case HEADER: - fileKind = "sourcecode.c.h"; - addToBuild = false; - addToResources = false; - break; - case OBJC: - addToResources = false; - fileKind = "sourcecode.cpp.objcpp"; - break; - default: - ofLogError() << "explicit source type " << type << " not supported yet on osx for " << srcFile; - break; - } - } - - if (folder == "src"){ - bAddFolder = false; - } - - //----------------------------------------------------------------- - // (A) make a FILE REF - //----------------------------------------------------------------- - - string pbxfileref = string(PBXFileReference); - if(ext == "xib"){ - pbxfileref = string(PBXFileReferenceXib); - } - - - string UUID = generateUUID(srcFile); // replace with theo's smarter system. - - string name, path; - splitFromLast(srcFile, "/", path, name); - - findandreplace( pbxfileref, "FILENAME", name); - findandreplace( pbxfileref, "FILEPATH", srcFile); - findandreplace( pbxfileref, "FILETYPE", fileKind); - findandreplace( pbxfileref, "FILEUUID", UUID); - - pugi::xml_document fileRefDoc; - pugi::xml_parse_result result = fileRefDoc.load_buffer(pbxfileref.c_str(), strlen(pbxfileref.c_str())); - - // insert it at - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child().next_sibling()); // UUID FIRST - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child()); // DICT SECOND - - //----------------------------------------------------------------- - // (B) BUILD REF - //----------------------------------------------------------------- - - if (addToBuild || addToBuildResource ){ - - buildUUID = generateUUID(srcFile + "-build"); - string pbxbuildfile = string(PBXBuildFile); - findandreplace( pbxbuildfile, "FILEUUID", UUID); - findandreplace( pbxbuildfile, "BUILDUUID", buildUUID); - - fileRefDoc.load_buffer(pbxbuildfile.c_str(), strlen(pbxbuildfile.c_str())); - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child().next_sibling()); // UUID FIRST - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child()); // DICT SECOND - - // add it to the build array. - if( addToBuildResource ){ - pugi::xml_node array; - findArrayForUUID(buildPhaseResourcesUUID, array); // this is the build array (all build refs get added here) - array.append_child("string").append_child(pugi::node_pcdata).set_value(buildUUID.c_str()); - } - if( addToBuild ){ - pugi::xml_node array; - findArrayForUUID(buildPhaseUUID, array); // this is the build array (all build refs get added here) - array.append_child("string").append_child(pugi::node_pcdata).set_value(buildUUID.c_str()); - - } - } - - //----------------------------------------------------------------- - // (C) resrouces - //----------------------------------------------------------------- - - - if (addToResources == true && resourcesUUID != ""){ - - string resUUID = generateUUID(srcFile + "-build"); - string pbxbuildfile = string(PBXBuildFile); - findandreplace( pbxbuildfile, "FILEUUID", UUID); - findandreplace( pbxbuildfile, "BUILDUUID", resUUID); - fileRefDoc.load_buffer(pbxbuildfile.c_str(), strlen(pbxbuildfile.c_str())); - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child().next_sibling()); // UUID FIRST - doc.select_single_node("/plist[1]/dict[1]/dict[2]").node().prepend_copy(fileRefDoc.first_child()); // DICT SECOND - - // add it to the build array. - pugi::xml_node array; - findArrayForUUID(resourcesUUID, array); // this is the build array (all build refs get added here) - array.append_child("string").append_child(pugi::node_pcdata).set_value(resUUID.c_str()); - - } - - - //----------------------------------------------------------------- - // (D) folder - //----------------------------------------------------------------- - - - if (bAddFolder == true){ - - vector < string > folders = ofSplitString(folder, "/", true); - - if (folders.size() > 1){ - if (folders[0] == "src"){ - string xmlStr = "//key[contains(.,'"+srcUUID+"')]/following-sibling::node()[1]"; - - folders.erase(folders.begin()); - pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); - pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, "src"); - nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - - } else if (folders[0] == "addons"){ - string xmlStr = "//key[contains(.,'"+addonUUID+"')]/following-sibling::node()[1]"; - - folders.erase(folders.begin()); - pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); - pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, "addons"); - - nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - - } else { - string xmlStr = "//key[contains(.,'"+srcUUID+"')]/following-sibling::node()[1]"; - - pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); - - // I'm not sure the best way to proceed; - // we should maybe find the rootest level and add it there. - // TODO: fix this. - } - }; - - } else { - - - pugi::xml_node array; - string xmlStr = "//key[contains(.,'"+srcUUID+"')]/following-sibling::node()[1]"; - pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); - node.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - //nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); -} - - -// todo: these three have very duplicate code... please fix up a bit. - -void xcodeProject::addInclude(string includeName){ - - - - - char query[255]; - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'HEADER_SEARCH_PATHS')]/following-sibling::node()[1]"); - pugi::xpath_node_set headerArray = doc.select_nodes(query); - - if (headerArray.size() > 0){ - - for (pugi::xpath_node_set::const_iterator it = headerArray.begin(); it != headerArray.end(); ++it){ - pugi::xpath_node node = *it; - //node.node().print(std::cout); - node.node().append_child("string").append_child(pugi::node_pcdata).set_value(includeName.c_str()); - } - - } else { - - //printf("we don't have HEADER_SEARCH_PATHS, so we're adding them... and calling this function again \n"); - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'buildSettings')]/following-sibling::node()[1]"); - pugi::xpath_node_set dictArray = doc.select_nodes(query); - - - for (pugi::xpath_node_set::const_iterator it = dictArray.begin(); it != dictArray.end(); ++it){ - pugi::xpath_node node = *it; - - //node.node().print(std::cout); - string headerXML = string(HeaderSearchPath); - pugi::xml_document headerDoc; - pugi::xml_parse_result result = headerDoc.load_buffer(headerXML.c_str(), strlen(headerXML.c_str())); - - // insert it at - node.node().prepend_copy(headerDoc.first_child().next_sibling()); // KEY FIRST - node.node().prepend_copy(headerDoc.first_child()); // ARRAY SECOND - - } - - // now that we have it, try again... - addInclude(includeName); - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); - -} - - -void xcodeProject::addLibrary(string libraryName, LibType libType){ - - char query[255]; - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'OTHER_LDFLAGS')]/following-sibling::node()[1]"); - pugi::xpath_node_set headerArray = doc.select_nodes(query); - - - if (headerArray.size() > 0){ - for (pugi::xpath_node_set::const_iterator it = headerArray.begin(); it != headerArray.end(); ++it){ - pugi::xpath_node node = *it; - node.node().append_child("string").append_child(pugi::node_pcdata).set_value(libraryName.c_str()); - } - - } else { - - //printf("we don't have OTHER_LDFLAGS, so we're adding them... and calling this function again \n"); - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'buildSettings')]/following-sibling::node()[1]"); - - pugi::xpath_node_set dictArray = doc.select_nodes(query); - - for (pugi::xpath_node_set::const_iterator it = dictArray.begin(); it != dictArray.end(); ++it){ - pugi::xpath_node node = *it; - - //node.node().print(std::cout); - string ldXML = string(LDFlags); - pugi::xml_document ldDoc; - pugi::xml_parse_result result = ldDoc.load_buffer(ldXML.c_str(), strlen(ldXML.c_str())); - - // insert it at - node.node().prepend_copy(ldDoc.first_child().next_sibling()); // KEY FIRST - node.node().prepend_copy(ldDoc.first_child()); // ARRAY SECOND - - //node.node().print(std::cout); - } - - // now that we have it, try again... - addLibrary(libraryName); - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); -} - -void xcodeProject::addLDFLAG(string ldflag, LibType libType){ - - char query[255]; - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'OTHER_LDFLAGS')]/following-sibling::node()[1]"); - pugi::xpath_node_set headerArray = doc.select_nodes(query); - - - if (headerArray.size() > 0){ - for (pugi::xpath_node_set::const_iterator it = headerArray.begin(); it != headerArray.end(); ++it){ - pugi::xpath_node node = *it; - node.node().append_child("string").append_child(pugi::node_pcdata).set_value(ldflag.c_str()); - } - - } else { - - //printf("we don't have OTHER_LDFLAGS, so we're adding them... and calling this function again \n"); - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'buildSettings')]/following-sibling::node()[1]"); - - pugi::xpath_node_set dictArray = doc.select_nodes(query); - - for (pugi::xpath_node_set::const_iterator it = dictArray.begin(); it != dictArray.end(); ++it){ - pugi::xpath_node node = *it; - - //node.node().print(std::cout); - string ldXML = string(LDFlags); - pugi::xml_document ldDoc; - pugi::xml_parse_result result = ldDoc.load_buffer(ldXML.c_str(), strlen(ldXML.c_str())); - - // insert it at - node.node().prepend_copy(ldDoc.first_child().next_sibling()); // KEY FIRST - node.node().prepend_copy(ldDoc.first_child()); // ARRAY SECOND - - //node.node().print(std::cout); - } - - // now that we have it, try again... - addLDFLAG(ldflag); - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); -} - -void xcodeProject::addCFLAG(string cflag, LibType libType){ - - char query[255]; - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'OTHER_CPLUSPLUSFLAGS')]/following-sibling::node()[1]"); - pugi::xpath_node_set headerArray = doc.select_nodes(query); - - - if (headerArray.size() > 0){ - for (pugi::xpath_node_set::const_iterator it = headerArray.begin(); it != headerArray.end(); ++it){ - pugi::xpath_node node = *it; - node.node().append_child("string").append_child(pugi::node_pcdata).set_value(cflag.c_str()); - } - - } else { - - //printf("we don't have OTHER_LDFLAGS, so we're adding them... and calling this function again \n"); - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'buildSettings')]/following-sibling::node()[1]"); - - pugi::xpath_node_set dictArray = doc.select_nodes(query); - - for (pugi::xpath_node_set::const_iterator it = dictArray.begin(); it != dictArray.end(); ++it){ - pugi::xpath_node node = *it; - - //node.node().print(std::cout); - string ldXML = string(CFlags); - pugi::xml_document ldDoc; - pugi::xml_parse_result result = ldDoc.load_buffer(ldXML.c_str(), strlen(ldXML.c_str())); - - // insert it at - node.node().prepend_copy(ldDoc.first_child().next_sibling()); // KEY FIRST - node.node().prepend_copy(ldDoc.first_child()); // ARRAY SECOND - - //node.node().print(std::cout); - } - - // now that we have it, try again... - addCFLAG(cflag); - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); -} - -void xcodeProject::addCPPFLAG(string cppflag, LibType libType){ - - char query[255]; - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'OTHER_CPLUSPLUSFLAGS')]/following-sibling::node()[1]"); - pugi::xpath_node_set headerArray = doc.select_nodes(query); - - - if (headerArray.size() > 0){ - for (pugi::xpath_node_set::const_iterator it = headerArray.begin(); it != headerArray.end(); ++it){ - pugi::xpath_node node = *it; - node.node().append_child("string").append_child(pugi::node_pcdata).set_value(cppflag.c_str()); - } - - } else { - - //printf("we don't have OTHER_CPLUSPLUSFLAGS, so we're adding them... and calling this function again \n"); - sprintf(query, "//key[contains(.,'baseConfigurationReference')]/parent::node()//key[contains(.,'buildSettings')]/following-sibling::node()[1]"); - - pugi::xpath_node_set dictArray = doc.select_nodes(query); - - for (pugi::xpath_node_set::const_iterator it = dictArray.begin(); it != dictArray.end(); ++it){ - pugi::xpath_node node = *it; - - //node.node().print(std::cout); - string ldXML = string(CPPFlags); - pugi::xml_document ldDoc; - pugi::xml_parse_result result = ldDoc.load_buffer(ldXML.c_str(), strlen(ldXML.c_str())); - - // insert it at - node.node().prepend_copy(ldDoc.first_child().next_sibling()); // KEY FIRST - node.node().prepend_copy(ldDoc.first_child()); // ARRAY SECOND - - //node.node().print(std::cout); - } - - // now that we have it, try again... - addCPPFLAG(cppflag); - } - - //saveFile(projectDir + "/" + projectName + ".xcodeproj" + "/project.pbxproj"); -} - -void xcodeProject::addAddon(ofAddon & addon){ - ofLogNotice() << "adding addon " << addon.name; - for(int i=0;i<(int)addons.size();i++){ - if(addons[i].name==addon.name) return; - } - - addons.push_back(addon); - - for(int i=0;i<(int)addon.includePaths.size();i++){ - ofLogVerbose() << "adding addon include path: " << addon.includePaths[i]; - addInclude(addon.includePaths[i]); - } - for(int i=0;i<(int)addon.libs.size();i++){ - ofLogVerbose() << "adding addon libs: " << addon.libs[i]; - addLibrary(addon.libs[i]); - } - for(int i=0;i<(int)addon.cflags.size();i++){ - ofLogVerbose() << "adding addon cflags: " << addon.cflags[i]; - addCFLAG(addon.cflags[i]); - } - for(int i=0;i<(int)addon.cppflags.size();i++){ - ofLogVerbose() << "adding addon cppflags: " << addon.cppflags[i]; - addCPPFLAG(addon.cppflags[i]); - } - for(int i=0;i<(int)addon.ldflags.size();i++){ - ofLogVerbose() << "adding addon ldflags: " << addon.ldflags[i]; - addLDFLAG(addon.ldflags[i]); - } - for(int i=0;i<(int)addon.srcFiles.size(); i++){ - ofLogVerbose() << "adding addon srcFiles: " << addon.srcFiles[i]; - addSrc(addon.srcFiles[i],addon.filesToFolders[addon.srcFiles[i]]); - } - - ofLogNotice() << "adding " << addon.frameworks.size() << " frameworks"; - for(int i=0;i<(int)addon.frameworks.size(); i++){ - ofLogNotice() << "adding addon frameworks: " << addon.frameworks[i]; - - size_t found=addon.frameworks[i].find('/'); - if (found==std::string::npos){ - addFramework( addon.frameworks[i] + ".framework", "/System/Library/Frameworks/" + addon.frameworks[i] + ".framework"); - } else { - vector < string > pathSplit = ofSplitString(addon.frameworks[i], "/"); - addFramework(pathSplit[pathSplit.size()-1], addon.frameworks[i]); - } - - } - -} diff --git a/addons/ofxProjectGenerator/src/projects/xcodeProject.h b/addons/ofxProjectGenerator/src/projects/xcodeProject.h deleted file mode 100644 index 9a7bed93535..00000000000 --- a/addons/ofxProjectGenerator/src/projects/xcodeProject.h +++ /dev/null @@ -1,60 +0,0 @@ - - -#pragma once - -#include "baseProject.h" - -class xcodeProject : public baseProject { - -public: - - xcodeProject(){}; - - void setup(); - -private: - - bool createProjectFile(); - bool loadProjectFile(); - bool saveProjectFile(); - void saveMakefile(); - -public: - - void addSrc(string srcFile, string folder, SrcType type=DEFAULT); - void addInclude(string includeName); - void addLibrary(string libraryName, LibType libType = RELEASE_LIB); - void addLDFLAG(string ldflag, LibType libType = RELEASE_LIB); - void addCFLAG(string cflag, LibType libType = RELEASE_LIB); // Other C Flags - void addCPPFLAG(string cppflag, LibType libType = RELEASE_LIB); // Other C++ Flags - - // specific to OSX - void addFramework(string name, string path); - - - - void addAddon(ofAddon & addon); - - void saveWorkspaceXML(); - void saveScheme(); - void renameProject(); - - string srcUUID; - string addonUUID; - string resourcesUUID; - string buildPhaseUUID; - string frameworksUUID; - string buildPhaseResourcesUUID; - string frameworksBuildPhaseUUID; - - - pugi::xml_node findOrMakeFolderSet( pugi::xml_node nodeToAddTo, vector < string > & folders, string pathForHash); - pugi::xml_node insertPoint; // where are we inserting items (at the second dict tag, - // /plist[1]/dict[1]/dict[2]) - bool findArrayForUUID(string UUID, pugi::xml_node & nodeMe); - -}; - - - - diff --git a/addons/ofxProjectGenerator/src/utils/Utils.cpp b/addons/ofxProjectGenerator/src/utils/Utils.cpp deleted file mode 100644 index 897cfaba528..00000000000 --- a/addons/ofxProjectGenerator/src/utils/Utils.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Utils.cpp - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#include "Utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Poco/String.h" - -#include "Poco/HMACEngine.h" -#include "Poco/MD5Engine.h" -using Poco::DigestEngine; -using Poco::HMACEngine; -using Poco::MD5Engine; - - - -#ifdef TARGET_WIN32 -#include -#define GetCurrentDir _getcwd -#elif defined(TARGET_LINUX) -#include -#define GetCurrentDir getcwd -#else -#include /* _NSGetExecutablePath */ -#include /* PATH_MAX */ -#endif - - -using namespace Poco; - -#include "ofUtils.h" - - -string StringToUpper(string strToConvert) -{ - std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper); - - return strToConvert; -} - -string generateUUID(string input){ - - std::string passphrase("openFrameworks"); // HMAC needs a passphrase - - HMACEngine hmac(passphrase); // we'll compute a MD5 Hash - hmac.update(input); - - const DigestEngine::Digest& digest = hmac.digest(); // finish HMAC computation and obtain digest - std::string digestString(DigestEngine::digestToHex(digest)); // convert to a string of hexadecimal numbers - - digestString = digestString.substr(0,24); - digestString = StringToUpper(digestString); - return digestString; -} - - - - - -void findandreplace( std::string& tInput, std::string tFind, std::string tReplace ) { - size_t uPos = 0; - size_t uFindLen = tFind.length(); - size_t uReplaceLen = tReplace.length(); - - if( uFindLen == 0 ){ - return; - } - - for( ;(uPos = tInput.find( tFind, uPos )) != std::string::npos; ){ - tInput.replace( uPos, uFindLen, tReplace ); - uPos += uReplaceLen; - } - -} - - -std::string LoadFileAsString(const std::string & fn) -{ - std::ifstream fin(fn.c_str()); - - if(!fin) - { - // throw exception - } - - std::ostringstream oss; - oss << fin.rdbuf(); - - return oss.str(); -} - -void findandreplaceInTexfile (string fileName, std::string tFind, std::string tReplace ){ - if( ofFile::doesFileExist(fileName) ){ - - std::ifstream t(ofToDataPath(fileName).c_str()); - std::stringstream buffer; - buffer << t.rdbuf(); - string bufferStr = buffer.str(); - t.close(); - findandreplace(bufferStr, tFind, tReplace); - ofstream myfile; - myfile.open (ofToDataPath(fileName).c_str()); - myfile << bufferStr; - myfile.close(); - - /* - std::ifstream ifile(ofToDataPath(fileName).c_str(),std::ios::binary); - ifile.seekg(0,std::ios_base::end); - long s=ifile.tellg(); - char *buffer=new char[s]; - ifile.seekg(0); - ifile.read(buffer,s); - ifile.close(); - std::string txt(buffer,s); - delete[] buffer; - findandreplace(txt, tFind, tReplace); - std::ofstream ofile(ofToDataPath(fileName).c_str()); - ofile.write(txt.c_str(),txt.size()); - */ - //return 0; - } else { - ; // some error checking here would be good. - } -} - - - - -bool doesTagAndAttributeExist(pugi::xml_document & doc, string tag, string attribute, string newValue){ - char xpathExpressionExists[1024]; - sprintf(xpathExpressionExists, "//%s[@%s='%s']", tag.c_str(), attribute.c_str(), newValue.c_str()); - //cout < 0){ // for some reason we get nulls here? - // ...delete the existing node - cout << "DELETING: " << node.node().name() << ": " << " " << node.node().attribute(attribute.c_str()).value() << endl; - node.node().parent().remove_child(node.node()); - } - } - - if (!doesTagAndAttributeExist(doc, tag, attribute, newValue)){ - // otherwise, add it please: - char xpathExpression[1024]; - sprintf(xpathExpression, "//%s[@%s]", tag.c_str(), attribute.c_str()); - //cout << xpathExpression << endl; - pugi::xpath_node_set add = doc.select_nodes(xpathExpression); - pugi::xml_node node = add[add.size()-1].node(); - pugi::xml_node nodeAdded = node.parent().append_copy(node); - nodeAdded.attribute(attribute.c_str()).set_value(newValue.c_str()); - return nodeAdded; - }else{ - return pugi::xml_node(); - } - -} - -// todo -- this doesn't use ofToDataPath -- so it's broken a bit. can we fix? -void getFilesRecursively(const string & path, vector < string > & fileNames){ - - ofDirectory dir; - - //ofLogVerbose() << "in getFilesRecursively "<< path << endl; - - dir.listDir(path); - for (int i = 0; i < dir.size(); i++){ - ofFile temp(dir.getFile(i)); - if (dir.getName(i) == ".svn") continue; // ignore svn - if (temp.isFile()){ - fileNames.push_back(dir.getPath(i)); - } else if (temp.isDirectory()){ - getFilesRecursively(dir.getPath(i), fileNames); - } - } - //folderNames.push_back(path); - -} - -static vector platforms; -bool isFolderNotCurrentPlatform(string folderName, string platform){ - if( platforms.size() == 0 ){ - platforms.push_back("osx"); - platforms.push_back("win_cb"); - platforms.push_back("vs"); - platforms.push_back("ios"); - platforms.push_back("linux"); - platforms.push_back("linux64"); - platforms.push_back("android"); - platforms.push_back("iphone"); - } - - for(int i = 0; i < platforms.size(); i++){ - if( folderName == platforms[i] && folderName != platform ){ - return true; - } - } - - return false; -} - -void splitFromLast(string toSplit, string deliminator, string & first, string & second){ - size_t found = toSplit.find_last_of(deliminator.c_str()); - first = toSplit.substr(0,found); - second = toSplit.substr(found+1); -} - -void splitFromFirst(string toSplit, string deliminator, string & first, string & second){ - size_t found = toSplit.find(deliminator.c_str()); - first = toSplit.substr(0,found ); - second = toSplit.substr(found+deliminator.size()); -} - - -void getFoldersRecursively(const string & path, vector < string > & folderNames, string platform){ - ofDirectory dir; - dir.listDir(path); - for (int i = 0; i < dir.size(); i++){ - ofFile temp(dir.getFile(i)); - if (temp.isDirectory() && isFolderNotCurrentPlatform(temp.getFileName(), platform) == false ){ - getFoldersRecursively(dir.getPath(i), folderNames, platform); - } - } - folderNames.push_back(path); -} - - -void getFrameworksRecursively( const string & path, vector < string > & frameworks, string platform){ - - - ofDirectory dir; - dir.listDir(path); - - for (int i = 0; i < dir.size(); i++){ - - ofFile temp(dir.getFile(i)); - - if (temp.isDirectory()){ - //getLibsRecursively(dir.getPath(i), folderNames); - - // on osx, framework is a directory, let's not parse it.... - string ext = ""; - string first = ""; - splitFromLast(dir.getPath(i), ".", first, ext); - if (ext != "framework") - getFrameworksRecursively(dir.getPath(i), frameworks, platform); - else - frameworks.push_back(dir.getPath(i)); - } - - } -} - - - - -void getLibsRecursively(const string & path, vector < string > & libFiles, vector < string > & libLibs, string platform ){ - - - - - if (ofFile::doesFileExist(ofFilePath::join(path, "libsorder.make"))){ - - bool platformFound = false; - -#ifdef TARGET_WIN32 - vector splittedPath = ofSplitString(path,"\\"); -#else - vector splittedPath = ofSplitString(path,"/"); -#endif - - - if(platform!=""){ - for(int j=0;j<(int)splittedPath.size();j++){ - if(splittedPath[j]==platform){ - platformFound = true; - // break; - } - } - } - - - if (platformFound == true){ - vector < string > libsInOrder; - ofFile libsorderMake(ofFilePath::join(path, "libsorder.make")); - ofBuffer libsorderMakeBuff; - libsorderMake >> libsorderMakeBuff; - while(!libsorderMakeBuff.isLastLine() && libsorderMakeBuff.size() > 0){ - string line = libsorderMakeBuff.getNextLine(); - if (ofFile::doesFileExist(ofFilePath::join(path , line))){ - - libLibs.push_back(ofFilePath::join(path , line) ); - } else { - libLibs.push_back(line); // this might be something like ws2_32 or other libs no in this project - } - } - } - - } else { - - - ofDirectory dir; - dir.listDir(path); - - - for (int i = 0; i < dir.size(); i++){ - -#ifdef TARGET_WIN32 - vector splittedPath = ofSplitString(dir.getPath(i),"\\"); -#else - vector splittedPath = ofSplitString(dir.getPath(i),"/"); -#endif - - ofFile temp(dir.getFile(i)); - - if (temp.isDirectory()){ - //getLibsRecursively(dir.getPath(i), folderNames); - - // on osx, framework is a directory, let's not parse it.... - string ext = ""; - string first = ""; - splitFromLast(dir.getPath(i), ".", first, ext); - if (ext != "framework") - getLibsRecursively(dir.getPath(i), libFiles, libLibs, platform); - - } else { - - - bool platformFound = false; - - if(platform!=""){ - for(int j=0;j<(int)splittedPath.size();j++){ - if(splittedPath[j]==platform){ - platformFound = true; - } - } - } - - - - - //string ext = ofFilePath::getFileExt(temp.getFile(i)); - string ext; - string first; - splitFromLast(dir.getPath(i), ".", first, ext); - - if (ext == "a" || ext == "lib" || ext == "dylib" || ext == "so" || ext == "dll"){ - if (platformFound){ - libLibs.push_back(dir.getPath(i)); - - //TODO: THEO hack - if( platform == "ios" ){ //this is so we can add the osx libs for the simulator builds - - string currentPath = dir.getPath(i); - - //TODO: THEO double hack this is why we need install.xml - custom ignore ofxOpenCv - if( currentPath.find("ofxOpenCv") == string::npos ){ - ofStringReplace(currentPath, "ios", "osx"); - if( ofFile::doesFileExist(currentPath) ){ - libLibs.push_back(currentPath); - } - } - } - } - } else if (ext == "h" || ext == "hpp" || ext == "c" || ext == "cpp" || ext == "cc" || ext == "cxx" || ext == "m" || ext == "mm"){ - libFiles.push_back(dir.getPath(i)); - } - - } - } - - } - - - - //folderNames.push_back(path); - - - - // DirectoryIterator end; - // for (DirectoryIterator it(path); it != end; ++it){ - // if (!it->isDirectory()){ - // string ext = ofFilePath::getFileExt(it->path()); - // vector splittedPath = ofSplitString(ofFilePath::getEnclosingDirectory(it->path()),"/"); - // - // if (ext == "a" || ext == "lib" || ext == "dylib" || ext == "so"){ - // - // if(platform!=""){ - // bool platformFound = false; - // for(int i=0;i<(int)splittedPath.size();i++){ - // if(splittedPath[i]==platform){ - // platformFound = true; - // break; - // } - // } - // if(!platformFound){ - // continue; - // } - // } - // libLibs.push_back(it->path()); - // } else if (ext == "h" || ext == "hpp" || ext == "c" || ext == "cpp" || ext == "cc"){ - // libFiles.push_back(it->path()); - // } - // } - // - // if (it->isDirectory()){ - // getLibsRecursively(it->path(), libFiles, libLibs, platform); - // } - // } - -} - - - -void fixSlashOrder(string & toFix){ - std::replace(toFix.begin(), toFix.end(),'/', '\\'); -} - - -string unsplitString (vector < string > strings, string deliminator ){ - string result; - for (int i = 0; i < (int)strings.size(); i++){ - if (i != 0) result += deliminator; - result += strings[i]; - } - return result; -} - - -static string OFRoot = "../../.."; - -string getOFRoot(){ - return ofFilePath::removeTrailingSlash(OFRoot); -} - -string getAddonsRoot(){ - return ofFilePath::join(getOFRoot(), "addons"); -} - -void setOFRoot(string path){ - OFRoot = path; -} - -string getOFRelPath(string from){ - from = ofFilePath::removeTrailingSlash(from); - Poco::Path base(true); - base.parse(from); - - Poco::Path path; - path.parse( getOFRoot() ); - path.makeAbsolute(); - - - string relPath; - if (path.toString() == base.toString()){ - // do something. - } - - int maxx = MAX(base.depth(), path.depth()); - for (int i = 0; i <= maxx; i++){ - - bool bRunOut = false; - bool bChanged = false; - if (i <= base.depth() && i <= path.depth()){ - if (base.directory(i) == path.directory(i)){ - - } else { - bChanged = true; - } - } else { - bRunOut = true; - } - - - if (bRunOut == true || bChanged == true){ - for (int j = i; j <= base.depth(); j++){ - relPath += "../"; - } - for (int j = i; j <= path.depth(); j++){ - relPath += path.directory(j) + "/"; - } - break; - } - } - - ofLogVerbose() << "returning path " << relPath << endl; - - return relPath; -} - -void parseAddonsDotMake(string path, vector < string > & addons){ - - addons.clear(); - ofFile addonsmake(path); - if(!addonsmake.exists()){ - return; - } - ofBuffer addonsmakebuff; - addonsmake >> addonsmakebuff; - while(!addonsmakebuff.isLastLine() && addonsmakebuff.size() > 0){ - string line = addonsmakebuff.getNextLine(); - if(line!="" && Poco::trim(line)[0]!='#'){ - addons.push_back(line); - } - } -} - -bool checkConfigExists(){ - ofFile config(ofFilePath::join(ofFilePath::getUserHomeDir(),".ofprojectgenerator/config")); - return config.exists(); -} - -bool askOFRoot(){ - ofFileDialogResult res = ofSystemLoadDialog("Select the folder of your openFrameworks install",true); - if (res.fileName == "" || res.filePath == "") return false; - - ofDirectory config(ofFilePath::join(ofFilePath::getUserHomeDir(),".ofprojectgenerator")); - config.create(true); - ofFile configFile(ofFilePath::join(ofFilePath::getUserHomeDir(),".ofprojectgenerator/config"),ofFile::WriteOnly); - configFile << res.filePath; - return true; -} - -string getOFRootFromConfig(){ - if(!checkConfigExists()) return ""; - ofFile configFile(ofFilePath::join(ofFilePath::getUserHomeDir(),".ofprojectgenerator/config"),ofFile::ReadOnly); - ofBuffer filePath = configFile.readToBuffer(); - return filePath.getFirstLine(); -} diff --git a/addons/ofxProjectGenerator/src/utils/Utils.h b/addons/ofxProjectGenerator/src/utils/Utils.h deleted file mode 100644 index d5bb41d6e91..00000000000 --- a/addons/ofxProjectGenerator/src/utils/Utils.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Utils.h - * - * Created on: 28/12/2011 - * Author: arturo - */ - -#ifndef UTILS_H_ -#define UTILS_H_ - -#include "pugixml.hpp" - -#include "ofConstants.h" -#include "ofFileUtils.h" -#include "ofLog.h" -#include "ofUtils.h" -#include "ofSystemUtils.h" - - -string generateUUID(string input); - -string getOFRoot(); -string getAddonsRoot(); -void setOFRoot(string path); -void findandreplace( std::string& tInput, std::string tFind, std::string tReplace ); -void findandreplaceInTexfile (string fileName, string tFind, string tReplace ); - - -bool doesTagAndAttributeExist(pugi::xml_document & doc, string tag, string attribute, string newValue); -pugi::xml_node appendValue(pugi::xml_document & doc, string tag, string attribute, string newValue, bool addMultiple = false); - - - -void getFoldersRecursively(const string & path, vector < string > & folderNames, string platform); -void getFilesRecursively(const string & path, vector < string > & fileNames); -void getLibsRecursively(const string & path, vector < string > & libFiles, vector < string > & libLibs, string platform = "" ); -void getFrameworksRecursively( const string & path, vector < string > & frameworks, string platform = "" ); - - -void splitFromLast(string toSplit, string deliminator, string & first, string & second); -void splitFromFirst(string toSplit, string deliminator, string & first, string & second); - -void parseAddonsDotMake(string path, vector < string > & addons); - -void fixSlashOrder(string & toFix); -string unsplitString (vector < string > strings, string deliminator ); - -string getOFRelPath(string from); - -bool checkConfigExists(); -bool askOFRoot(); -string getOFRootFromConfig(); - -template -inline bool isInVector(T item, vector & vec){ - bool bIsInVector = false; - for(int i=0;iload(entry.filename) ) { diff --git a/addons/ofxUnitTests/src/ofxUnitTests.h b/addons/ofxUnitTests/src/ofxUnitTests.h new file mode 100644 index 00000000000..28633df61d0 --- /dev/null +++ b/addons/ofxUnitTests/src/ofxUnitTests.h @@ -0,0 +1,301 @@ +/* + * ofxUnitTestsApp.h + * + * Created on: Jul 8, 2015 + * Author: arturo + */ +#pragma once + +#include "ofConstants.h" +#include "ofLog.h" +#include "ofBaseApp.h" +#include "ofAppRunner.h" +#include + +class ofColorsLoggerChannel: public ofBaseLoggerChannel{ + std::string CON_DEFAULT="\033[0m"; + std::string CON_BOLD="\033[1m"; + std::string CON_RED="\033[31m"; + std::string CON_YELLOW="\033[33m"; + std::string CON_GREEN="\033[32m"; + std::string getColor(ofLogLevel level) const{ + switch(level){ + case OF_LOG_FATAL_ERROR: + case OF_LOG_ERROR: + return CON_RED; + case OF_LOG_WARNING: + return CON_YELLOW; + case OF_LOG_NOTICE: + return CON_GREEN; + default: + return CON_DEFAULT; + } + } + std::string stdOut; + std::string stdErr; +public: + void log(ofLogLevel level, const std::string & module, const std::string & message){ + std::stringstream str; + + str << "[ " << ofGetLogLevelName(level, true) << "] "; + std::cout << "[ " << ofGetLogLevelName(level, true) << "] "; + + if(module != ""){ + str << module << ": "; + std::cout << module << ": "; + } + + str << message << std::endl; + std::cout << CON_BOLD << getColor(level) << message << CON_DEFAULT << std::endl; + + if(level>OF_LOG_WARNING){ + stdErr += str.str(); + }else{ + stdOut += str.str(); + } + } + + void log(ofLogLevel level, const std::string & module, const char* format, ...){ + va_list args; + va_start(args, format); + log(level, module, format, args); + va_end(args); + } + + void log(ofLogLevel level, const std::string & module, const char* format, va_list args){ + auto msg = ofVAArgsToString(format,args); + log(level, module, msg); + } + + std::string getStdOut(){ + return stdOut; + } + + std::string getStdErr(){ + return stdErr; + } +}; + +class ofAppveyorSystemChannel: public ofBaseLoggerChannel{ + + std::string category(ofLogLevel level){ + std::string category; + switch(level){ + case OF_LOG_VERBOSE: + case OF_LOG_NOTICE: + return "Information"; + case OF_LOG_WARNING: + return "Warning"; + default: + return "Error"; + break; + } + } + + std::string stdOut; + std::string stdErr; + +public: + std::string getStdOut(){ + return stdOut; + } + + std::string getStdErr(){ + return stdErr; + } + + void log(ofLogLevel level, const std::string & module, const std::string & message){ + auto msg = message; + if(module!=""){ + msg = module + ": " + msg; + } + stdOut += "[" + ofGetLogLevelName(level) + "]\t\t" + msg + "\n"; + ofSystem("appveyor AddMessage \"" + msg + "\" -Category " + category(level)); + } + + void log(ofLogLevel level, const std::string & module, const char* format, ...){ + va_list args; + va_start(args, format); + log(level, module, format, args); + va_end(args); + } + + void log(ofLogLevel level, const std::string & module, const char* format, va_list args){ + auto msg = ofVAArgsToString(format,args); + log(level, module, msg); + } +}; + +class ofxUnitTestsApp: public ofBaseApp{ + + void setup(){ + ofSetLoggerChannel(logger); + auto then = ofGetElapsedTimeMillis(); + run(); + auto now = ofGetElapsedTimeMillis(); + auto durationMs = now - then; + bool passed = numTestsFailed==0; + if(passed){ + ofLogNotice() << numTestsPassed << "/" << numTestsTotal << " tests passed"; + }else{ + ofLogError() << numTestsFailed << "/" << numTestsTotal << " tests failed"; + } + + ofLogNotice() << "took " << ofToString(durationMs) << "ms"; + if(!reportAppVeyor(passed, durationMs)){ + ++numTestsFailed; + } + ofExit(numTestsFailed); + } + +protected: + + virtual void run() = 0; + + bool do_test(bool test, const std::string & testName, const std::string & msg, const std::string & file, int line){ + numTestsTotal++; + if(test){ + ofLogNotice() << testName << " passed"; + numTestsPassed++; + return true; + }else{ + ofLogError() << testName << " failed " << msg; + ofLogError() << file << ": " << line; + numTestsFailed++; + return false; + } + } + + bool do_test(bool test, const std::string & testName, const std::string & file, int line){ + return this->do_test(test,testName,"",file,line); + } + + template + bool do_test_eq(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & msg, const std::string & file, int line){ + numTestsTotal++; + if(t1==t2){ + ofLogNotice() << testName << " passed"; + numTestsPassed++; + return true; + }else{ + ofLogError() << testName << " failed " << msg; + ofLogError() << "test_eq(" << v1 << ", " << v2 << ")"; + ofLogError() << "value1: " << v1 << " is " << t1; + ofLogError() << "value2: " << v2 << " is " << t2; + ofLogError() << file << ": " << line; + numTestsFailed++; + return false; + } + } + + template + bool do_test_eq(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & file, int line){ + return do_test_eq(t1,t2,v1,v2,testName,"",file,line); + } + + template + bool do_test_gt(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & msg, const std::string & file, int line){ + numTestsTotal++; + if(t1>t2){ + ofLogNotice() << testName << " passed"; + numTestsPassed++; + return true; + }else{ + ofLogError() << testName << " failed " << msg; + ofLogError() << "test_gt(" << v1 << ", " << v2 << ")"; + ofLogError() << "value1: " << v1 << " is " << t1; + ofLogError() << "value2: " << v2 << " is " << t2; + ofLogError() << file << ": " << line; + numTestsFailed++; + return false; + } + } + + template + bool do_test_gt(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & file, int line){ + return do_test_gt(t1,t2,v1,v2,testName,"",file,line); + } + + template + bool do_test_lt(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & msg, const std::string & file, int line){ + numTestsTotal++; + if(t1 + bool do_test_lt(T1 t1, T2 t2, const std::string & v1, const std::string & v2, const std::string & testName, const std::string & file, int line){ + return do_test_lt(t1,t2,v1,v2,testName,"",file,line); + } + +private: + std::string json_var_value(const std::string & var, const std::string & value){ + return "\"" + var + "\": \"" + value + "\""; + } + + bool reportAppVeyor(bool passed, uint64_t durationMs){ + const std::string APPVEYOR_API_URL = "APPVEYOR_API_URL"; + if(ofGetEnv(APPVEYOR_API_URL)!=""){ + //ofSystem("appveyor AddTest -Name " + projectName.string() + " -Framework ofxUnitTests -FileName " + exeName.string() + " -Outcome " + (passed?"Passed":"Failed") + " -Duration " + ofToString(now-then)); + auto projectDir = std::filesystem::canonical(std::filesystem::path(ofFilePath::getCurrentExeDir()) / ".."); + auto projectName = projectDir.stem(); + auto exeName = std::filesystem::path(ofFilePath::getCurrentExePath()).filename(); + auto stdOut = logger->getStdOut(); + ofStringReplace(stdOut, "\\", "\\\\"); + ofStringReplace(stdOut, "\"", "\\\""); + auto stdErr = logger->getStdErr(); + ofStringReplace(stdErr, "\\", "\\\\"); + ofStringReplace(stdErr, "\"", "\\\""); + ofHttpRequest req; + req.headers["Accept"] = "application/json"; + req.headers["Content-type"] = "application/json"; + req.method = ofHttpRequest::POST; + req.url = ofGetEnv(APPVEYOR_API_URL) + "api/tests"; + req.body = + "{ " + + json_var_value("testName", projectName.string()) + ", " + + json_var_value("testFramework", "ofxUnitTests") + ", " + + json_var_value("fileName", exeName.string()) + ", " + + json_var_value("outcome", passed?"Passed":"Failed") + ", " + + json_var_value("durationMilliseconds", ofToString(durationMs)) + ", " + + json_var_value("StdOut", stdOut) + ", " + + json_var_value("StdErr", stdErr) + + "}"; + ofURLFileLoader http; + auto res = http.handleRequest(req); + if(res.status<200 || res.status>=300){ + ofLogError() << "sending to " << req.url; + ofLogError() << res.status << ", " << res.error; + cout << res.data.getText() << endl; + ofLogError() << "for body:"; + cout << req.body << endl; + return false; + }else{ + return true; + } + }else{ + return true; + } + } + + int numTestsTotal = 0; + int numTestsPassed = 0; + int numTestsFailed = 0; + std::shared_ptr logger{new ofColorsLoggerChannel}; +}; + +#define test(x, ...) this->do_test(x,__VA_ARGS__,__FILE__,__LINE__) +#define test_eq(x,y, ...) this->do_test_eq(x,y,# x,# y,__VA_ARGS__,__FILE__,__LINE__) +#define test_gt(x,y, ...) this->do_test_gt(x,y,# x,# y,__VA_ARGS__,__FILE__,__LINE__) +#define test_lt(x,y, ...) this->do_test_lt(x,y,# x,# y,__VA_ARGS__,__FILE__,__LINE__) diff --git a/addons/ofxiOS/src/app/ofAppiOSWindow.h b/addons/ofxiOS/src/app/ofAppiOSWindow.h index b37a632e823..8d7e0121b93 100644 --- a/addons/ofxiOS/src/app/ofAppiOSWindow.h +++ b/addons/ofxiOS/src/app/ofAppiOSWindow.h @@ -31,9 +31,8 @@ #pragma once -#import "ofAppBaseWindow.h" +#include "ofAppBaseWindow.h" #include "ofxiOSConstants.h" -#include "ofWindowSettings.h" class ofiOSWindowSettings: public ofGLESWindowSettings{ public: @@ -47,6 +46,7 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ ,enableHardwareOrientationAnimation(false) ,enableSetupScreen(true) { windowMode = OF_FULLSCREEN; + setupOrientation = OF_ORIENTATION_DEFAULT; glesVersion = 1; } @@ -76,6 +76,7 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ enableHardwareOrientation = iosSettings->enableHardwareOrientation; enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; enableSetupScreen = iosSettings->enableSetupScreen; + setupOrientation = iosSettings->setupOrientation; } else { enableRetina = false; retinaScale = 0; @@ -85,6 +86,7 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ enableHardwareOrientation = false; enableHardwareOrientationAnimation = false; enableSetupScreen = true; + setupOrientation = OF_ORIENTATION_DEFAULT; } } @@ -108,6 +110,7 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ enableHardwareOrientation = iosSettings->enableHardwareOrientation; enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; enableSetupScreen = iosSettings->enableSetupScreen; + setupOrientation = iosSettings->setupOrientation; } } @@ -121,6 +124,8 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ bool enableHardwareOrientation; bool enableHardwareOrientationAnimation; bool enableSetupScreen; + ofOrientation setupOrientation; + }; @@ -141,6 +146,7 @@ class ofAppiOSWindow : public ofAppBaseGLESWindow { void setup(const ofWindowSettings & _settings); void setup(const ofGLESWindowSettings & _settings); void setup(const ofiOSWindowSettings & _settings); + void setup(); void run(ofBaseApp * appPtr); OF_DEPRECATED_MSG("Use setup(const ofiOSWindowSettings & settings); instead.", virtual void setupOpenGL(int w, int h, ofWindowMode screenMode) ); diff --git a/addons/ofxiOS/src/app/ofAppiOSWindow.mm b/addons/ofxiOS/src/app/ofAppiOSWindow.mm index 64724037523..fc943234fff 100644 --- a/addons/ofxiOS/src/app/ofAppiOSWindow.mm +++ b/addons/ofxiOS/src/app/ofAppiOSWindow.mm @@ -29,13 +29,12 @@ * * ***********************************************************************/ -#import "ofMain.h" -#import "ofGLProgrammableRenderer.h" -#import "ofAppiOSWindow.h" -#import "ofxiOSEAGLView.h" -#import "ofxiOSAppDelegate.h" -#import "ofxiOSViewController.h" -#import "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" +#include "ofGLRenderer.h" +#include "ofGLProgrammableRenderer.h" +#include "ofxiOSAppDelegate.h" +#include "ofxiOSViewController.h" +#include "ofxiOSEAGLView.h" //----------------------------------------------------------------------------------- instance. static ofAppiOSWindow * _instance = NULL; @@ -50,15 +49,13 @@ } else { ofLog(OF_LOG_ERROR, "ofAppiOSWindow instantiated more than once"); } - - orientation = OF_ORIENTATION_UNKNOWN; - bRetinaSupportedOnDevice = false; bRetinaSupportedOnDeviceChecked = false; } ofAppiOSWindow::~ofAppiOSWindow() { close(); + _instance = NULL; } void ofAppiOSWindow::close() { @@ -89,11 +86,23 @@ void ofAppiOSWindow::setup(const ofiOSWindowSettings & _settings) { settings = _settings; - if(settings.glesVersion >= ESRendererVersion_20) { - currentRenderer = shared_ptr(new ofGLProgrammableRenderer(this)); - } else { - currentRenderer = shared_ptr(new ofGLRenderer(this)); - } + setup(); +} + +void ofAppiOSWindow::setup() { + + + if(settings.setupOrientation == OF_ORIENTATION_UNKNOWN) { + settings.setupOrientation = OF_ORIENTATION_DEFAULT; + } + setOrientation(settings.setupOrientation); + if(settings.glesVersion >= ESRendererVersion_20) { + currentRenderer = shared_ptr(new ofGLProgrammableRenderer(this)); + } else { + currentRenderer = shared_ptr(new ofGLRenderer(this)); + } + + hasExited = false; } //----------------------------------------------------------------------------------- opengl setup. @@ -398,11 +407,12 @@ return settings.numOfAntiAliasingSamples; } +//----------------------------------------------------------------------------------- ofCoreEvents & ofAppiOSWindow::events(){ return coreEvents; } -//-------------------------------------------- +//----------------------------------------------------------------------------------- shared_ptr & ofAppiOSWindow::renderer(){ return currentRenderer; } diff --git a/addons/ofxiOS/src/app/ofxiOSApp.h b/addons/ofxiOS/src/app/ofxiOSApp.h index 91dac49beb0..75fcff0e3e3 100644 --- a/addons/ofxiOS/src/app/ofxiOSApp.h +++ b/addons/ofxiOS/src/app/ofxiOSApp.h @@ -9,12 +9,10 @@ #pragma once -#include "ofMain.h" -#include "ofEvents.h" +#include "ofBaseApp.h" #include "ofxiOSAlerts.h" -#include "ofxMultiTouch.h" -class ofxiOSApp : public ofSimpleApp, public ofxiOSAlertsListener, public ofxMultiTouchListener { +class ofxiOSApp : public ofBaseApp, public ofxiOSAlertsListener { public: virtual void setup() {}; diff --git a/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm b/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm index a8d937b3a8d..582beedfb6f 100644 --- a/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm +++ b/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm @@ -29,11 +29,14 @@ * * ***********************************************************************/ -#import "ofMain.h" -#import "ofxiOSAppDelegate.h" -#import "ofxiOSViewController.h" -#import "ofxiOSExtras.h" -#import "ofxiOSExternalDisplay.h" +#include "ofxiOSAppDelegate.h" +#include "ofxiOSViewController.h" +#include "ofxiOSExternalDisplay.h" +#include "ofxiOSExtras.h" +#include "ofxiOSAlerts.h" +#include "ofxiOSEAGLView.h" +#include "ofAppiOSWindow.h" +#include "ofAppRunner.h" @implementation ofxiOSAppDelegate @@ -113,43 +116,23 @@ - (void)applicationDidFinishLaunching:(UIApplication *)application { } BOOL bIsPortrait = UIInterfaceOrientationIsPortrait( iOrient ); - + + CGRect frame = [[UIScreen mainScreen] bounds]; + + if( (!bIsPortrait && bDoesHWOrientation)) { + float tWidth = frame.size.width; + float tHeight = frame.size.height; + frame.size.width = tHeight; + frame.size.height = tWidth; + } + + ofOrientation defaultOrient = ofGetOrientation(); + // check if app delegate is being extended. // if not, create a new view controller. NSString * appDelegateClassName = [[self class] description]; if ([appDelegateClassName isEqualToString:@"ofxiOSAppDelegate"]) { // app delegate is not being extended. - CGRect frame = [[UIScreen mainScreen] bounds]; - - if( (!bIsPortrait && bDoesHWOrientation)) { - float tWidth = frame.size.width; - float tHeight = frame.size.height; - frame.size.width = tHeight; - frame.size.height = tWidth; - } - - ofOrientation defaultOrient = OF_ORIENTATION_UNKNOWN; - if(bDoesHWOrientation) { - // update the window orientation based on the orientation of the device // - switch (iOrient) { - case UIInterfaceOrientationPortrait: - defaultOrient = OF_ORIENTATION_DEFAULT; - break; - case UIInterfaceOrientationPortraitUpsideDown: - defaultOrient = OF_ORIENTATION_180; - break; - case UIInterfaceOrientationLandscapeLeft: - defaultOrient = OF_ORIENTATION_90_RIGHT; - break; - case UIInterfaceOrientationLandscapeRight: - defaultOrient = OF_ORIENTATION_90_LEFT; - break; - } - } else { - defaultOrient = OF_ORIENTATION_DEFAULT; - } - - ofSetOrientation(defaultOrient); - + self.glViewController = [[[ofxiOSViewController alloc] initWithFrame:frame app:(ofxiOSApp *)ofGetAppPtr()] autorelease]; self.window.rootViewController = self.glViewController; @@ -186,6 +169,11 @@ - (void)applicationWillResignActive:(UIApplication *)application { [ofxiOSGetGLView() stopAnimation]; ofxiOSAlerts.lostFocus(); + glFinish(); +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + glFinish(); } - (void)applicationDidBecomeActive:(UIApplication *)application { @@ -224,11 +212,15 @@ -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientat - (void)receivedRotate:(NSNotification*)notification { UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation]; ofLogVerbose("ofxiOSAppDelegate") << "device orientation changed to " << deviceOrientation; - if(deviceOrientation != UIDeviceOrientationUnknown && deviceOrientation != UIDeviceOrientationFaceUp && deviceOrientation != UIDeviceOrientationFaceDown ) { - if([self.glViewController isReadyToRotate]) { + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + //iOS7- + if(deviceOrientation != UIDeviceOrientationUnknown && deviceOrientation != UIDeviceOrientationFaceUp && deviceOrientation != UIDeviceOrientationFaceDown ) { + if([self.glViewController isReadyToRotate]) { ofxiOSAlerts.deviceOrientationChanged( deviceOrientation ); - } - + } + } + }else { + ofxiOSAlerts.deviceOrientationChanged( deviceOrientation ); } } @@ -243,7 +235,6 @@ - (void)receivedRotate:(NSNotification*)notification { */ - (void)handleScreenConnectNotification:(NSNotification*)aNotification { - [self createExternalWindowWithPreferredMode]; // create external window as soon as external screen is connected to prevent unwanted mirroring. ofxiOSExternalDisplay::alertExternalDisplayConnected(); // alert any OF apps listening for a new external device. } @@ -253,7 +244,7 @@ - (void)handleScreenDisconnectNotification:(NSNotification*)aNotification { } - (void)handleScreenModeDidChangeNotification:(NSNotification*)aNotification { - // + ofxiOSExternalDisplay::alertExternalDisplayChanged(); } //------------------------------------------------------------------------------------------- diff --git a/addons/ofxiOS/src/core/ofxiOSEAGLView.h b/addons/ofxiOS/src/core/ofxiOSEAGLView.h index b8824e1c5e0..13f1f269186 100644 --- a/addons/ofxiOS/src/core/ofxiOSEAGLView.h +++ b/addons/ofxiOS/src/core/ofxiOSEAGLView.h @@ -5,6 +5,8 @@ // Created by lukasz karluk on 5/07/12. // +#pragma once + #import #import "EAGLView.h" @@ -16,9 +18,6 @@ class ofAppiOSWindow; @protected NSMutableDictionary * activeTouches; - ofxiOSApp * app; - ofAppiOSWindow * window; - ofVec3f * screenSize; // because ofVec3f is forward declared, ofVec3f * windowSize; // these values have to be pointers. ofVec3f * windowPos; diff --git a/addons/ofxiOS/src/core/ofxiOSEAGLView.mm b/addons/ofxiOS/src/core/ofxiOSEAGLView.mm index eadad4fa4eb..1066346e6cf 100644 --- a/addons/ofxiOS/src/core/ofxiOSEAGLView.mm +++ b/addons/ofxiOS/src/core/ofxiOSEAGLView.mm @@ -5,19 +5,18 @@ // Created by lukasz karluk on 5/07/12. // -#import "ofxiOSEAGLView.h" - -#import "ofMain.h" -#import "ofAppiOSWindow.h" -#import "ofGLProgrammableRenderer.h" -#import "ofxiOSApp.h" -#import "ofxiOSExtensions.h" +#include "ofxiOSEAGLView.h" +#include "ofxiOSApp.h" +#include "ofAppiOSWindow.h" +#include "ofGLRenderer.h" +#include "ofGLProgrammableRenderer.h" static ofxiOSEAGLView * _instanceRef = nil; @interface ofxiOSEAGLView() { BOOL bInit; - shared_ptr appSharedPtr; + shared_ptr window; + shared_ptr app; } - (void)updateDimensions; @end @@ -33,12 +32,14 @@ + (ofxiOSEAGLView *) getInstance { } - (id)initWithFrame:(CGRect)frame andApp:(ofxiOSApp *)appPtr { - - window = ofAppiOSWindow::getInstance(); - if(window == NULL) { + + window = dynamic_pointer_cast(ofGetMainLoop()->getCurrentWindow()); + + if(window.get() == NULL) { ofLog(OF_LOG_FATAL_ERROR, "ofxiOSEAGLView::initWithFrame - window is NULL"); return nil; } + ESRendererVersion preferedRendererVersion = (ESRendererVersion)window->getSettings().glesVersion; self = [self initWithFrame:frame @@ -53,28 +54,15 @@ - (id)initWithFrame:(CGRect)frame andApp:(ofxiOSApp *)appPtr { _instanceRef = self; - app = appPtr; + app = shared_ptr(appPtr); activeTouches = [[NSMutableDictionary alloc] init]; screenSize = new ofVec3f(); windowSize = new ofVec3f(); windowPos = new ofVec3f(); + ofSetOrientation(window->getOrientation()); [self updateDimensions]; - - if(window->isProgrammableRenderer()){ - static_cast(window->renderer().get())->setup(window->getSettings().glesVersion, 0); - } else{ - static_cast(window->renderer().get())->setup(); - } - - if(app != ofGetAppPtr()) { // check if already running. - appSharedPtr = shared_ptr(app); - ofRunApp(appSharedPtr); // this fallback only case occurs when app not created in main(). - } - ofxiOSAlerts.addListener(app); - - ofDisableTextureEdgeHack(); - + bInit = YES; } @@ -82,12 +70,37 @@ - (id)initWithFrame:(CGRect)frame andApp:(ofxiOSApp *)appPtr { } - (void)setup { - if(window != NULL){ - window->events().notifySetup(); - window->renderer()->clear(); - } else { - ofLog(OF_LOG_FATAL_ERROR, "ofxiOSEAGLView setup. Failed setup. window is NULL"); - } + if(window.get() == NULL) { + ofLog(OF_LOG_FATAL_ERROR, "ofxiOSEAGLView setup. Failed setup. window is NULL"); + return; + } + + if(app.get() != ofGetAppPtr()) { // check if already running. + + ofSetMainLoop(shared_ptr(NULL)); // destroy old main loop. + auto mainLoop = std::make_shared(); // make new main loop. + ofSetMainLoop(mainLoop); + + ofiOSWindowSettings windowSettings = window->getSettings(); + window = NULL; + + window = dynamic_pointer_cast(ofCreateWindow(windowSettings)); + + ofRunApp(app); + } + + if(window->isProgrammableRenderer() == true) { + static_cast(window->renderer().get())->setup(window->getSettings().glesVersion, 0); + } else{ + static_cast(window->renderer().get())->setup(); + } + + ofxiOSAlerts.addListener(app.get()); + + ofDisableTextureEdgeHack(); + + window->events().notifySetup(); + window->renderer()->clear(); } - (void)destroy { @@ -97,24 +110,22 @@ - (void)destroy { window->events().notifyExit(); + ofxiOSAlerts.removeListener(app.get()); + ofGetMainLoop()->exit(); - [activeTouches release]; - - delete screenSize; - screenSize = NULL; - delete windowSize; - windowSize = NULL; - delete windowPos; - windowPos = NULL; - - ofxiOSAlerts.removeListener(app); - - appSharedPtr = shared_ptr((app = NULL)); - ofSetAppPtr(appSharedPtr); - - window = NULL; - + app = NULL; + window = NULL; + + [activeTouches release]; + + delete screenSize; + screenSize = NULL; + delete windowSize; + windowSize = NULL; + delete windowPos; + windowPos = NULL; + _instanceRef = nil; bInit = NO; diff --git a/addons/ofxiOS/src/core/ofxiOSViewController.h b/addons/ofxiOS/src/core/ofxiOSViewController.h index 2e5f752c5aa..42739ca16f4 100644 --- a/addons/ofxiOS/src/core/ofxiOSViewController.h +++ b/addons/ofxiOS/src/core/ofxiOSViewController.h @@ -3,6 +3,8 @@ // Created by lukasz karluk on 12/12/11. // +#pragma once + #import class ofxiOSApp; diff --git a/addons/ofxiOS/src/core/ofxiOSViewController.mm b/addons/ofxiOS/src/core/ofxiOSViewController.mm index ff1457ef201..8515b0b8dbf 100644 --- a/addons/ofxiOS/src/core/ofxiOSViewController.mm +++ b/addons/ofxiOS/src/core/ofxiOSViewController.mm @@ -5,8 +5,8 @@ #import -#import "ofxiOSViewController.h" -#import "ofxiOSEAGLView.h" +#include "ofxiOSViewController.h" +#include "ofxiOSEAGLView.h" @interface ofxiOSViewController() { UIInterfaceOrientation currentInterfaceOrientation; @@ -25,7 +25,11 @@ - (id)initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { currentInterfaceOrientation = pendingInterfaceOrientation = UIInterfaceOrientationPortrait; if((self = [super init])) { currentInterfaceOrientation = pendingInterfaceOrientation = self.interfaceOrientation; - bReadyToRotate = NO; + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = NO; + }else{ + bReadyToRotate = YES; + } bFirstUpdate = NO; bAnimated = NO; @@ -53,7 +57,7 @@ - (void)viewDidLoad { // so now when we call setup in our OF app, a reference to ofxiOSViewController will exists. [self.view addSubview:self.glView]; - [self.glView setup]; + [self.glView performSelector:@selector(setup) withObject:nil afterDelay:0]; [self.glView startAnimation]; } @@ -68,10 +72,11 @@ - (void)viewDidAppear:(BOOL)animated { // rotation of the glView only works properly after viewDidAppear. // this is something to do with either the bounds, center or transform properties not being initialised earlier. // so now that glView is ready, we rotate it to the pendingInterfaceOrientation. - - bReadyToRotate = YES; - bFirstUpdate = YES; - [self rotateToInterfaceOrientation:pendingInterfaceOrientation animated:NO]; + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = YES; + bFirstUpdate = YES; + [self rotateToInterfaceOrientation:pendingInterfaceOrientation animated:NO]; + } } - (void)viewWillDisappear:(BOOL)animated { @@ -127,6 +132,8 @@ - (float)rotationForOrientation:(UIInterfaceOrientation)interfaceOrientation { - (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation animated:(BOOL)animated { bAnimated = animated; + + if(bReadyToRotate == NO) { pendingInterfaceOrientation = interfaceOrientation; @@ -143,7 +150,8 @@ - (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientatio return; } - + + if(currentInterfaceOrientation == interfaceOrientation && !bFirstUpdate) { return; } @@ -163,7 +171,7 @@ - (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientatio CGPoint center; CGRect bounds = CGRectMake(0, 0, screenSize.width, screenSize.height); - if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) { + if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) { center.x = screenSize.height * 0.5; center.y = screenSize.width * 0.5; } else { @@ -187,6 +195,17 @@ - (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientatio bounds.size.width = screenSize.width; bounds.size.height = screenSize.height; } + //borg + //NSLog(@"w %f h %f",[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height); + //assumes Portrait orientation + if(screenSize.width>screenSize.height){ + center.x = screenSize.height * 0.5; + center.y = screenSize.width * 0.5; + }else{ + center.x = screenSize.width * 0.5; + center.y = screenSize.height * 0.5; + } + //NSLog(@"rotating to portrait %i, is portrait %i, currentInterfaceOrientation %i, bound: w %f h %f",UIInterfaceOrientationIsPortrait(interfaceOrientation),UIInterfaceOrientationIsPortrait(self.interfaceOrientation),UIInterfaceOrientationIsPortrait(currentInterfaceOrientation),bounds.size.width,bounds.size.height); } float rot1 = [self rotationForOrientation:currentInterfaceOrientation]; @@ -194,7 +213,7 @@ - (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientatio float rot3 = rot2 - rot1; CGAffineTransform rotate = CGAffineTransformMakeRotation(rot3); rotate = CGAffineTransformConcat(rotate, self.glView.transform); - + if(animated) { NSTimeInterval duration = 0.3; if((UIInterfaceOrientationIsLandscape(currentInterfaceOrientation) && UIInterfaceOrientationIsLandscape(interfaceOrientation)) || @@ -280,25 +299,19 @@ - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInte } } -#ifdef __IPHONE_8_0 // iOS8+ version of willAnimateRotationToInterfaceOrientation +//NOTE: Only called if actually resizing and not masked +//http://stackoverflow.com/questions/25935006/ios8-interface-rotation-methods-not-called + +//borg +#ifdef __IPHONE_8_0 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { - CGSize screenSize = size; - + CGPoint center; - // Is the iOS version less than 8? - if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { - if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) { - center.x = screenSize.height * 0.5; - center.y = screenSize.width * 0.5; - } else { - center.x = screenSize.width * 0.5; - center.y = screenSize.height * 0.5; - } - } else { - center.x = screenSize.width * 0.5; - center.y = screenSize.height * 0.5; - } + + center.x = size.width * 0.5; + center.y = size.height * 0.5; + if(bAnimated) { NSTimeInterval duration = 0.3; @@ -306,14 +319,17 @@ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id +#include "ofUtils.h" +#include "ofxAccelerometer.h" + /************ Interface for iPhone Accelerometer Delegate ************/ @interface ofxiOSAccelerometerDelegate : NSObject { } diff --git a/addons/ofxiOS/src/events/ofxiOSAlerts.h b/addons/ofxiOS/src/events/ofxiOSAlerts.h index 57cd08d61c2..a6fc07b1a49 100644 --- a/addons/ofxiOS/src/events/ofxiOSAlerts.h +++ b/addons/ofxiOS/src/events/ofxiOSAlerts.h @@ -30,8 +30,10 @@ #pragma once -#import "ofxiOSAlertsListener.h" -#import +#include +#include "ofxiOSAlertsListener.h" + +using namespace std; class ofxiOSAlertsHandler : public ofxiOSAlertsListener { public: diff --git a/addons/ofxiOS/src/events/ofxiOSAlertsListener.h b/addons/ofxiOS/src/events/ofxiOSAlertsListener.h index 234034aa666..4824e2b9fa7 100644 --- a/addons/ofxiOS/src/events/ofxiOSAlertsListener.h +++ b/addons/ofxiOS/src/events/ofxiOSAlertsListener.h @@ -29,8 +29,10 @@ * ***********************************************************************/ #pragma once -#include "ofMain.h" +#include + +using namespace std; /****** protocol, delegate, interface, whatever you want to call it ******/ class ofxiOSAlertsListener { @@ -41,7 +43,7 @@ class ofxiOSAlertsListener { virtual void gotFocus(){}; virtual void gotMemoryWarning(){}; virtual void deviceOrientationChanged(int newOrientation){}; - virtual void launchedWithURL(string url){}; + virtual void launchedWithURL(std::string url){}; }; #define ofxiPhoneAlertsListener ofxiOSAlertsListener \ No newline at end of file diff --git a/addons/ofxiOS/src/gl/EAGLView.h b/addons/ofxiOS/src/gl/EAGLView.h index 7cc0f1533b7..89adb73070f 100644 --- a/addons/ofxiOS/src/gl/EAGLView.h +++ b/addons/ofxiOS/src/gl/EAGLView.h @@ -29,6 +29,8 @@ * * ***********************************************************************/ +#pragma once + #import #import "ESRenderer.h" diff --git a/addons/ofxiOS/src/gl/ES1Renderer.h b/addons/ofxiOS/src/gl/ES1Renderer.h index 18ded12229e..a0b3478e622 100644 --- a/addons/ofxiOS/src/gl/ES1Renderer.h +++ b/addons/ofxiOS/src/gl/ES1Renderer.h @@ -1,4 +1,5 @@ +#pragma once #import "ESRenderer.h" #import diff --git a/addons/ofxiOS/src/gl/ES2Renderer.h b/addons/ofxiOS/src/gl/ES2Renderer.h index e2e856a8dba..6d13c15735a 100644 --- a/addons/ofxiOS/src/gl/ES2Renderer.h +++ b/addons/ofxiOS/src/gl/ES2Renderer.h @@ -1,4 +1,5 @@ +#pragma once #import "ESRenderer.h" #import diff --git a/addons/ofxiOS/src/gl/ESRenderer.h b/addons/ofxiOS/src/gl/ESRenderer.h index e74c01791eb..a5437eef5b9 100644 --- a/addons/ofxiOS/src/gl/ESRenderer.h +++ b/addons/ofxiOS/src/gl/ESRenderer.h @@ -6,6 +6,8 @@ // Copyright MSA Visuals Ltd. 2010. All rights reserved. // +#pragma once + #import #import diff --git a/addons/ofxiOS/src/ofxiOS.h b/addons/ofxiOS/src/ofxiOS.h index 0ccb6d2d596..b72b0d255da 100644 --- a/addons/ofxiOS/src/ofxiOS.h +++ b/addons/ofxiOS/src/ofxiOS.h @@ -36,10 +36,13 @@ #pragma once -#import -#import - -#import "ofxAccelerometer.h" -#import "ofxiOSAlerts.h" -#import "ofxiOSApp.h" - +#include "ofMain.h" +#include "ofAppiOSWindow.h" +#include "ofxiOSConstants.h" +#include "ofxiOSExtensions.h" +#include "ofxiOSAppDelegate.h" +#include "ofxiOSViewController.h" +#include "ofxiOSEAGLView.h" +#include "ofxiOSApp.h" +#include "ofxiOSExtras.h" +#include "ofxAccelerometer.h" \ No newline at end of file diff --git a/addons/ofxiOS/src/ofxiOSExtensions.h b/addons/ofxiOS/src/ofxiOSExtensions.h index f4e95da1e9f..bbb1c7210cc 100644 --- a/addons/ofxiOS/src/ofxiOSExtensions.h +++ b/addons/ofxiOS/src/ofxiOSExtensions.h @@ -8,8 +8,6 @@ #pragma once void ofReloadGLResources(); - -void ofUpdateBitmapCharacterTexture(); void ofReloadAllImageTextures(); void ofReloadAllFontTextures(); void ofUnloadAllFontTextures(); diff --git a/addons/ofxiOS/src/sound/AVSoundPlayer.h b/addons/ofxiOS/src/sound/AVSoundPlayer.h index 235f2a93935..3b3abe8e9a8 100644 --- a/addons/ofxiOS/src/sound/AVSoundPlayer.h +++ b/addons/ofxiOS/src/sound/AVSoundPlayer.h @@ -4,6 +4,8 @@ // http://julapy.com/blog // +#pragma once + #import #import diff --git a/addons/ofxiOS/src/sound/AVSoundPlayer.m b/addons/ofxiOS/src/sound/AVSoundPlayer.m index 0782554fd1c..bae5cbf62f8 100644 --- a/addons/ofxiOS/src/sound/AVSoundPlayer.m +++ b/addons/ofxiOS/src/sound/AVSoundPlayer.m @@ -25,6 +25,20 @@ - (id)init { return self; } +// setupSharedSession is to prevent other iOS Classes closing the audio feed, such as AVAssetReader, when reading from disk +// It is set once on first launch of a AVAudioPlayer and remains as a set property from then on +- (void) setupSharedSession { + static BOOL audioSessionSetup = NO; + if(audioSessionSetup) { + return; + } + [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil]; + UInt32 doSetProperty = 1; + AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doSetProperty), &doSetProperty); + [[AVAudioSession sharedInstance] setActive: YES error: nil]; + audioSessionSetup = YES; +} + - (void)dealloc { [self unloadSound]; [super dealloc]; @@ -45,7 +59,7 @@ - (BOOL)loadWithPath:(NSString*)path { - (BOOL)loadWithURL:(NSURL*)url { [self unloadSound]; - + [self setupSharedSession]; NSError * error = nil; self.player = [[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error] autorelease]; diff --git a/addons/ofxiOS/src/sound/SoundInputStream.h b/addons/ofxiOS/src/sound/SoundInputStream.h index 31d665190a1..3e679c3d8c0 100644 --- a/addons/ofxiOS/src/sound/SoundInputStream.h +++ b/addons/ofxiOS/src/sound/SoundInputStream.h @@ -4,6 +4,8 @@ // http://julapy.com/blog // +#pragma once + #import "SoundStream.h" @interface SoundInputStream : SoundStream { diff --git a/addons/ofxiOS/src/sound/SoundOutputStream.h b/addons/ofxiOS/src/sound/SoundOutputStream.h index 479d30800c3..89173a4025c 100644 --- a/addons/ofxiOS/src/sound/SoundOutputStream.h +++ b/addons/ofxiOS/src/sound/SoundOutputStream.h @@ -4,6 +4,8 @@ // http://julapy.com/blog // +#pragma once + #import "SoundStream.h" @interface SoundOutputStream : SoundStream diff --git a/addons/ofxiOS/src/sound/SoundStream.h b/addons/ofxiOS/src/sound/SoundStream.h index ceddfeacabe..d8c59bd922f 100644 --- a/addons/ofxiOS/src/sound/SoundStream.h +++ b/addons/ofxiOS/src/sound/SoundStream.h @@ -5,6 +5,8 @@ // // +#pragma once + #import #import diff --git a/addons/ofxiOS/src/sound/SoundStream.m b/addons/ofxiOS/src/sound/SoundStream.m index 720208600e2..7c08ecc54c4 100644 --- a/addons/ofxiOS/src/sound/SoundStream.m +++ b/addons/ofxiOS/src/sound/SoundStream.m @@ -173,7 +173,7 @@ - (BOOL)checkStatus:(OSStatus)status { return YES; } else if([self.delegate respondsToSelector:@selector(soundStreamError:error:)]) { NSString * errorCode = [self stringForAudioUnitError:status]; - NSString * fullErrorString = [errorCode stringByAppendingFormat:@" (%li)", status]; + NSString * fullErrorString = [errorCode stringByAppendingFormat:@" (%i)", (int)status]; [self.delegate soundStreamError:self error:fullErrorString]; } return NO; diff --git a/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.cpp b/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.cpp index 99783775929..2572f6a824d 100644 --- a/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.cpp +++ b/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.cpp @@ -23,6 +23,7 @@ ************************************************************************/ #import "ofxOpenALSoundPlayer.h" +#include "ofUtils.h" bool SoundEngineInitialized = false; diff --git a/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.h b/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.h index 58418bb98dc..2ccb8b03e71 100644 --- a/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.h +++ b/addons/ofxiOS/src/sound/ofxOpenALSoundPlayer.h @@ -38,10 +38,7 @@ #include "SoundEngine.h" -#include #include "ofBaseSoundPlayer.h" -#include "ofUtils.h" -#include "ofPoint.h" #include "ofTypes.h" //globals diff --git a/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.h b/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.h index 1b9fa45b71b..b421fd5c4a7 100644 --- a/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.h +++ b/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.h @@ -6,7 +6,7 @@ #pragma once -#include "ofMain.h" +#include "ofBaseSoundPlayer.h" class ofxiOSSoundPlayer : public ofBaseSoundPlayer { diff --git a/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.mm b/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.mm index 7969ef3fc88..b46b46e7572 100644 --- a/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.mm +++ b/addons/ofxiOS/src/sound/ofxiOSSoundPlayer.mm @@ -5,6 +5,7 @@ // #include "ofxiOSSoundPlayer.h" +#include "ofUtils.h" #import "AVSoundPlayer.h" ofxiOSSoundPlayer::ofxiOSSoundPlayer() { diff --git a/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.h b/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.h index 710afe861bf..dd33aa778df 100644 --- a/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.h +++ b/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.h @@ -4,6 +4,8 @@ // http://julapy.com/blog // +#pragma once + #import "SoundStream.h" class ofBaseSoundInput; diff --git a/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.mm b/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.mm index 21cc2e587c2..1a66ea5bdc7 100644 --- a/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.mm +++ b/addons/ofxiOS/src/sound/ofxiOSSoundStreamDelegate.mm @@ -4,9 +4,9 @@ // http://julapy.com/blog // -#import "ofxiOSSoundStreamDelegate.h" -#import "ofBaseTypes.h" -#import "ofSoundBuffer.h" +#include "ofxiOSSoundStreamDelegate.h" +#include "ofBaseTypes.h" +#include "ofSoundBuffer.h" @interface ofxiOSSoundStreamDelegate() { ofBaseSoundInput * soundInputApp; diff --git a/addons/ofxiOS/src/utils/ofxiOSCoreLocation.h b/addons/ofxiOS/src/utils/ofxiOSCoreLocation.h index 9507c530b2a..b6a2ccd14b1 100644 --- a/addons/ofxiOS/src/utils/ofxiOSCoreLocation.h +++ b/addons/ofxiOS/src/utils/ofxiOSCoreLocation.h @@ -6,11 +6,10 @@ * */ -#import -#import -#import "ofMain.h" #pragma once +#import + @interface ofxiOSCoreLocationDelegate : NSObject { CLLocationManager *locationManager; diff --git a/addons/ofxiOS/src/utils/ofxiOSCoreLocation.mm b/addons/ofxiOS/src/utils/ofxiOSCoreLocation.mm index 0e92544cec3..a5b14589f47 100644 --- a/addons/ofxiOS/src/utils/ofxiOSCoreLocation.mm +++ b/addons/ofxiOS/src/utils/ofxiOSCoreLocation.mm @@ -17,7 +17,7 @@ * */ -#import "ofxiOSCoreLocation.h" +#include "ofxiOSCoreLocation.h" //C++ class implementations @@ -325,13 +325,13 @@ - (void)locationManager:(CLLocationManager *)manager // We shouldn't ever get an unknown error code, but just in case... // default: - [errorString appendFormat:@"%@ %d\n", NSLocalizedString(@"GenericLocationError", nil), [error code]]; + [errorString appendFormat:@"%@ %i\n", NSLocalizedString(@"GenericLocationError", nil), (int)[error code]]; break; } } else { // We handle all non-CoreLocation errors here // (we depend on localizedDescription for localization) - [errorString appendFormat:@"Error domain: \"%@\" Error code: %d\n", [error domain], [error code]]; + [errorString appendFormat:@"Error domain: \"%@\" Error code: %i\n", [error domain], (int)[error code]]; [errorString appendFormat:@"Description: \"%@\"\n", [error localizedDescription]]; } diff --git a/addons/ofxiOS/src/utils/ofxiOSExternalDisplay.h b/addons/ofxiOS/src/utils/ofxiOSExternalDisplay.h index b9a9b3fba7e..67c097a3065 100644 --- a/addons/ofxiOS/src/utils/ofxiOSExternalDisplay.h +++ b/addons/ofxiOS/src/utils/ofxiOSExternalDisplay.h @@ -7,7 +7,7 @@ #pragma once -#import "ofMain.h" +#include "ofConstants.h" struct ofxiOSExternalDisplayMode{ int width; diff --git a/addons/ofxiOS/src/utils/ofxiOSExtras.h b/addons/ofxiOS/src/utils/ofxiOSExtras.h index 2e7fad8005f..a17dd1246a0 100644 --- a/addons/ofxiOS/src/utils/ofxiOSExtras.h +++ b/addons/ofxiOS/src/utils/ofxiOSExtras.h @@ -37,18 +37,14 @@ #pragma once #import -#import "ofMain.h" -#import "ofxiOS.h" -#import "ofxiOSConstants.h" -#import "ofAppiOSWindow.h" -#import "ofxiOSAppDelegate.h" -#import "ofxiOSEAGLView.h" -#import "ofxiOSKeyboard.h" -#import "ofxiOSCoreLocation.h" -#import "ofxiOSImagePicker.h" -#import "ofxiOSMapKit.h" -#include +#include "ofBaseTypes.h" +#include "ofxiOSConstants.h" + +class ofAppiOSWindow; +@class ofxiOSAppDelegate; +@class ofxiOSViewController; +@class ofxiOSEAGLView; // this is the new way for getting device info. // we can add other parameters later. @@ -79,22 +75,22 @@ string ofxiOSGetDeviceRevision(); ofxiOSDeviceInfo ofxiOSGetDeviceInfo(); // return application key UIWindow -UIWindow *ofxiOSGetUIWindow(); +UIWindow * ofxiOSGetUIWindow(); // return openglview -ofxiOSEAGLView *ofxiOSGetGLView(); +ofxiOSEAGLView * ofxiOSGetGLView(); // return opengl parent view UIView * ofxiOSGetGLParentView(); // return OpenFrameworks iPhone Window -ofAppiOSWindow* ofxiOSGetOFWindow(); +ofAppiOSWindow * ofxiOSGetOFWindow(); // return application delegate -ofxiOSAppDelegate *ofxiOSGetAppDelegate(); +ofxiOSAppDelegate * ofxiOSGetAppDelegate(); // return iphone view controller. -ofxiOSViewController *ofxiOSGetViewController(); +ofxiOSViewController * ofxiOSGetViewController(); // brings the OpenGL view to the front of any other UIViews // the OpenGL view will receive touchXXXXX events, but other UIViews will not @@ -145,12 +141,12 @@ OF_DEPRECATED_MSG("ofxiOSGetOrientation is deprecated, use ofGetOrientation inst // load an image from the app bundle into a texture // NOTE: renamed this function to something more clearer // WAS: void iPhoneLoadImageFromBundle(NSString *filename, GLuint *spriteTexture); -bool ofxiOSBundleImageToGLTexture(NSString *filename, GLuint *spriteTexture); +bool ofxiOSBundleImageToGLTexture(NSString * filename, GLuint * spriteTexture); // load an image from UIImage into an opengl texture // NOTE: renamed this function to something more clearer // WAS: void iPhoneLoadImageFromUIImage(UIImage *uiImage, GLuint *spriteTexture); -bool ofxiOSUIImageToGLTexture(UIImage *uiImage, GLuint *spriteTexture); +bool ofxiOSUIImageToGLTexture(UIImage * uiImage, GLuint * spriteTexture); // create an ofImage out of a UIImage @@ -158,9 +154,9 @@ bool ofxiOSUIImageToGLTexture(UIImage *uiImage, GLuint *spriteTexture); // targetWidth, targetHeight are target dimensions (UIImage is resized to this size and ofImage is created) // .... omit targetWidth & targetHeight to use original image dimensions and not resize // TODO: take into consideration UI image orentation -bool ofxiOSUIImageToOFImage(UIImage *uiImage, ofImage &outImage, int targetWidth = 0, int targetHeight = 0); +bool ofxiOSUIImageToOFImage(UIImage * uiImage, ofImage & outImage, int targetWidth = 0, int targetHeight = 0); -bool ofxiOSUIImageToOFTexture(UIImage *uiImage, ofTexture &outTexture, int targetWidth, int targetHeight); +bool ofxiOSUIImageToOFTexture(UIImage * uiImage, ofTexture & outTexture, int targetWidth, int targetHeight); bool ofxiOSCGImageToPixels(CGImageRef & ref, unsigned char * pixels); diff --git a/addons/ofxiOS/src/utils/ofxiOSExtras.mm b/addons/ofxiOS/src/utils/ofxiOSExtras.mm index 1f3d481c8a6..004dd21b4d0 100644 --- a/addons/ofxiOS/src/utils/ofxiOSExtras.mm +++ b/addons/ofxiOS/src/utils/ofxiOSExtras.mm @@ -30,7 +30,14 @@ * ***********************************************************************/ -#import "ofxiOSExtras.h" +#include "ofxiOSExtras.h" +#include "ofxiOSAppDelegate.h" +#include "ofxiOSViewController.h" +#include "ofxiOSEAGLView.h" +#include "ofAppiOSWindow.h" +#include "ofAppRunner.h" +#include "ofImage.h" +#include //-------------------------------------------------------------- ofxiOSDeviceType ofxiOSGetDeviceType() { @@ -117,13 +124,13 @@ ofxiOSDeviceInfo ofxiOSGetDeviceInfo(){ } //-------------------------------------------------------------- -UIWindow *ofxiOSGetUIWindow() { +UIWindow * ofxiOSGetUIWindow() { return [[UIApplication sharedApplication] keyWindow]; } //-------------------------------------------------------------- -ofxiOSEAGLView *ofxiOSGetGLView() { +ofxiOSEAGLView * ofxiOSGetGLView() { return [ofxiOSEAGLView getInstance]; } @@ -133,18 +140,18 @@ ofxiOSDeviceInfo ofxiOSGetDeviceInfo(){ } //-------------------------------------------------------------- -ofAppiOSWindow* ofxiOSGetOFWindow() { +ofAppiOSWindow * ofxiOSGetOFWindow() { return ofAppiOSWindow::getInstance(); } //-------------------------------------------------------------- -ofxiOSAppDelegate *ofxiOSGetAppDelegate() { +ofxiOSAppDelegate * ofxiOSGetAppDelegate() { return [[UIApplication sharedApplication] delegate]; } //-------------------------------------------------------------- -ofxiOSViewController *ofxiOSGetViewController() { +ofxiOSViewController * ofxiOSGetViewController() { return [ofxiOSGetAppDelegate() glViewController]; } @@ -217,18 +224,18 @@ UIDeviceOrientation ofxiOSGetOrientation() { //-------------------------------------------------------------- -bool ofxiOSBundleImageToGLTexture(NSString *filename, GLuint *spriteTexture) { +bool ofxiOSBundleImageToGLTexture(NSString * filename, GLuint * spriteTexture) { return ofxiOSUIImageToGLTexture([UIImage imageNamed:filename], spriteTexture); } //-------------------------------------------------------------- -bool ofxiOSUIImageToGLTexture(UIImage *uiImage, GLuint *spriteTexture) { +bool ofxiOSUIImageToGLTexture(UIImage * uiImage, GLuint * spriteTexture) { if(!uiImage) return false; CGImageRef cgImage; CGContextRef spriteContext; - GLubyte *pixels; + GLubyte * pixels; size_t width, height; // Creates a Core Graphics image from an image file @@ -264,7 +271,7 @@ bool ofxiOSUIImageToGLTexture(UIImage *uiImage, GLuint *spriteTexture) { //-------------------------------------------------------------- -bool ofxiOSUIImageToOFImage(UIImage *uiImage, ofImage &outImage, int targetWidth, int targetHeight) { +bool ofxiOSUIImageToOFImage(UIImage * uiImage, ofImage & outImage, int targetWidth, int targetHeight) { if(uiImage == nil) { return false; } @@ -332,7 +339,7 @@ bool ofxiOSUIImageToOFImage(UIImage *uiImage, ofImage &outImage, int targetWidth } //-------------------------------------------------------------- -bool ofxiOSUIImageToOFTexture(UIImage *uiImage, ofTexture &outTexture, int targetWidth, int targetHeight) { +bool ofxiOSUIImageToOFTexture(UIImage * uiImage, ofTexture & outTexture, int targetWidth, int targetHeight) { if(!uiImage) return false; CGContextRef spriteContext; @@ -345,7 +352,7 @@ bool ofxiOSUIImageToOFTexture(UIImage *uiImage, ofTexture &outTexture, int targe int height = targetHeight > 0 ? targetHeight : CGImageGetHeight(cgImage); // Allocated memory needed for the bitmap context - GLubyte *pixels = (GLubyte *) malloc(width * height * bytesPerPixel); + GLubyte * pixels = (GLubyte *) malloc(width * height * bytesPerPixel); // Uses the bitmap creation function provided by the Core Graphics framework. spriteContext = CGBitmapContextCreate(pixels, width, height, CGImageGetBitsPerComponent(cgImage), width * bytesPerPixel, CGImageGetColorSpace(cgImage), bytesPerPixel == 4 ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone); @@ -401,7 +408,7 @@ bool ofxiOSCGImageToPixels(CGImageRef & ref, unsigned char * pixels){ int h = CGImageGetHeight(ref); // Allocated memory needed for the bitmap context - GLubyte *pixelsTmp = (GLubyte *) malloc(w * h * bytesPerPixel); + GLubyte * pixelsTmp = (GLubyte *) malloc(w * h * bytesPerPixel); // Uses the bitmap creation function provided by the Core Graphics framework. spriteContext = CGBitmapContextCreate(pixelsTmp, w, h, CGImageGetBitsPerComponent(ref), w * bytesPerPixel, CGImageGetColorSpace(ref), bytesPerPixel == 4 ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone); diff --git a/addons/ofxiOS/src/utils/ofxiOSImagePicker.h b/addons/ofxiOS/src/utils/ofxiOSImagePicker.h index 76a1a19cdd8..3000ea0c50d 100644 --- a/addons/ofxiOS/src/utils/ofxiOSImagePicker.h +++ b/addons/ofxiOS/src/utils/ofxiOSImagePicker.h @@ -6,11 +6,10 @@ * */ +#pragma once + #import -#import -#import "ofMain.h" -#include -#include +#include "ofBaseTypes.h" #define OFX_IMG_PICKER_UP 1 #define OFX_IMG_PICKER_DOWN 2 diff --git a/addons/ofxiOS/src/utils/ofxiOSImagePicker.mm b/addons/ofxiOS/src/utils/ofxiOSImagePicker.mm index 374f1be474a..d1035e9ebec 100644 --- a/addons/ofxiOS/src/utils/ofxiOSImagePicker.mm +++ b/addons/ofxiOS/src/utils/ofxiOSImagePicker.mm @@ -7,7 +7,7 @@ * */ -#import "ofxiOSImagePicker.h" +#include "ofxiOSImagePicker.h" //C++ class implementations diff --git a/addons/ofxiOS/src/utils/ofxiOSKeyboard.h b/addons/ofxiOS/src/utils/ofxiOSKeyboard.h index 719a897b70f..84a1d9df4e4 100644 --- a/addons/ofxiOS/src/utils/ofxiOSKeyboard.h +++ b/addons/ofxiOS/src/utils/ofxiOSKeyboard.h @@ -6,11 +6,11 @@ * */ -#import -#import "ofMain.h" -#import "ofxiOSExtras.h" #pragma once +#import +#include "ofConstants.h" + @interface ofxiOSKeyboardDelegate : NSObject { UITextField* _textField; diff --git a/addons/ofxiOS/src/utils/ofxiOSKeyboard.mm b/addons/ofxiOS/src/utils/ofxiOSKeyboard.mm index 59d42b6978a..ba13b7b65ca 100644 --- a/addons/ofxiOS/src/utils/ofxiOSKeyboard.mm +++ b/addons/ofxiOS/src/utils/ofxiOSKeyboard.mm @@ -7,7 +7,10 @@ * */ -#import "ofxiOSKeyboard.h" +#include "ofxiOSKeyboard.h" +#include "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" +#include "ofAppRunner.h" //C++ class implementations diff --git a/addons/ofxiOS/src/utils/ofxiOSMapKit.h b/addons/ofxiOS/src/utils/ofxiOSMapKit.h index 8160804401c..8d3bcbb9c39 100644 --- a/addons/ofxiOS/src/utils/ofxiOSMapKit.h +++ b/addons/ofxiOS/src/utils/ofxiOSMapKit.h @@ -30,12 +30,9 @@ #pragma once -#include - -#include "ofMain.h" -#include +#import +#include "ofBaseTypes.h" #include "ofxiOSMapKitListener.h" -#include // these are the types you can set for the map enum ofxiOSMapKitType { diff --git a/addons/ofxiOS/src/utils/ofxiOSMapKit.mm b/addons/ofxiOS/src/utils/ofxiOSMapKit.mm index ab431e1190c..72d4b630ca7 100644 --- a/addons/ofxiOS/src/utils/ofxiOSMapKit.mm +++ b/addons/ofxiOS/src/utils/ofxiOSMapKit.mm @@ -28,11 +28,10 @@ * * ***********************************************************************/ -#include - #include "ofxiOSMapKit.h" -#include "ofxiOSExtras.h" #include "ofxiOSMapKitDelegate.h" +#include "ofxiOSExtras.h" +#include "ofAppRunner.h" ofxiOSMapKit::ofxiOSMapKit() { mapView = nil; diff --git a/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.h b/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.h index d032e8dd689..dab6acabef4 100644 --- a/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.h +++ b/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.h @@ -28,7 +28,7 @@ * * ***********************************************************************/ -#include +#pragma once #import diff --git a/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.mm b/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.mm index d4ee3be6e5d..f4cbe997c6e 100644 --- a/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.mm +++ b/addons/ofxiOS/src/utils/ofxiOSMapKitDelegate.mm @@ -28,11 +28,8 @@ * * ***********************************************************************/ -#include - - -#import "ofxiOSMapKitDelegate.h" -#import "ofxiOSMapKit.h" +#include "ofxiOSMapKitDelegate.h" +#include "ofxiOSMapKit.h" @implementation ofxiOSMapKitDelegate diff --git a/addons/ofxiOS/src/video/AVFoundationVideoGrabber.h b/addons/ofxiOS/src/video/AVFoundationVideoGrabber.h index fb300fc878f..6bcd6d4f801 100644 --- a/addons/ofxiOS/src/video/AVFoundationVideoGrabber.h +++ b/addons/ofxiOS/src/video/AVFoundationVideoGrabber.h @@ -9,13 +9,11 @@ #import #import #import -#include "ofxiOS.h" -#include "ofxiOSExtras.h" - +#include "ofBaseTypes.h" +#include "ofTexture.h" class AVFoundationVideoGrabber; - @interface iOSVideoGrabber : UIViewController { @public diff --git a/addons/ofxiOS/src/video/AVFoundationVideoGrabber.mm b/addons/ofxiOS/src/video/AVFoundationVideoGrabber.mm index d552e21fd9e..ced01f075b8 100644 --- a/addons/ofxiOS/src/video/AVFoundationVideoGrabber.mm +++ b/addons/ofxiOS/src/video/AVFoundationVideoGrabber.mm @@ -3,13 +3,8 @@ */ #include "AVFoundationVideoGrabber.h" - -#import -#import -#import #include "ofxiOSExtras.h" -#import -#import +#include "ofAppRunner.h" #define IS_IOS_7_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) #define IS_IOS_6_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) @@ -247,7 +242,7 @@ -(CGImageRef)getCurrentFrame{ NSArray * devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; int i=0; for (AVCaptureDevice * captureDevice in devices){ - deviceNames.push_back(ofxNSStringToString(captureDevice.localizedName)); + deviceNames.push_back([captureDevice.localizedName UTF8String]); ofLogNotice() << "Device: " << i << ": " << deviceNames.back(); i++; } diff --git a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.h b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.h index a45bab390a0..f2046d669e3 100644 --- a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.h +++ b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.h @@ -5,8 +5,9 @@ // Created by lukasz karluk on 21/05/12. // +#pragma once + #import -#import #import #import diff --git a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m index 617d36cace2..4fc302da7c2 100644 --- a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m +++ b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m @@ -248,7 +248,7 @@ - (BOOL)loadWithURL:(NSURL*)url { videoHeight = CVPixelBufferGetHeight(imageBuffer); CVPixelBufferUnlockBaseAddress(imageBuffer,0); - NSLog(@"video loaded at %i x %i", videoWidth, videoHeight); + NSLog(@"video loaded at %i x %i", (int)videoWidth, (int)videoHeight); CGRect playerViewFrame = self.playerView.frame; playerViewFrame.size.width = videoWidth; @@ -276,8 +276,10 @@ - (BOOL)loadWithURL:(NSURL*)url { object:self.playerItem]; [_player replaceCurrentItemWithPlayerItem:self.playerItem]; - + [self addTimeObserverToPlayer]; + + _player.volume = volume; } else { NSLog(@"The asset's tracks were not loaded:\n%@", [error localizedDescription]); @@ -845,19 +847,7 @@ - (void)setVolume:(float)value { return; } - NSArray * audioTracks = [self.asset tracksWithMediaType:AVMediaTypeAudio]; - NSMutableArray * allAudioParams = [NSMutableArray array]; - for(AVAssetTrack * track in audioTracks) { - AVMutableAudioMixInputParameters * audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; - [audioInputParams setVolume:volume atTime:kCMTimeZero]; - [audioInputParams setTrackID:[track trackID]]; - [allAudioParams addObject:audioInputParams]; - } - - AVMutableAudioMix * audioMix = [AVMutableAudioMix audioMix]; - [audioMix setInputParameters:allAudioParams]; - - [self.playerItem setAudioMix:audioMix]; + _player.volume = volume; } - (float)getVolume { diff --git a/addons/ofxiOS/src/video/ofxiOSVideoGrabber.h b/addons/ofxiOS/src/video/ofxiOSVideoGrabber.h index 381dd2a3d86..cfcdf674f2c 100644 --- a/addons/ofxiOS/src/video/ofxiOSVideoGrabber.h +++ b/addons/ofxiOS/src/video/ofxiOSVideoGrabber.h @@ -2,9 +2,9 @@ #pragma once -class AVFoundationVideoGrabber; +#include "ofBaseTypes.h" -#include "ofVideoGrabber.h" +class AVFoundationVideoGrabber; class ofxiOSVideoGrabber : public ofBaseVideoGrabber { diff --git a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.h b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.h index fdfc912f4e3..b7e74b7bb38 100644 --- a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.h +++ b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.h @@ -1,11 +1,8 @@ #pragma once -#include "ofPixels.h" #include "ofBaseTypes.h" #include "ofTexture.h" -#include "ofVideoPlayer.h" - class ofxiOSVideoPlayer : public ofBaseVideoPlayer { public: diff --git a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm index b884bdeeb06..da91f6dd461 100644 --- a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm +++ b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm @@ -1,5 +1,6 @@ -#import "ofxiOSVideoPlayer.h" -#import "ofxiOSExtras.h" +#include "ofxiOSVideoPlayer.h" +#include "ofxiOSExtras.h" +#include "ofxiOSEAGLView.h" #import "AVFoundationVideoPlayer.h" CVOpenGLESTextureCacheRef _videoTextureCache = NULL; diff --git a/apps/devApps/fboTester/emptyExample_win_cb.cbp b/apps/devApps/fboTester/emptyExample_win_cb.cbp deleted file mode 100644 index 8eb18a8b7b3..00000000000 --- a/apps/devApps/fboTester/emptyExample_win_cb.cbp +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - diff --git a/apps/devApps/fboTester/emptyExample_win_cb.workspace b/apps/devApps/fboTester/emptyExample_win_cb.workspace deleted file mode 100644 index cacc8fffa04..00000000000 --- a/apps/devApps/fboTester/emptyExample_win_cb.workspace +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/apps/devApps/raspberrypi_hello_world/src/ofApp.cpp b/apps/devApps/raspberrypi_hello_world/src/ofApp.cpp index 61f8fc147cc..0281b87baf9 100644 --- a/apps/devApps/raspberrypi_hello_world/src/ofApp.cpp +++ b/apps/devApps/raspberrypi_hello_world/src/ofApp.cpp @@ -30,7 +30,7 @@ void ofApp::draw() { ofTranslate(ofGetWidth()/2.0f,ofGetHeight()/2.0f); ofRotateZ(angle); ofEnableAlphaBlending(); - rpiLogo.draw(-rpiLogo.width/2.0f,-rpiLogo.height/2.0f); + rpiLogo.draw(-rpiLogo.getWidth()/2.0f,-rpiLogo.getHeight()/2.0f); ofDisableAlphaBlending(); ofPopMatrix(); diff --git a/apps/projectGenerator b/apps/projectGenerator index b5fafc83012..d14e2470943 160000 --- a/apps/projectGenerator +++ b/apps/projectGenerator @@ -1 +1 @@ -Subproject commit b5fafc830128915cef181ae5c1cb76fbf75a9aee +Subproject commit d14e24709433d7e81a12ce74998d4725c9cd137f diff --git a/docs/PLATFORMS.md b/docs/PLATFORMS.md new file mode 100644 index 00000000000..57552b557b2 --- /dev/null +++ b/docs/PLATFORMS.md @@ -0,0 +1,66 @@ +openFrameworks currently supports the following platforms: + +# Android # + +versions: 2.2+ + +architectures: + * armeabi-v7a + * x86 + + +# Emscripten # + +notes: VM + + +# iOS # + +versions: iOS 5 - 8 (FAT Bundle with libc++ for all archs) + +architectures: + * ARMv7 + * ARM64 + * x86 + * x86_64 + +notes: + * ARMv7s removed since potential performance gains not worth the binary size increase, see #3423 for more discussion + * ARM64 supported until Xcode 6 (OS X 10.9+) + * Apple iOS store requires 64bit support and submission with Xcode 6+ + + +# Linux # + +versions: Debian, Arch, Ubuntu, Fedora + +architectures: + * x86 + * x86_64 + * ARMv6l + * ARMv7l + +# Microsoft Windows # + +versions: Win7 - Win10 + +architectures: + * x86 + * x86_64 + +notes: + * Visual Studio 2015 + * MSYS2 + + +# OS X # + +versions: 10.7 - 10.10 (FAT Bundle) + +architectures: + * x86 (with libc++) + * x86_64 (with libc++) + +notes: + * QTKitVideo pipeline will be deprecated, but essential for 10.7 support. + * 10.8 recommended minimum (to use Xcode 5) diff --git a/docs/android.md b/docs/android_eclipse.md similarity index 62% rename from docs/android.md rename to docs/android_eclipse.md index f8487ecdae1..21c4159b860 100644 --- a/docs/android.md +++ b/docs/android_eclipse.md @@ -3,97 +3,7 @@ Android ======= -The Android distribution of openFrameworks is setup to work with either the Eclipse IDE or the newer Android Studio IDE. The projects are currently using a custom toolchain based on Makefiles to compile and install applications. - -# Android Studio - -## Summary - -Setting up openFrameworks with Android Studio is fairly straightforward. The basic steps are: - -- Install Android Studio and the Android SDK -- Install the Android NDK (r10b or lower) -- Download openFrameworks from the download page or from git -- In Android Studio, use **File ➞ Import Project** and select the `settings.gradle` file in the root of the openFrameworks directory -- Set the path to the NDK in local.properties (`ndk.dir`) -- Build and run - -## Installation - -### Install Android Studio and the SDK - -Download and install Android Studio from http://tools.android.com/download/studio/stable (you need Android Studio 1.0 or higher). It should come with (or automatically install) a recent SDK, though you can customize the SDK version later from within Android Studio using **Tools ➞ Android ➞ SDK Manager**. - -In the event that Android Studio does not come with an SDK, you can install it from http://developer.android.com/sdk/index.html (under "Get the SDK for an existing IDE"). - -### Install the Android NDK - -For the current version of openFrameworks, you need to install Android NDK revision r10b or earlier. r10c breaks compatibility with some libraries, and should (at this time) be avoided. - -Here are download links for r9d, which has been tested and works fine: - -- Windows 32-bit: http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip -- Windows 64-bit: http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip -- Mac OS X 32-bit: http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2 -- Mac OS X 64-bit: http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2 -- Linux 32-bit (x86): http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2 -- Linux 64-bit (x86): http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2 - -On Windows, you will also need to install MinGW in order to build openFrameworks. MinGW provides some essential build tools which are not included in the NDK. Follow just the "Installing the MinGW and Msys" instructions on this page: http://www.multigesture.net/articles/how-to-install-mingw-msys-and-eclipse-on-windows/. - -### Download openFrameworks - -Download it from the downloads page: - -http://openframeworks.cc/download - -You may also check out the openFrameworks source from GitHub (under master branch): http://github.com/openframeworks/openFrameworks - -### Import the project - -At the Android Studio welcome screen select **Import Project**, or use the **File ➞ Import Project** menu item. Browse to the `settings.gradle` file in the `libs/openFrameworksCompiled/project/android` directory. Accept all the prompts and wait for Android Studio to set up the project. - -At this point you will get an error about the NDK not being configured. Onto the next step... - -### Configure the NDK - -Edit the file `local.properties` and add a line like this: - - ndk.dir=/path/to/the/ndk - -Save and resync the project (either press the "Try Again" link on the "Gradle project sync failed" banner, or use **Tools ➞ Android ➞ Sync Project with Gradle Files**). - -You'll have to wait a bit: the first sync will automatically build openFrameworks. If it doesn't work (Gradle sync still fails), try looking at the Troubleshooting tips. In some cases, clicking on the error in the console window will take you to a solution, such as installing various versions of the Android SDK. In some cases, you may have to do this several times to solve several missing dependencies. - -### Build and run - -Press the Play button next to the `androidEmptyExample` shown in the toolbar. With any luck, it should build the app, and momentarily deploy it to your Android device (or prompt you to deploy it on a suitable emulator). If the app runs, congratulations! You have setup openFrameworks. - -## Creating new projects - -1. Copy the provided example app (make sure to put it in a subdirectory of `apps`, at the same level as the sample) -2. Double-click on `build.gradle` and press "Add Now..." -3. If that doesn't work, add a line to `settings.gradle` including your project manually. -4. Perform a project sync (it should prompt you to do this). - -## Creating projects from examples - -1. Copy the `build.gradle` file from `androidEmptyExample` into the directory of the example you want to use. -2. Follow steps 2-4 above. - -## Troubleshooting - -- You may need to adjust the following numbers to match your installed Android Studio and Android SDK. Android Studio should offer to fix these values for you when you open the appropriate build files. - - - The Gradle version specified in `/build.gradle` - - The `compileSdkVersion`, `buildToolsVersion`, `minSdkVersion`, `targetSdkVersion` values - in `/addons/ofxAndroid/ofAndroidLib/build.gradle` and `/apps/myApps/androidEmptyExample/build.gradle` - -- If you get strange linker errors (e.g. errors about a missing `__srget`), try using the r9d version of the NDK. Newer NDKs (particularly r10c and up) don't work with some versions of OpenFrameworks. -- If you get strange linker errors when running the Android Simulator (e.g. `java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList`) make sure that your simulator is using the `armeabi-v7a`, not the `x86` or `x86_64` architecture. You can check your setup by opening your Android Virtual Device Manager and editing the device (**Tools ➞ Android ➞ AVD Manager** or click the AVD Manager icon in the toolbar). You may be prompted to download an appropriate system image for `armeabi-v7a`. - -Eclipse -======= +The Android distribution of openFrameworks is setup to work with either the Eclipse IDE or experimentally with the newer Android Studio IDE. The projects are currently using a custom toolchain based on Makefiles to compile and install applications. This information is also online: http://openframeworks.cc/setup/android-eclipse @@ -122,42 +32,37 @@ These instructions go into a lot of important detail, but the main steps are: Installation ------------ -**a) Eclipse**: download the C/C++ edition of Eclipse 4.2 (Juno) for your platform from here: - -http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/junosr1 +**a) Eclipse**: download the C/C++ edition of Eclipse 4.5 (Mars) or later for your platform from here: -These instructions were originally written using Eclipse 3.6 (Helios), but have been used for setting up Eclipse 4.2 (Juno). - -Ubuntu users: If downloading from the repositories, double check that the version of Eclipse is 3.6 (Helios) or higher. +http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/marsr You will need Java to use Eclipse, you can download it from java.com. For Linux, it will probably be in the official repositories. For example, in Ubuntu: - sudo apt-get install openjdk-6-jdk + sudo apt-get install openjdk-7-jdk or - sudo apt-get install sun-java6-jdk (this doesn't exist as of Ubuntu 10.10 (Maverick Meerkat)) + sudo apt-get install oracle-java8-installer **b) Android SDK**: This is the software that allows you to write Android apps. openFrameworks apps are written in C/C++, but you will still need this to interact with the NDK. You can download it from: http://developer.android.com/sdk/index.html -Uncompress it in any folder on your hard disk. Later you'll need to tell the openFrameworks makefiles where to find it. - -**c) Android NDK**: This is the C/C++ compiler, headers and libraries for Android. +Uncompress it in any folder on your hard disk. Later you'll need to tell eclipse where to find it. -- OS X: http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2 -- Linux: http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2 -- Windows: http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip +**c) Android NDK**: This is the C/C++ compiler, headers and libraries for Android. OF 0.9.0 has been tested with the NDK version r10e, newer versions might work but it's not guaranteed. -Other versions are available here, but we recommend using r8d for now: -http://developer.android.com/sdk/ndk/index.html +https://developer.android.com/ndk/downloads/index.html -There's a bug in the official NDK that makes apps crash on Android 2.1 and lower versions of Android so by now openFrameworks for Android will only work on Android 2.2 and above. +- OS X: http://dl.google.com/android/ndk/android-ndk-r10e-darwin-x86_64.bin +- Linux 32: http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86.bin +- Linux 64: http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin +- Windows 32: http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86.exe +- Windows 64: http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe -Uncompress this also to any place in your hard disk. We'll tell openFrameworks where to find it later. +On Windows, you will also need to install MinGW in order to build openFrameworks. MinGW provides some essential build tools which are not included in the NDK. Follow just the "Installing the MinGW and Msys" instructions on this page: http://www.multigesture.net/articles/how-to-install-mingw-msys-and-eclipse-on-windows/. **d) openFrameworks for Android package**: Download it from the downloads page: @@ -165,44 +70,25 @@ http://openframeworks.cc/download You may also check out the openFrameworks source from GitHub (under master branch): http://github.com/openframeworks/openFrameworks -**e) Install Ant:** - -This build tool is used to build, install and run applications on the Android device from the command line: - -- Ubuntu: - - sudo apt-get install ant-1.8 - -or for newer distributions: - - sudo apt-get install ant - -Other Linux distros have similar installation procedures. - -- OS X: - -Download and uncompress Apache Ant 1.8 or greater from http://ant.apache.org/bin/download.cgi - -Certain build tools like make might not be installed by default. To install these you can either: - -- Download and install Xcode. It's provided in the Mac App store, among other places. -- Or, just download the build tools separately. They were repackaged and are hosted on GitHub: https://github.com/kennethreitz/osx-gcc-installer - There are pkg files you can install for OS X 10.6 and 10.7. Note that this bundle doesn't include pkg-config, and errors may show up because it is missing, but you can ignore these. - -**f) Set the paths for the SDK, NDK and Ant:** +**f) Set the paths for the NDK:** Edit this file: openFrameworks/libs/openFrameworksCompiled/project/android/paths.make -This will tell openFrameworks where to find the SDK, NDK and Ant. +This will tell openFrameworks where to find the android NDK. If you don't have this file, create it from the paths.make.default template in the same directory. -- Set the values of SDK_ROOT and NDK_ROOT to their install paths +- Set the values of NDK_ROOT to their install paths + +The final file has to look something like: + +``` +# Default paths.make file. +# Enter the correct paths for your system and save this file as paths.make -- Set ANT_HOME: --- Linux: /usr --- OS X: Set it to the folder where you uncompressed Ant before. +NDK_ROOT=/home/arturo/Code/android-ndk-r10e +``` **g) Start Eclipse**: You will see a pop up asking you what workspace to use. Just point it to: openFrameworks/examples/android. @@ -225,21 +111,15 @@ You will see the SDK plugin in the list called "Developer Tools". Select it and press 'Next' until you get to the "Review Licenses" screen. Check the "I accept the terms of the license" checkbox and press 'Finish'. Eclipse will download and install the Android plugin. Once it finishes press 'Yes' in the popup to restart Eclipse. -**i) Set Eclipse Java compiler compliance to 1.6:** - -In the last version of Eclipse the Java compatibility should be set to version 6. You can check this in Window > Preferences > Java > Compiler. (Preferences is in the Eclipse menu for OS X.) - -The compiler compliance settings should be set to 1.6. - - **j) Configuring the Android plugin**: Once we have installed the Android plugin we need to tell it where to find the SDK. In Eclipse go to Window > Preferences > Android (or Eclipse > Preferences for OS X) and set the SDK location by browsing to the folder where you uncompressed the SDK before. - Now Eclipse knows where the SDK is. +Do the same for the path to the NDK. + Next you'll need to install the API files and optionally create an emulator to be able to test programs without uploading to the phone. Press the Android button in the Eclipse toolbar, or go to Window > Android SDK Manager. First you need to install the SDK platform-tools and API package. Just click on the "Tools" tab and select the box for Android SDK Platform-tools. Then click on the "Android 4.2 (API 17)" tab and select the box for SDK Platform. It's important to use SDK version 4.2 (API 17) since the makefiles are configured for that version. It doesn't matter what version of the Android OS you want to develop for, apps are compiled using SDK 4.2, but they should work on any phone that is at least 2.2. @@ -253,17 +133,16 @@ File > Import and select General > Existing projects in the workspace... Import in this order: -- openFrameworks/libs -- openFrameworks/libs/openFrameworks -- openFrameworks/addons/ofxAndroid/ofAndroidLib -- openFrameworks/examples/android +- openFrameworks/libs/openFrameworks +- openFrameworks/addons/ofxAndroid/ofAndroidLib +- openFrameworks/examples/android/androidEmptyExample + +You can later import more examples if you want but it's recommended to not have many examples opened at the same time so eclipse works faster **l) Compile openFrameworks**: In the "Project Explorer" on the left side of the window, select the openFrameworks project. Choose the Android target in Project > Build Configurations > Set Active, and then click Project > Build Project. You can also do this from the toolbar by switching to the C/C++ perspective and clicking the toolbar button with a hammer. -OS X seems to be missing pkg-config. Currently this doesn't seem to affect the build, since these commands were only important in detecting Linux libraries. - **m) Enable development in your device:** Enable USB debugging: Settings > Applications > Development > USB Debug (On Ice Cream Sandwich, this is in Settings > Developer options > USB Debugging). The device needs to be disconnected from the computer while you do this. diff --git a/docs/android_studio.md b/docs/android_studio.md new file mode 100644 index 00000000000..09086620be9 --- /dev/null +++ b/docs/android_studio.md @@ -0,0 +1,113 @@ +[openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) + +Android +======= + +The Android distribution of openFrameworks is setup to work with either the Eclipse IDE or experimentally Android Studio IDE. The projects are currently using a custom toolchain based on Makefiles to compile and install applications. + +# Android Studio + +Android studio support in openFrameworks is still experimental. The latest version of android studio still doesn't have full support for c++ development so even if it's deprecated we still recomend to use eclipse and the ADT plugin if you want to have code completeion in c++. See android-eclipse.md in the docs folder or the corresponding guide in the download page. + +## Summary + +Setting up openFrameworks with Android Studio is fairly straightforward. The basic steps are: + +- Install Android Studio and the Android SDK +- Install the Android NDK (actually tested version is r10e) +- Download openFrameworks from the download page or from git +- Set the path to the NDK in local.properties (`ndk.dir`) +- In Android Studio, use **File ➞ Import Project** and select an openFrameworks example from the examples/android folder +- Build and run + +## Installation + +### Install Android Studio and the SDK + +Download and install Android Studio from http://tools.android.com/download/studio/stable (you need Android Studio 1.0 or higher). It should come with (or automatically install) a recent SDK, though you can customize the SDK version later from within Android Studio using **Tools ➞ Android ➞ SDK Manager**. + +In the event that Android Studio does not come with an SDK, you can install it from http://developer.android.com/sdk/index.html (under "Get the SDK for an existing IDE"). + +### Install the Android NDK + +This is the C/C++ compiler, headers and libraries for Android. OF 0.9.0 has been tested with the NDK version r10e, newer versions might work but it's not guaranteed. + +https://developer.android.com/ndk/downloads/index.html + +- OS X: http://dl.google.com/android/ndk/android-ndk-r10e-darwin-x86_64.bin +- Linux 32: http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86.bin +- Linux 64: http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin +- Windows 32: http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86.exe +- Windows 64: http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe + +On Windows, you will also need to install MinGW in order to build openFrameworks. MinGW provides some essential build tools which are not included in the NDK. Follow just the "Installing the MinGW and Msys" instructions on this page: http://www.multigesture.net/articles/how-to-install-mingw-msys-and-eclipse-on-windows/. + +### Download openFrameworks + +Download it from the downloads page: + +http://openframeworks.cc/download + +You may also check out the openFrameworks source from GitHub (under master branch): http://github.com/openframeworks/openFrameworks + +Or download the latest nightly: +http://openframeworks.cc/download (bottom of the page) + +### Configure the NDK + +With a text editor, edit the file `libs/openFrameworksCompiled/project/android/paths.make` and set the NDK path to the correct folder: + + NDK_ROOT=/path/to/the/ndk + +### Import the project + +At the Android Studio welcome screen select **Open an Existing Android Studio Project**. + +![](images/android/open-existing-project.png) + +Then browse to any of the android examples in `examples/android`. + +![Opening androidEmptyExample](images/android/androidEmptyExample.png) + +Accept all the prompts and wait for Android Studio to set up the project. + +You'll have to wait a bit: the first sync will automatically build openFrameworks. If it doesn't work (Gradle sync still fails), try looking at the Troubleshooting tips. In some cases, clicking on the error in the console window will take you to a solution, such as installing various versions of the Android SDK. In some cases, you may have to do this several times to solve several missing dependencies. + +### Build and run + +Press the Play button next to the `androidEmptyExample` shown in the toolbar. With any luck, it should build the app, and momentarily deploy it to your Android device (or prompt you to deploy it on a suitable emulator). If the app runs, congratulations! You have setup openFrameworks. + +### Editing the c++ source code + +Android studio in it's version 1.3 still has very limited support for c++ source code editing. In any case to work with openFrameworks, you'll want to switch from the Android view to the Project one where you can see all the files in the project including the C++ source code: + +![Project view](images/android/projectview.png) +![Opening ofApp](images/android/ofApp.png) +![Full view](images/android/full.png) + +## Creating new projects + +1. Copy any of the provided example app (make sure to put it in a subdirectory of `apps`, at the same level as the sample) +2. Edit the file AndroidManifest.xml and change every appearance to the original name to the new name of you application. +3. In srcJava/cc/openFrameworks change the name of the folder to the new name of you application. +4. Edit the file srcJava/cc/openFrameworks/newApplicationName/OFActivity.java and change the name of the package to the correct new name. +5. Edit the file res/values/strings.xml and change the value of app_name to the new name of the application. +6. Import the new project from android studio + +## Troubleshooting + +- You may need to adjust the following numbers to match your installed Android Studio and Android SDK. Android Studio should offer to fix these values for you when you open the appropriate build files. + + - The Gradle version specified in `/build.gradle` + - The `compileSdkVersion`, `buildToolsVersion`, `minSdkVersion`, `targetSdkVersion` values + in `/addons/ofxAndroid/ofAndroidLib/build.gradle` and `/apps/myApps/androidEmptyExample/build.gradle` + +- If you get strange linker errors, check that you are using the 10e version of the NDK. Newer NDKs might work but usually there's some always some fixes that need to be done when moving to a new NDK version. + +- If your connected device is not recognized by Android Studio, restart adb + with `adb kill-server && adb start-server` + +- If, when syncronizing a project for the first time, clicking on the console + messages does not solves the problem regarding a missing dependency of the + android API (like for example Android API 22), open the sdk from the console, + select the missing API and install it diff --git a/docs/codeblocks.md b/docs/codeblocks.md deleted file mode 100644 index 9d6e535bdf2..00000000000 --- a/docs/codeblocks.md +++ /dev/null @@ -1,55 +0,0 @@ -[openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) - -Code::Blocks - Windows -====================== - -We like Code::Blocks for Windows development since it's light weight, and avoids some of the quirkiness of Windows Visual Studio. Here's a step by step tutorial to get up and running. -**Note**: [Additions](#additions) are required to run openFrameworks. Please do not skip this step. - -Installation ------------- -Follow the steps [here][1]. - -Additions ---------- -1. Download the files -> [Additions for Code::Blocks to work with openFrameworks][2] - -2. In the zip there are two folders, you need to put the **contents** of them into the contents of folders in MinGW. - - * Add the _contents_ of the folder "**add\_to\_codeblocks\_mingw\_include**" into "**C:\\Program Files\\CodeBlocks\\MinGW\\include**" (or wherever your app\\mingw\\include is) - * Add the _contents_ of the folder "**add\_to\_codeblocks\_mingw\_lib**" into "**C:\\Program Files\\CodeBlocks\\MinGW\\lib**" (or wherever your app\\mingw\\lib is) - -These are additional libs and header files that need to be added to the MinGW distribution that comes with Code::Blocks. - -Here's a quick video which shows what this should look like: [copy steps for codeblocks][3]. - -Workspaces ----------- - -You should open up the workspace that comes with each project: - -`imageSaverExample.cbp` -`imageSaverExample.workspace` **<------ load this** - -The workspaces load both the imageSaverExample project as well as the openframeworksLib project, and -will recompile the openframeworks library as needed. - -### A few points: - -1. It's easy to open up multiple projects into the workspace. Remember to close the workspace before working -with a new project. If you accidently open up other projects into the workspace, just don't save it. - -2. Within each workspace, it's easy to highlight which project you want to build by clicking it. -Choose the "project", ie, imageSaverExample as opposed to the openframeworks lib. - -New project ------------ - -To create a new project, you could simply use the projectGenerator. [See here how to](projectgenerator.md). - -**As always have fun!** - -[1]: http://www.openframeworks.cc/setup/codeblocks -[2]: http://www.openframeworks.cc/content/files/codeblocks_additions.zip -[3]: http://vimeo.com/33985058 diff --git a/docs/images/android/androidEmptyExample.png b/docs/images/android/androidEmptyExample.png new file mode 100644 index 00000000000..b0492edc208 Binary files /dev/null and b/docs/images/android/androidEmptyExample.png differ diff --git a/docs/images/android/full.png b/docs/images/android/full.png new file mode 100644 index 00000000000..6a8acc9f45f Binary files /dev/null and b/docs/images/android/full.png differ diff --git a/docs/images/android/ofApp.png b/docs/images/android/ofApp.png new file mode 100644 index 00000000000..5e5e9b6b5c6 Binary files /dev/null and b/docs/images/android/ofApp.png differ diff --git a/docs/images/android/open-existing-project.png b/docs/images/android/open-existing-project.png new file mode 100644 index 00000000000..3ecd9bdefde Binary files /dev/null and b/docs/images/android/open-existing-project.png differ diff --git a/docs/images/android/projectview.png b/docs/images/android/projectview.png new file mode 100644 index 00000000000..71df51f7127 Binary files /dev/null and b/docs/images/android/projectview.png differ diff --git a/docs/linux.md b/docs/linux.md index 58c5f9cf6fd..8e7d7273f97 100644 --- a/docs/linux.md +++ b/docs/linux.md @@ -1,162 +1,45 @@ [openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) -Linux -===== +Linux install +========== -a) Installation ---------------- +Before you can use OF in linux you'll need to run a couple of scripts to install some dependencies and compile the OF library itself and the project generator. -Inside the scripts folder you'll find some scripts in the ubuntu, debian, fedora -and archlinux folders which will install everything you need to use openFrameworks. -Inside those folders there's a file called `install_codeblocks.sh` that will install -a current Code::Blocks version. Please use this script to install Code::Blocks, -it will avoid problems with some old Code::Blocks versions, but typically your -distribution's current version will be installed. -There's also a script called `install_dependencies.sh` that will install -all the libraries needed to use openFrameworks under Linux. +First of all you'll need to execute the install_dependencies.sh script for your distribution which is located in `scripts/linux/dsitro_name/install_dependencies.sh` -You will need to run from a console: +For example if you are using ubuntu, from a console: -for ubuntu: +``` +cd OF/scripts/linux/ubuntu +sudo ./install_dependencies.sh +``` - cd your_oF_directory/scripts/linux/ubuntu - sudo ./install_codeblocks.sh - sudo ./install_dependencies.sh - if you want to have support for mp3 and some video codecs: - sudo ./install_codecs.sh +Next if you want to use some formats like mp3 you'll need to run the install_codecs script, it's in the same folder and is run the same way as the install_dependencies one. We separate them cause mp3 and some other formats installed by the script might be protected by patents in some countries and could be problematic to use in comercial work. -for debian: +The OF source code comes uncompiled so the first time you compile an example it would need to compile it to, if you go and compile any example it would compile OF as a dependency but to make that easier and catch any potential problems let's do that as a separate step: - su - - cd your_oF_directory/scripts/linux/debian - ./install_codeblocks.sh - ./install_dependencies.sh - if you want to have support for mp3 and some video codecs: - sudo ./install_codecs.sh - -for fedora +``` +cd OF/scritps/linux +./compileOF.sh -j3 +``` - su - - cd your_oF_directory/scripts/linux/fedora - ./install_codeblocks.sh - ./install_dependencies.sh - if you want to have support for mp3 and some video codecs: - sudo ./install_codecs.sh +`-j3` tells the script to use 3 cpus to compile, you can specify as many as you want but it's recommended to use the number of cores in your computer or less. -for archlinux +With this you can already go into any of the examples folders and compile the examples using make: - su - - cd your_oF_directory/scripts/linux/archlinux - ./install_codeblocks.sh - ./install_dependencies.sh - if you want to have support for mp3 and some video codecs: - sudo ./install_codecs.sh +``` +cd OF/examples/graphics/polygonExample +make +make Run +``` -That's all, now go to the your_oF_directory/examples folder, where you will find -the examples, and have fun! +Or use any of the officially supported IDEs: [qtcreator](../qtcreator/) or [eclipse](../eclipse/) both IDEs have plugins that allow to create new projects, import existing ones, add addons to them. +If you want to install the project generator, a tool that allows to create and update an OF project you'll need to run a last script: -b) Other distributions ----------------------- - -If you are using a different distribution than ubuntu, debian, fedora or archlinux, -please take a look at one of the `install_dependencies.sh` scripts from -one of the supported distributions to know what libraries you need to install. -Also, if you have problems or manage to install OF in any other distribution, -please post in the forums so we can add it to the next release. - - -c) projectGenerator -------------------- - -This is an openFrameworks application that will make your life easier when -creating projects or adding addons to existing ones. It will be compiled when -you run the install_dependencies.sh script. - -To use it open the executable in OF_ROOT/projectGenerator. You can find more -instructions in that folder too. - - -d) Code::Blocks Wizard ----------------------- -You can also install a Code::Blocks wizard to create new projects, check the -instructions in scripts/linux/codeblocks_wizard. - - -e) Code::Blocks projects ------------------------- - -Code::Blocks projects are now using Makefiles to make the configuration easier. -Take a look at the next section to see how it works, to add search paths or -libraries you need to edit config.make, if you want to add addons, edit addons.make. - - -f) Makefile ------------ - -Every example has a Makefile you can configure using the files config.make -and addons.make. - -config.make: This file has options to add search paths, libraries, etc., the -syntax is the usual syntax in makefiles, there's help comments inside the file. - -addons.make: if you want to use an addon which is inside the addons folder, just -add its name in a new line in this file. - - -g) Post build steps: --------------------- - -Some folks have mentioned trouble with post-build step which copies the export -directory into the bin folder. if you have issues, please let us know, -and especially what Linux you are running, what version of Code::Blocks, etc... -(please read the readme in export to understand the post build step). - -In a previous release, we've modified the script to use `$(PROJECT_DIR)bin` instead of -`$(TARGET_OUTPUT_DIR)bin/`, since this lead to `bin/bin` on some versions of CB. -It should work now on all versions (fingers crossed). - -One problem occurs if you try to compile OF from a folder you reached in nautilus -via a symbolic link: - -The error will look like this: - - cp -r ../../../export/libs /home/zach/Desktop/Link to openframeworks/0.05/0.05b_fat/apps/addonsExamples/allTestExample/bin/ - cp: target `openframeworks/0.05/0.05b_fat/apps/addonsExamples/allTestExample/bin/' is not a directory: No such file or directory - Process terminated with status 1 (0 minutes, 1 seconds) - 0 errors, 0 warnings - -So, don't open up the project via a symbolic link. We will report this to CB forum. - - -h) Other scripts ----------------- - -We've created a /scripts directory to make everyone life easier, and to get a -hang of building / cleaning multiple projects at once. -Also, you can enable or disable running app from within CB via our hacked out -build = build + run system. -We are hoping that crafty folk will get into scripting, esp. as it relates to -addons, etc. Please share any helpful scripts on the forum. - - -i) Linux info, advice, etc --------------------------- - -The linux version of openFrameworks is in some way different to Windows and MacOS, -mainly the video support provided by quicktime doesn't exist here. From OF 0.06, -this is provided with gStreamer for video files and unicap for cameras. -Although it has been tested, some cameras and video formats can pose some -issues, if you have some problem please post in the forum as much info -as possible. - - -Libs ----- -The `export/` folder contains necessary components that need to be exported with the application: -contains .so (shared objects) that the app needs to run against this allows OF linux apps to be released in a very portable way. -Users of the apps shouldn't need to install anything besides glut (which should be installed in most cases). - - -many thanks!! OFteam +``` +cd OF/scritps/linux +./compilePG.sh +``` +which will compile the command line version of the project generator and install it in your system so you can create projects from anywhere, it'll also make it possible to use the gui tool which is present in the root of the OF folder. diff --git a/docs/msys2.md b/docs/msys2.md new file mode 100644 index 00000000000..3737ea6b3db --- /dev/null +++ b/docs/msys2.md @@ -0,0 +1,105 @@ +[openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) + +MSYS2 +===== + +Installing MSYS2 +---------------- + +First, install MSYS2 using the [one-click installer](https://msys2.github.io/) or +directly unzipping the archive from their [repository](http://sourceforge.net/projects/msys2/files/Base/x86_64/) + +If you are going to use QtCreator you should install msys2 in the default install folder, c:\msys64 + +Open a MSYS2 shell and update the system packages : + + pacman --noconfirm --needed -Sy bash pacman pacman-mirrors msys2-runtime + +Close the shell and open a new one to update the remaining packages : + + pacman --noconfirm -Su + +You are now ready to install openFrameworks. + + +Installing openFrameworks +------------------------- + +Download and unzip the msys2 version of oF. + +Open an MSYS shell and install OF dependencies: + + cd your_oF_directory/scripts/msys2 + ./install_dependencies.sh + +Open an **MINGW32** shell and compile oF libraries: + + cd your_oF_directory/libs/openFrameworksCompiled/project + make + +You can speed-up compilation using parallel build `make -j${NUMBER_OF_PROCESSORS}` + + +Running examples +---------------- +Compile the example (for example the 3DPrimitivesExample) + + cd your_oF_directory/examples/3d/3DPrimitivesExample + make + +At this point, `make run` or double-click on the exe file to launch. + + +Makefile +-------- + +Every example has a Makefile you can configure using the files config.make +and addons.make. + +config.make: This file has options to add search paths, libraries, etc., the +syntax is the usual syntax in makefiles, there's help comments inside the file. + +addons.make: if you want to use an addon which is inside the addons folder, just +add its name in a new line in this file. + +Dlls +---- + +Windows applications compiled with msys2 need some system dlls to run. If you are going to run the application in a different machine where you don't wont to install msys2 you can run: + + make copy_dlls + +from the msys2 terminal and it'll copy the necesary dlls to the project bin folder. Now you can copy that bin folder to any computer and it will run right away without having to install msys2. + +This is still experimental so if you find any problem please [report it on github](https://github.com/openframeworks/openFrameworks/new?title=Problem%20with%20msys2%20dlls) + +QtCreator +--------- + +With msys2 you can also use QtCreator as an IDE, you can find more information in the corresponding setup guide: + +http://openframeworks.cc/setup/qtcreator + +FAQ / Common problems +--------------------- +- "I have a TLSv1_1_client_method missing error" when I double-click the exe ?" + +The executable looks for ssleay32.dll and libeay32.dll and it first finds a version that doesn't support TLS v1.1. Often it happens with Intel iCls software. The solution is to move the your_msys2_directory\mingw32\bin path before the conflicting path. If the conflicting path is in the system PATH and you do not have administrative privileges, copy/link ssleay32.dll and libeay32.dll from your_msys2_directory\mingw32\bin to the executable folder. + +- "I'm on a corporate network with a proxy. I cannot download packages with pacman." + +You may need to set HTTP_PROXY and HTTPS_PROXY environment variables. + + From a DOS/CMD prompt : + set http_proxy=http://your_proxy:your_port + set http_proxy=http://username:password@your_proxy:your_port + set https_proxy=https://your_proxy:your_port + set https_proxy=https://username:password@your_proxy:your_port +Don't forget to escape special characters in your password... + + + + + +many thanks!! OFteam + diff --git a/docs/projectgenerator.md b/docs/projectgenerator.md index b051cc25342..dc83f136cdc 100644 --- a/docs/projectgenerator.md +++ b/docs/projectgenerator.md @@ -1,17 +1,25 @@ -[openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) +[openFrameworks](http://openframeworks.cc/) | [Documentation table of contents](table_of_contents.md) projectGenerator ================ About ----- -* The tool can be used to generate project files for the platform you've downloaded (osx Xcode, Windows Codeblocks, etc). +* The tool can be used to generate project files for the platform you've downloaded (osx Xcode, Windows, etc). * The project generator can add addons to your project, but not all addons (especially non core addons) are packaged in the right way for this. -* It assumes you will want to put your project in `root/apps/myApps`, but you can put your projects anywhere relative to OF, and it should work. Putting your apps in non standard paths (ie, not at a height of `../../../`) is not recommended. +* It assumes you will want to put your project in `OF_ROOT/apps/myApps`, but you can put your projects anywhere relative to OF, and it should work. Putting your apps in non standard paths (ie, not at a height of `../../../`) is not recommended. Also putting your apps outside of the OF folder itself is not recommended, since that makes the relative path system more fragile. + +*NOTE: If you are on linux, be sure to run the install_dependencies.sh script, which will install necessary components for this.* + + +Changes +----- +This project generator is new since 0.9 -- the original one in earlier OF releases only allowed you to make new projects, this one allows for updating existing projects as well as recursive updating. + Usage ----- -It's pretty simple to make an new project, there are 3 things you can adjust: +It's pretty simple to make an new project, or update an exisiting project, in the simple mode. there are 3 things you can adjust: 1. **Name of the project** This is where you set the name of the project. This creates both a folder with this name and a project file, so for example, if your name is "myCoolExample" it will generate: @@ -22,9 +30,23 @@ This defaults to `apps/myApps`, but it should allow you to put projects anywhere `chosenPath/projectName/projectName.project` (where chosenPath and projectName are based on your settings, and .project is the xcode, code blocks, visual studio file that's generated). 3. **Addons** -To use, choose addons in the GUI then hit the back button. -Here you can select the addons you'd like included. Not all addons work, but all of the core addons should and if the addon doesn't work, you can tell the addon developer to take a look at it. The project generator is basically searching the file system recursively through the addons, and it's looking for things like folders that say "osx" on them, etc, so it can make decisions about what to include / exclude, etc. For most simple addons, this should work fairly well, but we haven't tested with many addons yet. -After this release is out, we'll spend some time to document exactly how our system parses, and some of the more intricate nuances that will help addon developers make PG friendly releases. +To use, choose addons you want to add, and/or remove ones you don't want. Not all addons work with the PG, but all of the core addons should and if the addon doesn't work, you can tell the addon developer to take a look at it. The project generator is basically searching the file system recursively through the addons, and it's looking for things like folders that say "osx" on them, etc, so it can make decisions about what to include / exclude, etc. For more complex addons, you may need to read the documentation or reach out to the addon author for more info. Also note that not all addons are designed for every platform. 4. **Generate** -When you hit this button, hopefully magic will happen. Some addons take a very long time to parse (such as opencv) so please be patient. If you add a lot of addons, it can sometimes take several seconds for a project to generate. +When you hit this button, hopefully magic will happen. Some addons take a very long time to parse (such as opencv) so please be patient. If you add a lot of addons, it can sometimes take several seconds for a project to generate. You should see a success message with the option of opening the folder or opening the project in an IDE. + +Settings +----- + +In the settings panel, you can update the path to the root of openframeworks. This is the folder that is the base level, which contains "libs", "addons", etc. There are also options for advanced mode (see below) and verbose output. Verbose output runs the project generator w/ verbose flag, which gives a ton of details about how its adding an addon and what it's doing. + + +Advanced +----- + +Since 0.9 the project generator features an advanced mode, which gives you additional functionalities. You can choose other platforms for cross platform development (Note: this is useful only if you are working from the master branch or have those other templates available). Also, it can recursively update projects, useful if you are working with a folder full of project files that you want to test in a newer version of OF. + +Technical considerations +----- + +This project generator uses two tools -- a command line tool and an gui front end. The command line tool is very powerful, and in later releases we will expose this more for the end users to install locally on their machines, etc since it is really helpful for advanced users. For now, if you poke around the PG folders, you can find this tool (it's in slightly different locations on osx, windows and linux). On linux this is compiled and installed for you. This command line tool is wrapped in a gui front end which uses electron (http://electron.atom.io/). \ No newline at end of file diff --git a/docs/table_of_contents.md b/docs/table_of_contents.md index 9380b102edd..15c9750f6f2 100644 --- a/docs/table_of_contents.md +++ b/docs/table_of_contents.md @@ -6,15 +6,18 @@ openFrameworks is a C++ toolkit for creative coding. Getting started --------------- -* [Android](android.md) — A guide to install on Android environment. +* [supported platforms](PLATFORMS.md) - A list of supported hardware and software platforms. * [Linux](linux.md) — A guide to install on Linux environment. * [OS X](osx.md) — A guide to install on OS X environment. -* [Code::Block](codeblocks.md) — A guide to configure Code::Block on Windows environment. -* [Visual Studio](visualstudio.md) — A guide to configure Visual Studio on Windows environment. +* [Android Eclipse](android_eclipse.md) — A guide to install for Android using the Eclipse IDE. +* [Android Studio](android_studio.md) - A guide to install for Android Studio IDE. +* [Code::Block](codeblocks.md) — A guide to configure Code::Block on Windows. +* [Visual Studio](visualstudio.md) — A guide to configure Visual Studio on Windows. +* [MSYS2](msys2.md) — A guide to install on Windows using MSYS2. Usage ----- -* [Examples and Apps](apps.md) — An introduction to making use of openFrameworks core. +* [Examples and Apps](apps.md) — An introduction to openFrameworks. * [projectGenerator](projectgenerator.md) — Usage of the tool to generate projects. About @@ -24,4 +27,6 @@ About More ---- -* [Wiki](http://wiki.openframeworks.cc) — Going further with openFrameworks. +* [Reference](http://openframeworks.cc/documentation) — openFrameworks reference. +* [Tutorials](http://openframeworks.cc/tutorials) — openFrameworks tutorials. +* [Forum](http://forum.openframeworks.cc) — The openFrameworks forum. diff --git a/docs/visualstudio.md b/docs/visualstudio.md index fd31f2f57b8..0f60b4d3d6c 100644 --- a/docs/visualstudio.md +++ b/docs/visualstudio.md @@ -5,18 +5,18 @@ Visual Studio Installation ------------ -To getting started with openFrameworks and Visual Studio, you need to have Visual Studio 2012 installed. +To getting started with openFrameworks and Visual Studio, you need to have [Visual Studio 2015](https://www.visualstudio.com) installed. Any version should work, Express included. -There are many versions of Visual Studio. If you don't know which one to install, then we recommend Visual Studio 2012 Express for Desktop. -Each generation of Visual Studio (i.e. 2008, 2010, 2012) comes with a different C++ compiler (a compiler is what makes your c++ code into an executable that you can run). +There are many versions of Visual Studio. If you don't know which one to install, then we recommend [Visual Studio Community 2015](https://www.visualstudio.com/products/visual-studio-community-vs.aspx). +Each generation of Visual Studio (i.e. 2010, 2012, 2015) comes with a different C++ compiler (a compiler is what makes your c++ code into an executable that you can run). Generally, projects created in different generations of Visual Studio are not compatible with each other, but you can upgrade files from old generations to new generations. **See [setup guide](http://openframeworks.cc/setup/vs) for more detailed instructions.** -_Visual Studio Express is a special version of Visual Studio which is free to download and use indefinitely. There appears to be no restriction of commercial use for Visual Studio Express -versions, but Express versions have a reduced feature set whilst sharing the same compiler and general interface of the more premium versions (e.g. Professsional, Premium, Ultimate, etc). -The premium versions are only really recommended for more commercial oF users, for students who can otherwise get these versions for free, or for users who know for definite that they need -the premium features which aren't available in the Express distributions._ +_Visual Studio Community is free for individual developers, open source projects, academic research, education, and small professional teams. +Community versions have a reduced feature set whilst sharing the same compiler and general interface of the more premium versions (e.g. Professional, Enterprise etc). +The premium versions are only really recommended for more commercial oF users, for students who can otherwise get these versions for free, or for users who know for definite that they need +the premium features which aren't available in the Community distributions._ Creating a new openFrameworks project ------------------------------------- @@ -24,13 +24,13 @@ See [projectGenerator page](projectgenerator.md), to understand the usage of thi Open your new Solution ---------------------- -Every openFrameworks application is represented by a **'Solution'** and a **'Project'**. A solution is a collection of (generally) co-dependent projects. -The solution for your project contains your project, and the openFrameworks project, which is a library of all openFrameworks functions and classes +Every openFrameworks application is represented by a **'Solution'** and a **'Project'**. A solution is a collection of (generally) co-dependent projects. +The solution for your project contains your project, and the openFrameworks project, which is a library of all openFrameworks functions and classes which can be used by your project. -Your solution filename will be `openFrameworks/apps/[your name]/[project name]/[project name].sln`. Open this file with Visual Studio either by double +Your solution filename will be `openFrameworks/apps/[your name]/[project name]/[project name].sln`. Open this file with Visual Studio either by double clicking on it in Explorer, or selecting File>Open>Project/Solution... inside Visual Studio. -Compile and Run +Compile and Run --------------- Open your solution file `[project].sln`, and hit **F5**. This should compile and run your project. You should see a blank OpenGL window appear. _If Visual Studio complains that your project cannot be started, try right clicking on your project in the 'Solution Explorer' and select 'Set as startup project' and then try F5 again._ @@ -44,8 +44,8 @@ These are two build configurations, **"Debug"** and **"Release"**: Change the world ---------------- -Now it's time to get to work coding with openFrameworks. Hit 'Esc' to exit the blank, boring application you just built, and start editing `testApp.cpp` -and `testApp.h` to finally put to rest your critics and friends and make that generative/interactive/totally awesome piece of work that you've been wanting +Now it's time to get to work coding with openFrameworks. Hit 'Esc' to exit the blank, boring application you just built, and start editing `testApp.cpp` +and `testApp.h` to finally put to rest your critics and friends and make that generative/interactive/totally awesome piece of work that you've been wanting to get out. Just be careful not to forget your friends and critics in the process! diff --git a/examples/.gitignore b/examples/.gitignore index 0962fb939a5..1e92bef66b2 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -34,6 +34,12 @@ /*/*/.project /*/*/.settings/ +# QtCreator +/*/*/*.qbs +/*/*/*.qbs.user +/*/*/*.pro +/*/*/*.pro.user + ######################### # operating system ######################### diff --git a/examples/3d/3DPrimitivesExample/src/ofApp.cpp b/examples/3d/3DPrimitivesExample/src/ofApp.cpp index e972af24329..a2f8eab4868 100644 --- a/examples/3d/3DPrimitivesExample/src/ofApp.cpp +++ b/examples/3d/3DPrimitivesExample/src/ofApp.cpp @@ -45,9 +45,9 @@ void ofApp::setup(){ pointLight3.setSpecularColor( ofFloatColor(18.f/255.f,150.f/255.f,135.f/255.f) ); // shininess is a value between 0 - 128, 128 being the most shiny // - material.setShininess( 120 ); + material.setShininess( 120 ); // the light highlight of the material // - material.setSpecularColor(ofColor(255, 255, 255, 255)); + material.setSpecularColor(ofColor(255, 255, 255, 255)); ofSetSphereResolution(24); @@ -87,14 +87,15 @@ void ofApp::draw() { pointLight.enable(); pointLight2.enable(); pointLight3.enable(); - - material.begin(); - - - ofSetColor(180); + + + + // draw the outer sphere + material.begin(); ofNoFill(); ofDrawSphere(ofGetWidth()/2, ofGetHeight()/2, ofGetWidth()); - + material.end(); + if(mode == 1 || mode == 3) texture.getTexture().bind(); if(mode == 2) vidGrabber.getTexture().bind(); @@ -112,7 +113,7 @@ void ofApp::draw() { float planeAngleX = ofGetElapsedTimef()*3.6; float planeAngleInc = 3.f/(float)planeDims.x; ofVec3f vert; - for(int i = 0; i < deformPlane.getNumIndices(); i++ ) { + for(size_t i = 0; i < deformPlane.getNumIndices(); i++ ) { planeAngleX += planeAngleInc; int ii = deformPlane.getIndex( i ); vert = deformPlane.getVertex( ii ); @@ -120,10 +121,18 @@ void ofApp::draw() { deformPlane.setVertex( ii, vert ); } } + + if(!bFill && bWireframe){ + // if we are only drawing the wireframe, use + // the material to draw it, otherwise the material + // will be bound and unbound for every geometry + // and the wireframe will be drawn in black + material.begin(); + } if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { plane.transformGL(); deformPlane.draw(); @@ -131,31 +140,26 @@ void ofApp::draw() { } else { plane.draw(); } + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill) ofSetColor(255); plane.setPosition(plane.getPosition().x, plane.getPosition().y, plane.getPosition().z+1); - //if(bFill) { - if( mode == 3 ) { - ofSetColor(255); - } plane.drawWireframe(); - //} plane.setPosition(plane.getPosition().x, plane.getPosition().y, plane.getPosition().z-2); } - - + // Box // box.setPosition(ofGetWidth()*.5, ofGetHeight()*.25, 0); box.rotate(spinX, 1.0, 0.0, 0.0); box.rotate(spinY, 0, 1.0, 0.0); if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { box.transformGL(); for(int i = 0; i < ofBoxPrimitive::SIDES_TOTAL; i++ ) { @@ -168,15 +172,13 @@ void ofApp::draw() { } else { box.draw(); } + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill) ofSetColor(255); box.setScale(1.01f); - if(mode == 3) { - ofSetColor(255); - } box.drawWireframe(); box.setScale(1.f); } @@ -193,13 +195,13 @@ void ofApp::draw() { } if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { float angle = ofGetElapsedTimef()*3.2; float strength = (sin( angle+.25 )) * .5f * 5.f; ofVec3f faceNormal; - for(int i = 0; i < triangles.size(); i++ ) { + for(size_t i = 0; i < triangles.size(); i++ ) { // store the face normal here. // we change the vertices, which makes the face normal change // every time that we call getFaceNormal // @@ -211,12 +213,12 @@ void ofApp::draw() { sphere.getMesh().setFromTriangles( triangles ); } sphere.draw(); - + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill) ofSetColor(255); sphere.setScale(1.01f); sphere.drawWireframe(); sphere.setScale(1.f); @@ -233,13 +235,13 @@ void ofApp::draw() { } if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { float angle = (ofGetElapsedTimef() * 1.4); ofVec3f faceNormal; - for(int i = 0; i < triangles.size(); i++ ) { + for(size_t i = 0; i < triangles.size(); i++ ) { float frc = ofSignedNoise(angle* (float)i * .1, angle*.05) * 4; faceNormal = triangles[i].getFaceNormal(); for(int j = 0; j < 3; j++ ) { @@ -250,11 +252,12 @@ void ofApp::draw() { } icoSphere.draw(); + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill) ofSetColor(255); icoSphere.setScale(1.01f); icoSphere.drawWireframe(); icoSphere.setScale(1.f); @@ -272,8 +275,8 @@ void ofApp::draw() { cylinder.rotate(spinX, 1.0, 0.0, 0.0); cylinder.rotate(spinY, 0, 1.0, 0.0); if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { cylinder.transformGL(); ofPushMatrix(); { @@ -297,11 +300,12 @@ void ofApp::draw() { } else { cylinder.draw(); } + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill || mode == 3) ofSetColor(255); cylinder.setScale(1.01f); cylinder.drawWireframe(); cylinder.setScale(1.0f); @@ -318,8 +322,8 @@ void ofApp::draw() { body = cone.getConeMesh(); } if(bFill) { + material.begin(); ofFill(); - ofSetColor(255); if(mode == 3) { cone.transformGL(); ofPushMatrix(); @@ -339,15 +343,20 @@ void ofApp::draw() { } else { cone.draw(); } + material.end(); } + if(bWireframe) { ofNoFill(); ofSetColor(0, 0, 0); - if(!bFill || mode == 3) ofSetColor(255); cone.setScale(1.01f); cone.drawWireframe(); cone.setScale(1.0f); } + + if(!bFill && bWireframe){ + material.end(); + } if(mode == 1 || mode == 3) texture.getTexture().unbind(); if(mode == 2) vidGrabber.getTexture().unbind(); diff --git a/examples/3d/advanced3dExample/src/ofApp.cpp b/examples/3d/advanced3dExample/src/ofApp.cpp index aefd982922c..7e836866b3c 100644 --- a/examples/3d/advanced3dExample/src/ofApp.cpp +++ b/examples/3d/advanced3dExample/src/ofApp.cpp @@ -126,10 +126,6 @@ void ofApp::update(){ //-------------------------------------------------------------- void ofApp::draw(){ - - ofDrawBitmapString("test", 10, 10); - - //-- // Highlight background of selected camera diff --git a/examples/3d/modelNoiseExample/bin/data/dog/dog.3ds b/examples/3d/modelNoiseExample/bin/data/dog/dog.3ds index 02276bfc2a1..c4a1c7a8b83 100644 Binary files a/examples/3d/modelNoiseExample/bin/data/dog/dog.3ds and b/examples/3d/modelNoiseExample/bin/data/dog/dog.3ds differ diff --git a/examples/3d/normalsExample/src/ofApp.cpp b/examples/3d/normalsExample/src/ofApp.cpp index 37e3ff775b6..4c51fbf50cf 100644 --- a/examples/3d/normalsExample/src/ofApp.cpp +++ b/examples/3d/normalsExample/src/ofApp.cpp @@ -76,7 +76,6 @@ void ofApp::update(){ //-------------------------------------------------------------- void ofApp::draw(){ - ofEnableLighting(); ofBackgroundGradient(ofColor(65,62,50),ofColor(25,22,10) ); // disable normals if a key is pressed @@ -89,6 +88,8 @@ void ofApp::draw(){ cam.begin(); mesh.enableColors(); mesh.drawWireframe(); + + mesh.disableColors(); ofSetColor(137,137,140); ofFill(); @@ -98,7 +99,10 @@ void ofApp::draw(){ glPolygonOffset(-1,-1); #endif + ofEnableLighting(); mesh.drawFaces(); + ofDisableLighting(); + ofSetColor(255,255,255); light.draw(); @@ -109,7 +113,6 @@ void ofApp::draw(){ float normalLength = 50.; if(!ofGetKeyPressed()){ - ofDisableLighting(); ofSetColor(255,255,255,70); for(unsigned int i=0; i < n.size() ;i++){ ofDrawLine(v[i].x,v[i].y,v[i].z, @@ -125,7 +128,7 @@ void ofApp::draw(){ cam.end(); - ofSetColor(255,255,255); + ofSetColor(255); ofDrawBitmapString("press any key or mouse button to disable mesh normals", 20,20); ofDrawBitmapString("light", cam.worldToScreen(light.getGlobalPosition()) + ofPoint(10,0)); } diff --git a/tutorials/shader/01_simpleColorQuad/addons.make b/examples/3d/ofNodeExample/addons.make similarity index 100% rename from tutorials/shader/01_simpleColorQuad/addons.make rename to examples/3d/ofNodeExample/addons.make diff --git a/examples/android/android3DModelLoaderExample/bin/data/.gitkeep b/examples/3d/ofNodeExample/bin/data/.gitkeep similarity index 100% rename from examples/android/android3DModelLoaderExample/bin/data/.gitkeep rename to examples/3d/ofNodeExample/bin/data/.gitkeep diff --git a/examples/3d/ofNodeExample/src/Car.cpp b/examples/3d/ofNodeExample/src/Car.cpp new file mode 100644 index 00000000000..59c4e6efc96 --- /dev/null +++ b/examples/3d/ofNodeExample/src/Car.cpp @@ -0,0 +1,57 @@ +#include "Car.h" + +Car::Car(){ +} + +void Car::setup(){ + material.setDiffuseColor(ofFloatColor::green); + // This is how we append the 2 headlamps to the car. + // Calling setParent, we are telling to the lights that they are + // a child of the object car, and that teir movement are relative to + // the movement of the car + + lightL.setParent(geometry); + lightR.setParent(geometry); + + lightL.move(-45,20,-51); + lightR.move(45,20,-51); + lightL.tilt(-20); + lightR.tilt(-20); + lightL.setSpotlight(); + lightR.setSpotlight(); + lightL.setDiffuseColor(ofFloatColor::yellow); + lightR.setDiffuseColor(ofFloatColor::yellow); + lightL.setup(); + lightR.setup(); +} + +void Car::draw(){ + material.begin(); + geometry.draw(); + material.end(); + + lightR.draw(); + lightL.draw(); +} + +void Car::update(){ + vel += acceleration; + vel *= 0.9; + acceleration *= 0.99; + // here we are defining the vector that contains the direction + // in which the car should move, that is defined by the z-axis of the car and the velocity + auto velVector = geometry.getZAxis() * -vel; + geometry.move(velVector); +} + +void Car::brake(){ + acceleration -= 0.1; +} + +void Car::accellerate(){ + acceleration += 0.1; +} + +void Car::steer(float dir){ + geometry.rotate(dir, 0, 1, 0); // the rotation happens on the y axis +} diff --git a/examples/3d/ofNodeExample/src/Car.h b/examples/3d/ofNodeExample/src/Car.h new file mode 100644 index 00000000000..c2b01c98fa6 --- /dev/null +++ b/examples/3d/ofNodeExample/src/Car.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ofMain.h" + +class Car{ +public: + Car(); + void setup(); + void draw(); + void update(); + void brake(); + void accellerate(); + void steer(float dir); + +private: + float acceleration; + float vel; + ofBoxPrimitive geometry; + ofMaterial material; + ofLight lightR, lightL; +}; \ No newline at end of file diff --git a/examples/3d/ofNodeExample/src/main.cpp b/examples/3d/ofNodeExample/src/main.cpp new file mode 100644 index 00000000000..2bbca3218a4 --- /dev/null +++ b/examples/3d/ofNodeExample/src/main.cpp @@ -0,0 +1,14 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLFWWindowSettings settings; + settings.setGLVersion(3, 2); + settings.width = 1280; + settings.height = 720; + ofCreateWindow(settings); + + ofRunApp(new ofApp()); + +} diff --git a/examples/3d/ofNodeExample/src/ofApp.cpp b/examples/3d/ofNodeExample/src/ofApp.cpp new file mode 100644 index 00000000000..eb384d7130d --- /dev/null +++ b/examples/3d/ofNodeExample/src/ofApp.cpp @@ -0,0 +1,129 @@ +#include "ofApp.h" + +/* + This tutorial shows how to use the ofNode to build a gerarchy of objects, it was + originally developed in a workshop held by Arturo Castro at Lacuna Lab. + Most 3D classes in OF inheritate from ofNode. ofNode is simply a class that defines + a point in a 3D space and allows to: + - Chain a point with another point + - Apply matrices transformation to it + + We will never define an ofNode directly in this example, that's why you will + not find the word `ofNode` in the code but both ofLight and ofBoxPrimitive + inherith from ofNode, allowing us to access all its powerful methods. + + In this example we want to create a car with 2 headlamps, and we want to move the lights + together with the car, without re-calculating the position of the 2 light. + We define only how the car should move into the space, the light just need to stay on the front + of the car, their movement it's just a consequence of the movement of the car. + Have a look at the Car.cpp file to see how we attach the lights on the front of the car and how to move + object using the handy rotate, move and tilt methods, without any need to use ofPushMatrix and ofPopMatrix. + */ + + + +//-------------------------------------------------------------- +void ofApp::setup(){ + light.setup(); + light.setPosition(-100, 200,0); + // we set up a plane on which the car will move + plane.set(10000, 10000); + plane.rotate(270, 1, 0 , 0); + plane.move(0, -49, 0); + roadMaterial.setDiffuseColor(ofFloatColor::gray); + roadMaterial.setShininess(0.01); + car.setup(); + + ofEnableDepthTest(); +} + +//-------------------------------------------------------------- +void ofApp::update(){ + car.update(); +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + cam.begin(); + roadMaterial.begin(); + plane.draw(); + roadMaterial.end(); + car.draw(); + cam.end(); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + if(key == OF_KEY_UP){ + car.accellerate(); + }else if(key == OF_KEY_DOWN){ + car.brake(); + } + + switch (key) { + case OF_KEY_UP: + car.accellerate(); + break; + case OF_KEY_DOWN: + car.brake(); + break; + case OF_KEY_LEFT: + car.steer(+1); + break; + case OF_KEY_RIGHT: + car.steer(-1); + break; + default: + break; + } +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseEntered(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseExited(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/examples/3d/ofNodeExample/src/ofApp.h b/examples/3d/ofNodeExample/src/ofApp.h new file mode 100644 index 00000000000..d040e3205d6 --- /dev/null +++ b/examples/3d/ofNodeExample/src/ofApp.h @@ -0,0 +1,32 @@ +#pragma once + +#include "ofMain.h" +#include "Car.h" + + +class ofApp : public ofBaseApp{ + + 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 mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + + ofLight light; + ofEasyCam cam; + Car car; + ofPlanePrimitive plane; + ofMaterial roadMaterial; +}; diff --git a/examples/addons/3DModelLoaderExample/addons.make b/examples/addons/3DModelLoaderExample/addons.make index dc4e9b4a4d0..482b1a79d96 100644 --- a/examples/addons/3DModelLoaderExample/addons.make +++ b/examples/addons/3DModelLoaderExample/addons.make @@ -1 +1 @@ -ofx3DModelLoader +ofxAssimpModelLoader diff --git a/examples/addons/3DModelLoaderExample/src/ofApp.cpp b/examples/addons/3DModelLoaderExample/src/ofApp.cpp index 056884c1a21..1ef50bbc6de 100644 --- a/examples/addons/3DModelLoaderExample/src/ofApp.cpp +++ b/examples/addons/3DModelLoaderExample/src/ofApp.cpp @@ -78,7 +78,7 @@ void ofApp::draw(){ glTranslatef(-ofGetWidth()/2,-ofGetHeight()/2,0); ofSetColor(255, 255, 255, 255); - squirrelModel.draw(); + squirrelModel.drawFaces(); glPopMatrix(); diff --git a/examples/addons/3DModelLoaderExample/src/ofApp.h b/examples/addons/3DModelLoaderExample/src/ofApp.h index 233205c1a18..40e7918c753 100644 --- a/examples/addons/3DModelLoaderExample/src/ofApp.h +++ b/examples/addons/3DModelLoaderExample/src/ofApp.h @@ -1,7 +1,7 @@ #pragma once #include "ofMain.h" -#include "ofx3DModelLoader.h" +#include "ofxAssimpModelLoader.h" class ofApp : public ofBaseApp{ @@ -23,7 +23,7 @@ class ofApp : public ofBaseApp{ void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); - ofx3DModelLoader squirrelModel; + ofxAssimpModelLoader squirrelModel; }; diff --git a/examples/addons/allAddonsExample/addons.make b/examples/addons/allAddonsExample/addons.make index 405003d4201..1989b49e2a5 100644 --- a/examples/addons/allAddonsExample/addons.make +++ b/examples/addons/allAddonsExample/addons.make @@ -1,4 +1,4 @@ -ofx3DModelLoader +ofxAssimpModelLoader ofxNetwork ofxOpenCv ofxOsc @@ -6,3 +6,6 @@ ofxVectorGraphics ofxXmlSettings ofxAssimpModelLoader ofxThreadedImageLoader +ofxGui +ofxKinect +ofxSvg diff --git a/examples/addons/allAddonsExample/src/ofApp.h b/examples/addons/allAddonsExample/src/ofApp.h index 6b4b774b6ae..e25633fc328 100644 --- a/examples/addons/allAddonsExample/src/ofApp.h +++ b/examples/addons/allAddonsExample/src/ofApp.h @@ -5,10 +5,11 @@ #include "ofxNetwork.h" #include "ofxOsc.h" #include "ofxXmlSettings.h" -#include "ofx3DModelLoader.h" #include "ofxAssimpModelLoader.h" #include "ofxThreadedImageLoader.h" - +#include "ofxKinect.h" +#include "ofxGui.h" +#include "ofxSvg.h" class ofApp : public ofBaseApp{ public: @@ -38,7 +39,9 @@ class ofApp : public ofBaseApp{ ofxTCPServer server; ofxOscSender osc_sender; ofxXmlSettings settings; - ofx3DModelLoader modelLoader; - ofxAssimpModelLoader betterModelLoader; - ofxThreadedImageLoader threadedLoader; + ofxAssimpModelLoader betterModelLoader; + ofxThreadedImageLoader threadedLoader; + ofxKinect kinect; + ofxPanel gui; + ofxSVG svg; }; diff --git a/examples/addons/kinectExample/src/ofApp.cpp b/examples/addons/kinectExample/src/ofApp.cpp index 13432e02bd5..8424f813e5b 100644 --- a/examples/addons/kinectExample/src/ofApp.cpp +++ b/examples/addons/kinectExample/src/ofApp.cpp @@ -1,5 +1,9 @@ #include "ofApp.h" +/* + If you are struggling to get the device to connect ( especially Windows Users ) + please look at the ReadMe: in addons/ofxKinect/README.md +*/ //-------------------------------------------------------------- void ofApp::setup() { diff --git a/examples/addons/networkTcpClientExample/src/ofApp.cpp b/examples/addons/networkTcpClientExample/src/ofApp.cpp index 4c5c0b257af..8a75fc4d386 100644 --- a/examples/addons/networkTcpClientExample/src/ofApp.cpp +++ b/examples/addons/networkTcpClientExample/src/ofApp.cpp @@ -4,56 +4,38 @@ //-------------------------------------------------------------- void ofApp::setup(){ + ofSetBackgroundColor(230, 230, 230); - // we don't want to be running to fast - ofSetVerticalSync(true); - - //some variables: - //have we typed - typed = false; - - //our typing position - pos = 0; - - //our send and recieve strings + // our send and recieve strings msgTx = ""; msgRx = ""; - //are we connected to the server - if this fails we - //will check every few seconds to see if the server exists - weConnected = tcpClient.setup("127.0.0.1", 11999); - //optionally set the delimiter to something else. The delimter in the client and the server have to be the same + // connect to the server - if this fails or disconnects + // we'll check every few seconds to see if the server exists + tcpClient.setup("127.0.0.1", 11999); + + // optionally set the delimiter to something else. The delimiter in the client and the server have to be the same tcpClient.setMessageDelimiter("\n"); connectTime = 0; - deltaTime = 0; - - tcpClient.setVerbose(true); - + deltaTime = 0; } //-------------------------------------------------------------- void ofApp::update(){ - ofBackground(230, 230, 230); - - //we are connected - lets send our text and check what we get back - if(weConnected){ - if(tcpClient.send(msgTx)){ - - //if data has been sent lets update our text - string str = tcpClient.receive(); - if( str.length() > 0 ){ - msgRx = str; - } - }else if(!tcpClient.isConnected()){ - weConnected = false; - } - }else{ - //if we are not connected lets try and reconnect every 5 seconds + if(tcpClient.isConnected()){ + // we are connected - lets try to receive from the server + string str = tcpClient.receive(); + if( str.length() > 0 ){ + msgRx = str; + } + }else{ + msgTx = ""; + // if we are not connected lets try and reconnect every 5 seconds deltaTime = ofGetElapsedTimeMillis() - connectTime; if( deltaTime > 5000 ){ - weConnected = tcpClient.setup("127.0.0.1", 11999); + tcpClient.setup("127.0.0.1", 11999); connectTime = ofGetElapsedTimeMillis(); } @@ -66,35 +48,38 @@ void ofApp::draw(){ ofSetColor(20, 20, 20); ofDrawBitmapString("openFrameworks TCP Send Example", 15, 30); - if(typed){ - ofDrawBitmapString("sending:", 15, 55); - ofDrawBitmapString(msgTx, 85, 55); - } - else{ - if(weConnected)ofDrawBitmapString("status: type something to send data to port 11999", 15, 55); - else ofDrawBitmapString("status: server not found. launch server app and check ports!\n\nreconnecting in "+ofToString( (5000 - deltaTime) / 1000 )+" seconds", 15, 55); + if(tcpClient.isConnected()){ + if(!msgTx.empty()){ + ofDrawBitmapString("sending:", 15, 55); + ofDrawBitmapString(msgTx, 85, 55); + }else{ + ofDrawBitmapString("status: type something to send data to port 11999", 15, 55); + } + ofDrawBitmapString("from server: \n" + msgRx, 15, 270); + }else{ + ofDrawBitmapString("status: server not found. launch server app and check ports!\n\nreconnecting in "+ofToString( (5000 - deltaTime) / 1000 )+" seconds", 15, 55); } - - ofDrawBitmapString("from server: \n"+msgRx, 15, 270); - } //-------------------------------------------------------------- void ofApp::keyPressed(int key){ - - //you can only type if you're connected - if(weConnected){ - if(key == 13)key = '\n'; - if(key == 8 || key == 127){ - if( pos != 0 ){pos--; - msgTx = msgTx.substr(0,pos); - }else msgTx = ""; + // you can only type if you're connected + // we accumulate 1 line of text and send every typed character + // on the next character after a breakline we clear the buffer + if(tcpClient.isConnected()){ + if(key == OF_KEY_RETURN) key = '\n'; + if(key == OF_KEY_BACKSPACE || key == OF_KEY_DEL){ + if( !msgTx.empty()){ + msgTx = msgTx.substr(0, msgTx.size()-1); + } }else{ - msgTx.append(1, (char) key); - pos++; + msgTx += (char) key; + } + tcpClient.send(msgTx); + if (!msgTx.empty() && msgTx.back() == '\n') { + msgTx.clear(); } - typed = true; } } diff --git a/examples/addons/networkTcpClientExample/src/ofApp.h b/examples/addons/networkTcpClientExample/src/ofApp.h index 86ed4f495b5..6052113b3c9 100644 --- a/examples/addons/networkTcpClientExample/src/ofApp.h +++ b/examples/addons/networkTcpClientExample/src/ofApp.h @@ -31,12 +31,8 @@ class ofApp : public ofBaseApp{ float counter; int connectTime; - int deltaTime; + int deltaTime; - bool weConnected; - - int size; - int pos; - bool typed; + int size; }; diff --git a/examples/addons/networkTcpServerExample/src/ofApp.cpp b/examples/addons/networkTcpServerExample/src/ofApp.cpp index 3c8ec18a57f..b9c6e553f25 100644 --- a/examples/addons/networkTcpServerExample/src/ofApp.cpp +++ b/examples/addons/networkTcpServerExample/src/ofApp.cpp @@ -3,24 +3,27 @@ //-------------------------------------------------------------- void ofApp::setup(){ - //we run at 60 fps! - ofSetVerticalSync(true); - - //setup the server to listen on 11999 + // setup the server to listen on 11999 TCP.setup(11999); - //optionally set the delimiter to something else. The delimter in the client and the server have to be the same, default being [/TCP] + // optionally set the delimiter to something else. The delimiter in the client and the server have to be the same, default being [/TCP] TCP.setMessageDelimiter("\n"); + lastSent = 0; } //-------------------------------------------------------------- void ofApp::update(){ ofBackground(20, 20, 20); - //for each client lets send them a message letting them know what port they are connected on - for(int i = 0; i < TCP.getLastID(); i++){ - if( !TCP.isClientConnected(i) )continue; - - TCP.send(i, "hello client - you are connected on port - "+ofToString(TCP.getClientPort(i)) ); + // for each client lets send them a message letting them know what port they are connected on + // we throttle the message sending frequency to once every 100ms + uint64_t now = ofGetElapsedTimeMillis(); + if(now - lastSent >= 100){ + for(int i = 0; i < TCP.getLastID(); i++){ + if( !TCP.isClientConnected(i) ) continue; + + TCP.send(i, "hello client - you are connected on port - "+ofToString(TCP.getClientPort(i)) ); + } + lastSent = now; } } @@ -36,38 +39,45 @@ void ofApp::draw(){ ofSetHexColor(0xDDDDDD); - //for each connected client lets get the data being sent and lets print it to the screen + // for each connected client lets get the data being sent and lets print it to the screen for(unsigned int i = 0; i < (unsigned int)TCP.getLastID(); i++){ if( !TCP.isClientConnected(i) )continue; - //give each client its own color + // give each client its own color ofSetColor(255 - i*30, 255 - i * 20, 100 + i*40); - //calculate where to draw the text + // calculate where to draw the text int xPos = 15; int yPos = 80 + (12 * i * 4); - //get the ip and port of the client + // get the ip and port of the client string port = ofToString( TCP.getClientPort(i) ); string ip = TCP.getClientIP(i); string info = "client "+ofToString(i)+" -connected from "+ip+" on port: "+port; - //if we don't have a string allocated yet - //lets create one + // if we don't have a string allocated yet + // lets create one if(i >= storeText.size() ){ storeText.push_back( string() ); } - //we only want to update the text we have recieved there is data - string str = TCP.receive(i); + // receive all the available messages, separated by \n + // and keep only the last one + string str; + string tmp; + do{ + str = tmp; + tmp = TCP.receive(i); + }while(tmp!=""); + // if there was a message set it to the corresponding client if(str.length() > 0){ storeText[i] = str; } - //draw the info text and the received text bellow it + // draw the info text and the received text bellow it ofDrawBitmapString(info, xPos, yPos); ofDrawBitmapString(storeText[i], 25, yPos + 20); diff --git a/examples/addons/networkTcpServerExample/src/ofApp.h b/examples/addons/networkTcpServerExample/src/ofApp.h index 0615bf05ae4..f2c24382f85 100644 --- a/examples/addons/networkTcpServerExample/src/ofApp.h +++ b/examples/addons/networkTcpServerExample/src/ofApp.h @@ -29,5 +29,6 @@ class ofApp : public ofBaseApp{ ofTrueTypeFont monosm; vector storeText; + uint64_t lastSent; }; diff --git a/examples/addons/oscReceiveExample/src/ofApp.cpp b/examples/addons/oscReceiveExample/src/ofApp.cpp index 0f97cae70d8..34ff56f7eb2 100644 --- a/examples/addons/oscReceiveExample/src/ofApp.cpp +++ b/examples/addons/oscReceiveExample/src/ofApp.cpp @@ -29,7 +29,7 @@ void ofApp::update(){ while(receiver.hasWaitingMessages()){ // get the next message ofxOscMessage m; - receiver.getNextMessage(&m); + receiver.getNextMessage(m); // check for mouse moved message if(m.getAddress() == "/mouse/position"){ diff --git a/examples/addons/oscSenderExample/bin/data/of-logo.png b/examples/addons/oscSenderExample/bin/data/of-logo.png new file mode 100644 index 00000000000..de4eba802c4 Binary files /dev/null and b/examples/addons/oscSenderExample/bin/data/of-logo.png differ diff --git a/examples/addons/oscSenderExample/src/ofApp.cpp b/examples/addons/oscSenderExample/src/ofApp.cpp index cf14e9e2e86..34f5d74d547 100644 --- a/examples/addons/oscSenderExample/src/ofApp.cpp +++ b/examples/addons/oscSenderExample/src/ofApp.cpp @@ -8,7 +8,7 @@ void ofApp::setup(){ // open an outgoing connection to HOST:PORT sender.setup(HOST, PORT); - imgAsBuffer = ofBufferFromFile("sendImageTest.jpg", true); + imgAsBuffer = ofBufferFromFile("of-logo.png", true); } @@ -84,6 +84,7 @@ void ofApp::mouseDragged(int x, int y, int button){ void ofApp::mousePressed(int x, int y, int button){ ofxOscMessage m; m.setAddress("/mouse/button"); + m.addIntArg(button); m.addStringArg("down"); sender.sendMessage(m, false); } @@ -92,6 +93,7 @@ void ofApp::mousePressed(int x, int y, int button){ void ofApp::mouseReleased(int x, int y, int button){ ofxOscMessage m; m.setAddress("/mouse/button"); + m.addIntArg(button); m.addStringArg("up"); sender.sendMessage(m, false); diff --git a/examples/addons/svgExample/src/ofApp.cpp b/examples/addons/svgExample/src/ofApp.cpp index c1bee8b245c..bde39f7a88c 100644 --- a/examples/addons/svgExample/src/ofApp.cpp +++ b/examples/addons/svgExample/src/ofApp.cpp @@ -12,7 +12,7 @@ void ofApp::setup(){ ofPath p = svg.getPathAt(i); // svg defaults to non zero winding which doesn't look so good as contours p.setPolyWindingMode(OF_POLY_WINDING_ODD); - vector& lines = p.getOutline(); + vector& lines = const_cast&>(p.getOutline()); for(int j=0;j<(int)lines.size();j++){ outlines.push_back(lines[j].getResampledBySpacing(1)); } diff --git a/examples/android/android3DModelLoaderExample/.classpath b/examples/android/android3DModelLoaderExample/.classpath deleted file mode 100644 index 2b29adaa3de..00000000000 --- a/examples/android/android3DModelLoaderExample/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/examples/android/android3DModelLoaderExample/.cproject b/examples/android/android3DModelLoaderExample/.cproject deleted file mode 100644 index f529f1d4c76..00000000000 --- a/examples/android/android3DModelLoaderExample/.cproject +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/android/android3DModelLoaderExample/.project b/examples/android/android3DModelLoaderExample/.project deleted file mode 100644 index 35dbf1bfbc7..00000000000 --- a/examples/android/android3DModelLoaderExample/.project +++ /dev/null @@ -1,98 +0,0 @@ - - - android3DModelLoaderExample - - - openFrameworks - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.cleanBuildTarget - CleanRelease PLATFORM_OS=Android - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - Release PLATFORM_OS=Android - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - false - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/examples/android/android3DModelLoaderExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/android3DModelLoaderExample/.settings/org.eclipse.cdt.codan.core.prefs deleted file mode 100644 index 810101ec581..00000000000 --- a/examples/android/android3DModelLoaderExample/.settings/org.eclipse.cdt.codan.core.prefs +++ /dev/null @@ -1,67 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.cdt.codan.checkers.errnoreturn=Warning -org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.checkers.errreturnvalue=Error -org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.checkers.noreturn=Error -org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=-Error -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} -org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning -org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidArguments=-Error -org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=-Error -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=-Error -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=-Error -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.OverloadProblem=-Error -org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=-Error -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=-Error -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} diff --git a/examples/android/android3DModelLoaderExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/android3DModelLoaderExample/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 8000cd6ca61..00000000000 --- a/examples/android/android3DModelLoaderExample/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/examples/android/android3DModelLoaderExample/addons.make b/examples/android/android3DModelLoaderExample/addons.make deleted file mode 100644 index 412979711f5..00000000000 --- a/examples/android/android3DModelLoaderExample/addons.make +++ /dev/null @@ -1,3 +0,0 @@ -ofxAndroid -ofxAccelerometer -ofx3DModelLoader \ No newline at end of file diff --git a/examples/android/android3DModelLoaderExample/bin/data/squirrel/NewSquirrel.3ds b/examples/android/android3DModelLoaderExample/bin/data/squirrel/NewSquirrel.3ds deleted file mode 100644 index c189b2d7a9c..00000000000 Binary files a/examples/android/android3DModelLoaderExample/bin/data/squirrel/NewSquirrel.3ds and /dev/null differ diff --git a/examples/android/android3DModelLoaderExample/bin/data/squirrel/Squirrel.jpg b/examples/android/android3DModelLoaderExample/bin/data/squirrel/Squirrel.jpg deleted file mode 100644 index 3f3c8460704..00000000000 Binary files a/examples/android/android3DModelLoaderExample/bin/data/squirrel/Squirrel.jpg and /dev/null differ diff --git a/examples/android/android3DModelLoaderExample/bin/data/squirrel/readme.txt b/examples/android/android3DModelLoaderExample/bin/data/squirrel/readme.txt deleted file mode 100644 index a6a52b638ba..00000000000 --- a/examples/android/android3DModelLoaderExample/bin/data/squirrel/readme.txt +++ /dev/null @@ -1,30 +0,0 @@ --- 3dvia.com -- - -The zip file NewSquirrel.3ds.zip contains the following files : -- readme.txt -- NewSquirrel.3ds -- Squirrel.jpg - - --- Model information -- - -Model Name : New Squirrel -Author : Bruce Lehmann -Publisher : Omind - -You can view this model here : -http://www.3dvia.com/Omind/media/64EAC75A6C7E5062 -More models about this author : -http://www.3dvia.com/Omind - - --- Attached license -- - -A license is attached to the New Squirrel model and all related media. -You must agree with this licence before using the enclosed media. - -License : Attribution License 2.5 -Detailled license : http://creativecommons.org/licenses/by/2.5/ - -The licenses used by 3dvia are based on Creative Commons Licenses. -More info: http://creativecommons.org/about/licenses/meet-the-licenses diff --git a/examples/android/android3DModelLoaderExample/build.xml b/examples/android/android3DModelLoaderExample/build.xml deleted file mode 100644 index 024f138d46d..00000000000 --- a/examples/android/android3DModelLoaderExample/build.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/android/android3DModelLoaderExample/ic_launcher-web.png b/examples/android/android3DModelLoaderExample/ic_launcher-web.png deleted file mode 100644 index 70b562fba01..00000000000 Binary files a/examples/android/android3DModelLoaderExample/ic_launcher-web.png and /dev/null differ diff --git a/examples/android/android3DModelLoaderExample/libs/android-support-v4.jar b/examples/android/android3DModelLoaderExample/libs/android-support-v4.jar deleted file mode 100644 index 6080877d4ad..00000000000 Binary files a/examples/android/android3DModelLoaderExample/libs/android-support-v4.jar and /dev/null differ diff --git a/examples/android/android3DModelLoaderExample/proguard-project.txt b/examples/android/android3DModelLoaderExample/proguard-project.txt deleted file mode 100644 index f2fe1559a21..00000000000 --- a/examples/android/android3DModelLoaderExample/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/examples/android/android3DModelLoaderExample/project.properties b/examples/android/android3DModelLoaderExample/project.properties deleted file mode 100644 index 1052e2e6579..00000000000 --- a/examples/android/android3DModelLoaderExample/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-19 -android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/android3DModelLoaderExample/res/values/strings.xml b/examples/android/android3DModelLoaderExample/res/values/strings.xml deleted file mode 100644 index ab192957750..00000000000 --- a/examples/android/android3DModelLoaderExample/res/values/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - android3DModelLoaderExample - Hello world! - Settings - - \ No newline at end of file diff --git a/examples/android/android3DModelLoaderExample/src/ofApp.cpp b/examples/android/android3DModelLoaderExample/src/ofApp.cpp deleted file mode 100644 index 4675a0af6c9..00000000000 --- a/examples/android/android3DModelLoaderExample/src/ofApp.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "ofApp.h" - -GLfloat lightOnePosition[] = {40.0, 40, 100.0, 0.0}; -GLfloat lightOneColor[] = {0.99, 0.99, 0.99, 1.0}; - -GLfloat lightTwoPosition[] = {-40.0, 40, 100.0, 0.0}; -GLfloat lightTwoColor[] = {0.99, 0.99, 0.99, 1.0}; - -//-------------------------------------------------------------- -void ofApp::setup(){ - ofBackground(255,255,255); - - //some model / light stuff - ofEnableDepthTest(); - glShadeModel (GL_SMOOTH); - - /* initialize lighting */ - glLightfv (GL_LIGHT0, GL_POSITION, lightOnePosition); - glLightfv (GL_LIGHT0, GL_DIFFUSE, lightOneColor); - glEnable (GL_LIGHT0); - glLightfv (GL_LIGHT1, GL_POSITION, lightTwoPosition); - glLightfv (GL_LIGHT1, GL_DIFFUSE, lightTwoColor); - glEnable (GL_LIGHT1); - glEnable (GL_LIGHTING); - //glColorMaterial (GL_FRONT_AND_BACK, GL_DIFFUSE); - - glEnable (GL_COLOR_MATERIAL); - - //load the squirrel model - the 3ds and the texture file need to be in the same folder - squirrelModel.loadModel("squirrel/NewSquirrel.3ds", 20); - - //you can create as many rotations as you want - //choose which axis you want it to effect - //you can update these rotations later on - squirrelModel.setRotation(0, 90, 1, 0, 0); - squirrelModel.setRotation(1, 270, 0, 0, 1); - squirrelModel.setScale(0.9, 0.9, 0.9); - squirrelModel.setPosition(ofGetWidth()/2, ofGetHeight()/2, 0); -} - -//-------------------------------------------------------------- -void ofApp::update(){ - squirrelModel.setRotation(1, 270 + ofGetElapsedTimef() * 60, 0, 0, 1); -} - -//-------------------------------------------------------------- -void ofApp::draw(){ - //fake back wall - ofSetColor(20, 20, 20); - - GLfloat vertices1[] = {0.0, ofGetHeight(), -600, - ofGetWidth(), ofGetHeight(), -600, - ofGetWidth(), 0, -600, - 0, 0, -600}; - - GLubyte indices[] = {0, 1, 2, 0, 2, 3}; - - glVertexPointer(3, GL_FLOAT, 0, vertices1); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices); - - //fake wall - ofSetColor(50, 50, 50); - GLfloat vertices2[] = {0, ofGetHeight(), 0, - ofGetWidth(), ofGetHeight(), 0, - ofGetWidth(), ofGetHeight(), -600, - 0, ofGetHeight(), -600 - }; - - glVertexPointer(3, GL_FLOAT, 0, vertices2); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices); - - //lets tumble the world with the mouse - glPushMatrix(); - - //draw in middle of the screen - glTranslatef(ofGetWidth()/2,ofGetHeight()/2,0); - //tumble according to mouse - glRotatef(-mouseY,1,0,0); - glRotatef(mouseX,0,1,0); - glTranslatef(-ofGetWidth()/2,-ofGetHeight()/2,0); - - ofSetColor(255, 255, 255, 255); - squirrelModel.draw(); - - glPopMatrix(); - - ofSetHexColor(0x000000); - ofDrawBitmapString("fps: "+ofToString(ofGetFrameRate(), 2), 10, 15); -} - -//-------------------------------------------------------------- -void ofApp::keyPressed (int key){ - -} - -//-------------------------------------------------------------- -void ofApp::keyReleased(int key){ - -} - -//-------------------------------------------------------------- -void ofApp::windowResized(int w, int h){ - -} - -//-------------------------------------------------------------- -void ofApp::touchDown(int x, int y, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::touchMoved(int x, int y, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::touchUp(int x, int y, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::touchDoubleTap(int x, int y, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::touchCancelled(int x, int y, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::swipe(ofxAndroidSwipeDir swipeDir, int id){ - -} - -//-------------------------------------------------------------- -void ofApp::pause(){ - -} - -//-------------------------------------------------------------- -void ofApp::stop(){ - -} - -//-------------------------------------------------------------- -void ofApp::resume(){ - -} - -//-------------------------------------------------------------- -void ofApp::reloadTextures(){ - -} - -//-------------------------------------------------------------- -bool ofApp::backPressed(){ - return false; -} - -//-------------------------------------------------------------- -void ofApp::okPressed(){ - -} - -//-------------------------------------------------------------- -void ofApp::cancelPressed(){ - -} diff --git a/examples/android/androidAccelerometerExample/.cproject b/examples/android/androidAccelerometerExample/.cproject index 8533d313a74..cc2393d4a6c 100644 --- a/examples/android/androidAccelerometerExample/.cproject +++ b/examples/android/androidAccelerometerExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidAccelerometerExample/.project b/examples/android/androidAccelerometerExample/.project index d33db8157de..8873fd5fed3 100644 --- a/examples/android/androidAccelerometerExample/.project +++ b/examples/android/androidAccelerometerExample/.project @@ -3,7 +3,6 @@ androidAccelerometerExample - openFrameworks @@ -95,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidAccelerometerExample/.settings/language.settings.xml b/examples/android/androidAccelerometerExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidAccelerometerExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidAccelerometerExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidAccelerometerExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidAccelerometerExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidAccelerometerExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidAccelerometerExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidAccelerometerExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidAccelerometerExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidAccelerometerExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidAccelerometerExample/build.gradle b/examples/android/androidAccelerometerExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidAccelerometerExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidAccelerometerExample/project.properties b/examples/android/androidAccelerometerExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidAccelerometerExample/project.properties +++ b/examples/android/androidAccelerometerExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidAccelerometerExample/settings.gradle b/examples/android/androidAccelerometerExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidAccelerometerExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidAdvanced3DExample/.cproject b/examples/android/androidAdvanced3DExample/.cproject index f8dcf14b0cc..cc2393d4a6c 100644 --- a/examples/android/androidAdvanced3DExample/.cproject +++ b/examples/android/androidAdvanced3DExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidAdvanced3DExample/.project b/examples/android/androidAdvanced3DExample/.project index de8bed58689..55d6aeacf36 100644 --- a/examples/android/androidAdvanced3DExample/.project +++ b/examples/android/androidAdvanced3DExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidAdvanced3DExample/.settings/language.settings.xml b/examples/android/androidAdvanced3DExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidAdvanced3DExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidAdvanced3DExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidAdvanced3DExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidAdvanced3DExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidAdvanced3DExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidAdvanced3DExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidAdvanced3DExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidAdvanced3DExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidAdvanced3DExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidAdvanced3DExample/build.gradle b/examples/android/androidAdvanced3DExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidAdvanced3DExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidAdvanced3DExample/project.properties b/examples/android/androidAdvanced3DExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidAdvanced3DExample/project.properties +++ b/examples/android/androidAdvanced3DExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidAdvanced3DExample/settings.gradle b/examples/android/androidAdvanced3DExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidAdvanced3DExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidAssimpExample/.cproject b/examples/android/androidAssimpExample/.cproject index 0da964d0f32..cc2393d4a6c 100644 --- a/examples/android/androidAssimpExample/.cproject +++ b/examples/android/androidAssimpExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidAssimpExample/.project b/examples/android/androidAssimpExample/.project index 2691f4bab76..fe582e8fd00 100644 --- a/examples/android/androidAssimpExample/.project +++ b/examples/android/androidAssimpExample/.project @@ -27,7 +27,7 @@ org.eclipse.cdt.make.core.cleanBuildTarget - CleanRelease PLATFORM_OS=Android + CleanRelease PLATFORM_OS=Android org.eclipse.cdt.make.core.contents @@ -47,7 +47,7 @@ org.eclipse.cdt.make.core.fullBuildTarget - Release PLATFORM_OS=Android + Release PLATFORM_OS=Android org.eclipse.cdt.make.core.stopOnError @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidAssimpExample/.settings/language.settings.xml b/examples/android/androidAssimpExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidAssimpExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidAssimpExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidAssimpExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidAssimpExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidAssimpExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidAssimpExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidAssimpExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidAssimpExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidAssimpExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidAssimpExample/build.gradle b/examples/android/androidAssimpExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidAssimpExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidAssimpExample/project.properties b/examples/android/androidAssimpExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidAssimpExample/project.properties +++ b/examples/android/androidAssimpExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidAssimpExample/settings.gradle b/examples/android/androidAssimpExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidAssimpExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidAudioExample/.cproject b/examples/android/androidAudioExample/.cproject index 87025d36423..cc2393d4a6c 100644 --- a/examples/android/androidAudioExample/.cproject +++ b/examples/android/androidAudioExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidAudioExample/.project b/examples/android/androidAudioExample/.project index 18b1889f311..62d8ce1b1cb 100644 --- a/examples/android/androidAudioExample/.project +++ b/examples/android/androidAudioExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidAudioExample/.settings/language.settings.xml b/examples/android/androidAudioExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidAudioExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidAudioExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidAudioExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidAudioExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidAudioExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidAudioExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidAudioExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidAudioExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidAudioExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidAudioExample/build.gradle b/examples/android/androidAudioExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidAudioExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidAudioExample/project.properties b/examples/android/androidAudioExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidAudioExample/project.properties +++ b/examples/android/androidAudioExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidAudioExample/settings.gradle b/examples/android/androidAudioExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidAudioExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidCameraExample/.cproject b/examples/android/androidCameraExample/.cproject index e66d4ec4e98..cc2393d4a6c 100644 --- a/examples/android/androidCameraExample/.cproject +++ b/examples/android/androidCameraExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidCameraExample/.project b/examples/android/androidCameraExample/.project index e6d9d98c3d6..e9c179b3a85 100644 --- a/examples/android/androidCameraExample/.project +++ b/examples/android/androidCameraExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidCameraExample/.settings/language.settings.xml b/examples/android/androidCameraExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidCameraExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidCameraExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidCameraExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidCameraExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidCameraExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidCameraExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidCameraExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidCameraExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidCameraExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidCameraExample/build.gradle b/examples/android/androidCameraExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidCameraExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidCameraExample/project.properties b/examples/android/androidCameraExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidCameraExample/project.properties +++ b/examples/android/androidCameraExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidCameraExample/settings.gradle b/examples/android/androidCameraExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidCameraExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidCameraExample/src/ofApp.cpp b/examples/android/androidCameraExample/src/ofApp.cpp index 2c868121092..0d6fe597563 100644 --- a/examples/android/androidCameraExample/src/ofApp.cpp +++ b/examples/android/androidCameraExample/src/ofApp.cpp @@ -3,10 +3,28 @@ //-------------------------------------------------------------- void ofApp::setup(){ - ofBackground(255,255,255); - ofSetLogLevel(OF_LOG_NOTICE); - ofSetOrientation(OF_ORIENTATION_90_LEFT); - grabber.setup(320,240); + ofBackground(0,0,0); + + // List devices + // The device name contains information about the direction of the camera + vector devices = grabber.listDevices(); + for(int i=0;isetUsePixels(false); + + // Start the grabber + grabber.setup(1280,960); + + // Get the orientation and facing of the current camera + orientation = ((ofxAndroidVideoGrabber*)grabber.getGrabber().get())->getCameraOrientation(); + facing = ((ofxAndroidVideoGrabber*)grabber.getGrabber().get())->getFacingOfCamera(); one_second_time = ofGetElapsedTimeMillis(); camera_fps = 0; @@ -23,16 +41,52 @@ void ofApp::update(){ frames_one_sec = 0; one_second_time = ofGetElapsedTimeMillis(); } + + grabberImage.setFromPixels(grabber.getPixels()); } } //-------------------------------------------------------------- -void ofApp::draw(){ +void ofApp::draw(){ + // Calculate aspect ratio of grabber image + float grabberAspectRatio = grabber.getWidth() / grabber.getHeight(); + + // Draw camera image centered in the window + ofPushMatrix(); ofSetHexColor(0xFFFFFF); - grabber.draw(20,20); + ofSetRectMode(OF_RECTMODE_CENTER); + + ofTranslate(ofGetWidth() / 2, ofGetHeight() / 2); + + int wOrientation = ofOrientationToDegrees(ofGetOrientation()); + ofLogNotice()<<"Orientation: "< ofGetHeight()) { + grabber.draw(0,0, ofGetHeight() * grabberAspectRatio, + ofGetHeight()); + } else { + grabber.draw(0,0, ofGetWidth(), + ofGetWidth() * 1.0/grabberAspectRatio); + + } + ofPopMatrix(); + ofSetRectMode(OF_RECTMODE_CORNER); + + // Draw the image through raw pixels + grabberImage.draw(0,110, 300, 300*1.0/grabberAspectRatio); + + // Draw text gui + ofDrawRectangle(0, 0, 300, 100); ofSetHexColor(0x000000); - ofDrawBitmapString("fps: " + ofToString(ofGetFrameRate()),20,350); - ofDrawBitmapString("camera fps: " + ofToString(camera_fps),20,370); + ofDrawBitmapString("fps: " + ofToString(ofGetFrameRate()),20,20); + ofDrawBitmapString("camera fps: " + ofToString(camera_fps),20,40); + + if(facing == 1) { + ofDrawBitmapString("facing: front", 20, 60); + } else { + ofDrawBitmapString("facing: back", 20, 60); + } + ofDrawBitmapString("orientation: " + ofToString(orientation) ,20,80); } //-------------------------------------------------------------- @@ -52,7 +106,21 @@ void ofApp::windowResized(int w, int h){ //-------------------------------------------------------------- void ofApp::touchDown(int x, int y, int id){ + // Swap between back and front camera + + // Get the native android video grabber + ofxAndroidVideoGrabber* androidGrabber = (ofxAndroidVideoGrabber*)grabber.getGrabber().get(); + + // If the current camera is frontal, then choose the back camera + if(facing == 1) { + androidGrabber->setDeviceID(androidGrabber->getBackCamera()); + } else { + androidGrabber->setDeviceID(androidGrabber->getFrontCamera()); + } + // Read current orientation and facing out again + orientation = androidGrabber->getCameraOrientation(); + facing = androidGrabber->getFacingOfCamera(); } //-------------------------------------------------------------- diff --git a/examples/android/androidCameraExample/src/ofApp.h b/examples/android/androidCameraExample/src/ofApp.h index 6f2a6af9512..bc67d68bc4b 100644 --- a/examples/android/androidCameraExample/src/ofApp.h +++ b/examples/android/androidCameraExample/src/ofApp.h @@ -31,10 +31,16 @@ class ofApp : public ofxAndroidApp{ void okPressed(); void cancelPressed(); - ofVideoGrabber grabber; + + // Image storing a clone of the grabber image + ofImage grabberImage; + int one_second_time; int camera_fps; int frames_one_sec; + bool facing; + int orientation; + }; diff --git a/examples/android/androidEmptyExample/.cproject b/examples/android/androidEmptyExample/.cproject index 4829dddf3bc..cc2393d4a6c 100644 --- a/examples/android/androidEmptyExample/.cproject +++ b/examples/android/androidEmptyExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -67,11 +69,23 @@ + + + + + + + + + + + + + - diff --git a/examples/android/androidEmptyExample/.project b/examples/android/androidEmptyExample/.project index e558fc81569..f5c8f181bcf 100644 --- a/examples/android/androidEmptyExample/.project +++ b/examples/android/androidEmptyExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidEmptyExample/.settings/language.settings.xml b/examples/android/androidEmptyExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidEmptyExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidEmptyExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidEmptyExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidEmptyExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidEmptyExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidEmptyExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidEmptyExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidEmptyExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidEmptyExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidEmptyExample/build.gradle b/examples/android/androidEmptyExample/build.gradle index faed0ccbaf3..401fbe51104 100644 --- a/examples/android/androidEmptyExample/build.gradle +++ b/examples/android/androidEmptyExample/build.gradle @@ -1,12 +1,30 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + apply plugin: 'com.android.application' android { - compileSdkVersion 19 + compileSdkVersion 22 buildToolsVersion "21.1.1" defaultConfig { minSdkVersion 8 - targetSdkVersion 17 + targetSdkVersion 22 } buildTypes { @@ -19,7 +37,7 @@ android { sourceSets { main { manifest.srcFile 'AndroidManifest.xml' - jni.srcDirs = ['jni'] + jni.srcDirs = [] java.srcDirs = ['srcJava'] resources.srcDirs = ['srcJava'] aidl.srcDirs = ['srcJava'] @@ -35,23 +53,8 @@ dependencies { compile project(':ofAndroidLib') } -task compileReleaseOF(dependsOn: rootProject.ofNdkSetup) << { - rootProject.ofRunMake(["-C", projectDir.absolutePath, "PLATFORM_OS=Android", "Release"]) -} - -task compileDebugOF(dependsOn: rootProject.ofNdkSetup) << { - rootProject.ofRunMake(["-C", projectDir.absolutePath, "PLATFORM_OS=Android", "Debug"]) -} +clean.dependsOn(":openFrameworksProject:clean") -task cleanOF(dependsOn: rootProject.ofNdkSetup) << { - rootProject.ofRunMake(["-C", projectDir.absolutePath, "PLATFORM_OS=Android", "clean"]) -} +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") -clean { - dependsOn cleanOF -} - -project.afterEvaluate { - compileDebugNdk.dependsOn(compileDebugOF) - compileReleaseNdk.dependsOn(compileReleaseOF) -} +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidEmptyExample/project.properties b/examples/android/androidEmptyExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidEmptyExample/project.properties +++ b/examples/android/androidEmptyExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidEmptyExample/settings.gradle b/examples/android/androidEmptyExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidEmptyExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidFontExample/.cproject b/examples/android/androidFontExample/.cproject index 1440cf10200..cc2393d4a6c 100644 --- a/examples/android/androidFontExample/.cproject +++ b/examples/android/androidFontExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidFontExample/.project b/examples/android/androidFontExample/.project index 5a327935a5b..6f55f9284aa 100644 --- a/examples/android/androidFontExample/.project +++ b/examples/android/androidFontExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidFontExample/.settings/language.settings.xml b/examples/android/androidFontExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidFontExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidFontExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidFontExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidFontExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidFontExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidFontExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidFontExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidFontExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidFontExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidFontExample/build.gradle b/examples/android/androidFontExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidFontExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidFontExample/project.properties b/examples/android/androidFontExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidFontExample/project.properties +++ b/examples/android/androidFontExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidFontExample/settings.gradle b/examples/android/androidFontExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidFontExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidGuiExample/.cproject b/examples/android/androidGuiExample/.cproject index dc6dbf92939..cc2393d4a6c 100644 --- a/examples/android/androidGuiExample/.cproject +++ b/examples/android/androidGuiExample/.cproject @@ -8,52 +8,44 @@ - - - - + - + - - - - - + + + + + - - - + - - + + - - - - + - - - - - - - + + + + + + + @@ -77,11 +69,23 @@ + + + + + + + + + + + + + - diff --git a/examples/android/androidGuiExample/.project b/examples/android/androidGuiExample/.project index c5b82130b49..9b15c4924c1 100644 --- a/examples/android/androidGuiExample/.project +++ b/examples/android/androidGuiExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidGuiExample/.settings/language.settings.xml b/examples/android/androidGuiExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidGuiExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidGuiExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidGuiExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidGuiExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidGuiExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidGuiExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidGuiExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidGuiExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidGuiExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidGuiExample/build.gradle b/examples/android/androidGuiExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidGuiExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidGuiExample/project.properties b/examples/android/androidGuiExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidGuiExample/project.properties +++ b/examples/android/androidGuiExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidGuiExample/settings.gradle b/examples/android/androidGuiExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidGuiExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidImageExample/.cproject b/examples/android/androidImageExample/.cproject index a6e95e12b6c..cc2393d4a6c 100644 --- a/examples/android/androidImageExample/.cproject +++ b/examples/android/androidImageExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidImageExample/.project b/examples/android/androidImageExample/.project index 677f59d2d04..09d7a157fae 100644 --- a/examples/android/androidImageExample/.project +++ b/examples/android/androidImageExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidImageExample/.settings/language.settings.xml b/examples/android/androidImageExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidImageExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidImageExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidImageExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidImageExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidImageExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidImageExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidImageExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidImageExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidImageExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidImageExample/build.gradle b/examples/android/androidImageExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidImageExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidImageExample/project.properties b/examples/android/androidImageExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidImageExample/project.properties +++ b/examples/android/androidImageExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidImageExample/settings.gradle b/examples/android/androidImageExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidImageExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidOpenCVExample/.cproject b/examples/android/androidOpenCVExample/.cproject index caf47670a93..cc2393d4a6c 100644 --- a/examples/android/androidOpenCVExample/.cproject +++ b/examples/android/androidOpenCVExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidOpenCVExample/.project b/examples/android/androidOpenCVExample/.project index 9ae269b01c1..726743ce37a 100644 --- a/examples/android/androidOpenCVExample/.project +++ b/examples/android/androidOpenCVExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidOpenCVExample/.settings/language.settings.xml b/examples/android/androidOpenCVExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidOpenCVExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidOpenCVExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidOpenCVExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidOpenCVExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidOpenCVExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidOpenCVExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidOpenCVExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidOpenCVExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidOpenCVExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidOpenCVExample/build.gradle b/examples/android/androidOpenCVExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidOpenCVExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidOpenCVExample/project.properties b/examples/android/androidOpenCVExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidOpenCVExample/project.properties +++ b/examples/android/androidOpenCVExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidOpenCVExample/settings.gradle b/examples/android/androidOpenCVExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidOpenCVExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidOpenCVFaceExample/.cproject b/examples/android/androidOpenCVFaceExample/.cproject index acc88419ad7..cc2393d4a6c 100644 --- a/examples/android/androidOpenCVFaceExample/.cproject +++ b/examples/android/androidOpenCVFaceExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidOpenCVFaceExample/.project b/examples/android/androidOpenCVFaceExample/.project index 8fdc96a7904..c8a34842b00 100644 --- a/examples/android/androidOpenCVFaceExample/.project +++ b/examples/android/androidOpenCVFaceExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidOpenCVFaceExample/.settings/language.settings.xml b/examples/android/androidOpenCVFaceExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidOpenCVFaceExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidOpenCVFaceExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidOpenCVFaceExample/build.gradle b/examples/android/androidOpenCVFaceExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidOpenCVFaceExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidOpenCVFaceExample/project.properties b/examples/android/androidOpenCVFaceExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidOpenCVFaceExample/project.properties +++ b/examples/android/androidOpenCVFaceExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidOpenCVFaceExample/settings.gradle b/examples/android/androidOpenCVFaceExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidOpenCVFaceExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidPolygonExample/.cproject b/examples/android/androidPolygonExample/.cproject index ec39aaabd03..cc2393d4a6c 100644 --- a/examples/android/androidPolygonExample/.cproject +++ b/examples/android/androidPolygonExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidPolygonExample/.project b/examples/android/androidPolygonExample/.project index bf71ae2c412..44f19b6a3b0 100644 --- a/examples/android/androidPolygonExample/.project +++ b/examples/android/androidPolygonExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidPolygonExample/.settings/language.settings.xml b/examples/android/androidPolygonExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidPolygonExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidPolygonExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidPolygonExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidPolygonExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidPolygonExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidPolygonExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidPolygonExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidPolygonExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidPolygonExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidPolygonExample/build.gradle b/examples/android/androidPolygonExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidPolygonExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidPolygonExample/project.properties b/examples/android/androidPolygonExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidPolygonExample/project.properties +++ b/examples/android/androidPolygonExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidPolygonExample/settings.gradle b/examples/android/androidPolygonExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidPolygonExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidShaderExample/.cproject b/examples/android/androidShaderExample/.cproject index dc6dbf92939..cc2393d4a6c 100644 --- a/examples/android/androidShaderExample/.cproject +++ b/examples/android/androidShaderExample/.cproject @@ -8,52 +8,44 @@ - - - - + - + - - - - - + + + + + - - - + - - + + - - - - + - - - - - - - + + + + + + + @@ -77,11 +69,23 @@ + + + + + + + + + + + + + - diff --git a/examples/android/androidShaderExample/.project b/examples/android/androidShaderExample/.project index 56ea95130ff..a043103a2e2 100644 --- a/examples/android/androidShaderExample/.project +++ b/examples/android/androidShaderExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidShaderExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidShaderExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidShaderExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidShaderExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidShaderExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidShaderExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidShaderExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidShaderExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidShaderExample/build.gradle b/examples/android/androidShaderExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidShaderExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidShaderExample/project.properties b/examples/android/androidShaderExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidShaderExample/project.properties +++ b/examples/android/androidShaderExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidShaderExample/settings.gradle b/examples/android/androidShaderExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidShaderExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidShaderExample/src/main.cpp b/examples/android/androidShaderExample/src/main.cpp index f8231811266..a8ae3c8ae9e 100644 --- a/examples/android/androidShaderExample/src/main.cpp +++ b/examples/android/androidShaderExample/src/main.cpp @@ -3,14 +3,14 @@ #include "ofGLProgrammableRenderer.h" int main(){ - ofSetCurrentRenderer(ofPtr(new ofGLProgrammableRenderer())); - ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context + ofGLESWindowSettings settings; + settings.setGLESVersion(2); + ofCreateWindow(settings); // <-------- 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 ofApp() ); - return 0; + return ofRunApp( new ofApp() ); } diff --git a/examples/android/androidShaderExample/src/ofApp.cpp b/examples/android/androidShaderExample/src/ofApp.cpp index e8a46d293d0..a598d821a3b 100644 --- a/examples/android/androidShaderExample/src/ofApp.cpp +++ b/examples/android/androidShaderExample/src/ofApp.cpp @@ -11,6 +11,21 @@ void ofApp::setup(){ font.load("type/verdana.ttf", 80, true, false, true, 0.4, 72); shader.load("shaders/noise.vert", "shaders/noise.frag"); + auto textShapes = font.getStringAsPoints("openFrameworks"); + ofRectangle boundingBox; + for(auto glyph: textShapes){ + text.append(glyph); + for(auto outline: glyph.getOutline()){ + boundingBox = boundingBox.getUnion(outline.getBoundingBox()); + } + } + + boundingBox.alignTo(ofGetCurrentViewport(), OF_ALIGN_HORZ_CENTER, OF_ALIGN_VERT_CENTER); + ofVec2f textPos(boundingBox.getX(), boundingBox.getMaxY()); + + text.translate(textPos); + text.setFillColor(ofColor(245, 58, 135)); + doShader = false; } @@ -21,12 +36,6 @@ void ofApp::update(){ //-------------------------------------------------------------- void ofApp::draw(){ - - ofSetColor(225); - - ofSetColor(245, 58, 135); - ofFill(); - if( doShader ){ shader.begin(); //we want to pass in some varrying values to animate our type / color @@ -35,12 +44,12 @@ void ofApp::draw(){ //we also pass in the mouse position //we have to transform the coords to what the shader is expecting which is 0,0 in the center and y axis flipped. - shader.setUniform2f("mouse", mouseX - ofGetWidth()/2, ofGetHeight()/2-mouseY ); + shader.setUniform2f("mouse", ofGetMouseX() - ofGetWidth()/2, ofGetHeight()/2-ofGetMouseY() ); } //finally draw our text - font.drawStringAsShapes("openFrameworks", 90, 260); + text.draw(); if( doShader ){ shader.end(); @@ -109,7 +118,7 @@ void ofApp::resume(){ //-------------------------------------------------------------- void ofApp::reloadTextures(){ - shader.load("shaders/noise.vert", "shaders/noise.frag"); + } //-------------------------------------------------------------- diff --git a/examples/android/androidShaderExample/src/ofApp.h b/examples/android/androidShaderExample/src/ofApp.h index 5c1ea1b2aa4..e7163b7d3e7 100644 --- a/examples/android/androidShaderExample/src/ofApp.h +++ b/examples/android/androidShaderExample/src/ofApp.h @@ -34,6 +34,7 @@ class ofApp : public ofxAndroidApp{ void cancelPressed(); + ofPath text; ofTrueTypeFont font; ofShader shader; bool doShader; diff --git a/examples/android/androidShaderExampleOld/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidShaderExampleOld/.settings/org.eclipse.cdt.codan.core.prefs deleted file mode 100644 index d1c7b011aba..00000000000 --- a/examples/android/androidShaderExampleOld/.settings/org.eclipse.cdt.codan.core.prefs +++ /dev/null @@ -1,67 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.cdt.codan.checkers.errnoreturn=Warning -org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.checkers.errreturnvalue=Error -org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.checkers.noreturn=Error -org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} -org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning -org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error -org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error -org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} diff --git a/examples/android/androidShaderExampleOld/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidShaderExampleOld/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 8000cd6ca61..00000000000 --- a/examples/android/androidShaderExampleOld/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/examples/android/androidSoundPlayerExample/.cproject b/examples/android/androidSoundPlayerExample/.cproject index e505fc941c4..cc2393d4a6c 100644 --- a/examples/android/androidSoundPlayerExample/.cproject +++ b/examples/android/androidSoundPlayerExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,28 +55,37 @@ - + - + - + - + - + + + + + + + + + + diff --git a/examples/android/androidSoundPlayerExample/.project b/examples/android/androidSoundPlayerExample/.project index fc2711e5f3c..a7c4446a186 100644 --- a/examples/android/androidSoundPlayerExample/.project +++ b/examples/android/androidSoundPlayerExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidSoundPlayerExample/.settings/language.settings.xml b/examples/android/androidSoundPlayerExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidSoundPlayerExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidSoundPlayerExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidSoundPlayerExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidSoundPlayerExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidSoundPlayerExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidSoundPlayerExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidSoundPlayerExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidSoundPlayerExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidSoundPlayerExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidSoundPlayerExample/build.gradle b/examples/android/androidSoundPlayerExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidSoundPlayerExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidSoundPlayerExample/project.properties b/examples/android/androidSoundPlayerExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidSoundPlayerExample/project.properties +++ b/examples/android/androidSoundPlayerExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidSoundPlayerExample/settings.gradle b/examples/android/androidSoundPlayerExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidSoundPlayerExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidSwipeExample/.cproject b/examples/android/androidSwipeExample/.cproject index 9631ac04857..cc2393d4a6c 100644 --- a/examples/android/androidSwipeExample/.cproject +++ b/examples/android/androidSwipeExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidSwipeExample/.project b/examples/android/androidSwipeExample/.project index ad345d1a974..e15eddd2535 100644 --- a/examples/android/androidSwipeExample/.project +++ b/examples/android/androidSwipeExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidSwipeExample/.settings/language.settings.xml b/examples/android/androidSwipeExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidSwipeExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidSwipeExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidSwipeExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidSwipeExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidSwipeExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidSwipeExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidSwipeExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidSwipeExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidSwipeExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidSwipeExample/build.gradle b/examples/android/androidSwipeExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidSwipeExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidSwipeExample/project.properties b/examples/android/androidSwipeExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidSwipeExample/project.properties +++ b/examples/android/androidSwipeExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidSwipeExample/settings.gradle b/examples/android/androidSwipeExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidSwipeExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidSwipeExample/src/ofApp.cpp b/examples/android/androidSwipeExample/src/ofApp.cpp index 61a58f4d1f9..32a2ad3cacb 100644 --- a/examples/android/androidSwipeExample/src/ofApp.cpp +++ b/examples/android/androidSwipeExample/src/ofApp.cpp @@ -2,7 +2,7 @@ //-------------------------------------------------------------- void ofApp::setup(){ - ofRegisterTouchEvents((ofxAndroidApp*)this); + } //-------------------------------------------------------------- diff --git a/examples/android/androidTouchExample/.cproject b/examples/android/androidTouchExample/.cproject index 9759cabd2f5..cc2393d4a6c 100644 --- a/examples/android/androidTouchExample/.cproject +++ b/examples/android/androidTouchExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidTouchExample/.project b/examples/android/androidTouchExample/.project index 7329de03bf0..bf482f67434 100644 --- a/examples/android/androidTouchExample/.project +++ b/examples/android/androidTouchExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidTouchExample/.settings/language.settings.xml b/examples/android/androidTouchExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidTouchExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidTouchExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidTouchExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidTouchExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidTouchExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidTouchExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidTouchExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidTouchExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidTouchExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidTouchExample/build.gradle b/examples/android/androidTouchExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidTouchExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidTouchExample/project.properties b/examples/android/androidTouchExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidTouchExample/project.properties +++ b/examples/android/androidTouchExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidTouchExample/settings.gradle b/examples/android/androidTouchExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidTouchExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidVBOExample/.cproject b/examples/android/androidVBOExample/.cproject index 6cb6df99c5b..cc2393d4a6c 100644 --- a/examples/android/androidVBOExample/.cproject +++ b/examples/android/androidVBOExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidVBOExample/.project b/examples/android/androidVBOExample/.project index e4ff02383dc..9272856c67b 100644 --- a/examples/android/androidVBOExample/.project +++ b/examples/android/androidVBOExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidVBOExample/.settings/language.settings.xml b/examples/android/androidVBOExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidVBOExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidVBOExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidVBOExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidVBOExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidVBOExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidVBOExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidVBOExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidVBOExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidVBOExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidVBOExample/build.gradle b/examples/android/androidVBOExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidVBOExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidVBOExample/project.properties b/examples/android/androidVBOExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidVBOExample/project.properties +++ b/examples/android/androidVBOExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidVBOExample/settings.gradle b/examples/android/androidVBOExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidVBOExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidVibratorExample/.cproject b/examples/android/androidVibratorExample/.cproject index 59b252ceeea..cc2393d4a6c 100644 --- a/examples/android/androidVibratorExample/.cproject +++ b/examples/android/androidVibratorExample/.cproject @@ -8,42 +8,44 @@ + + - + - - - - - + + + + + - - - + - - + + + + - - - - - - - + + + + + + + @@ -53,25 +55,37 @@ - + - + - + - + + + + + + + + + + + + + + - diff --git a/examples/android/androidVibratorExample/.settings/language.settings.xml b/examples/android/androidVibratorExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidVibratorExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidVibratorExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidVibratorExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidVibratorExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidVibratorExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidVibratorExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidVibratorExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidVibratorExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidVibratorExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidVibratorExample/build.gradle b/examples/android/androidVibratorExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidVibratorExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidVibratorExample/project.properties b/examples/android/androidVibratorExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidVibratorExample/project.properties +++ b/examples/android/androidVibratorExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidVibratorExample/settings.gradle b/examples/android/androidVibratorExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidVibratorExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/androidVideoExample/.cproject b/examples/android/androidVideoExample/.cproject index e643764ad4a..cc2393d4a6c 100644 --- a/examples/android/androidVideoExample/.cproject +++ b/examples/android/androidVideoExample/.cproject @@ -8,52 +8,44 @@ - - - - + - + - - - - - + + + + + - - - + - - + + - - - - + - - - - - - - + + + + + + + @@ -66,14 +58,34 @@ - - + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/examples/android/androidVideoExample/.project b/examples/android/androidVideoExample/.project index 4c17243e269..c2e23ed10fd 100644 --- a/examples/android/androidVideoExample/.project +++ b/examples/android/androidVideoExample/.project @@ -94,4 +94,11 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + ofxAndroid + 2 + $%7BPARENT-3-PROJECT_LOC%7D/addons/ofxAndroid + + diff --git a/examples/android/androidVideoExample/.settings/language.settings.xml b/examples/android/androidVideoExample/.settings/language.settings.xml new file mode 100644 index 00000000000..cd50bd7d3f0 --- /dev/null +++ b/examples/android/androidVideoExample/.settings/language.settings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/android/androidVideoExample/.settings/org.eclipse.cdt.codan.core.prefs b/examples/android/androidVideoExample/.settings/org.eclipse.cdt.codan.core.prefs index 810101ec581..704d8817997 100644 --- a/examples/android/androidVideoExample/.settings/org.eclipse.cdt.codan.core.prefs +++ b/examples/android/androidVideoExample/.settings/org.eclipse.cdt.codan.core.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +inEditor=false org.eclipse.cdt.codan.checkers.errnoreturn=Warning org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.checkers.errreturnvalue=Error org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.checkers.noreturn=Error org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error @@ -14,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={lau org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error diff --git a/examples/android/androidVideoExample/.settings/org.eclipse.jdt.core.prefs b/examples/android/androidVideoExample/.settings/org.eclipse.jdt.core.prefs index 8000cd6ca61..ef8a789ca02 100644 --- a/examples/android/androidVideoExample/.settings/org.eclipse.jdt.core.prefs +++ b/examples/android/androidVideoExample/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 diff --git a/examples/android/androidVideoExample/build.gradle b/examples/android/androidVideoExample/build.gradle new file mode 100644 index 00000000000..401fbe51104 --- /dev/null +++ b/examples/android/androidVideoExample/build.gradle @@ -0,0 +1,60 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.1" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + } + + buildTypes { + release { + minifyEnabled false + } + } + + // Configure source folders like Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + jni.srcDirs = [] + java.srcDirs = ['srcJava'] + resources.srcDirs = ['srcJava'] + aidl.srcDirs = ['srcJava'] + renderscript.srcDirs = ['srcJava'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } +} + +dependencies { + compile project(':ofAndroidLib') +} + +clean.dependsOn(":openFrameworksProject:clean") + +assembleDebug.dependsOn(":openFrameworksProject:compileDebugOF") + +assembleRelease.dependsOn(":openFrameworksProject:compileReleaseOF") diff --git a/examples/android/androidVideoExample/project.properties b/examples/android/androidVideoExample/project.properties index 1052e2e6579..c8d5c871660 100644 --- a/examples/android/androidVideoExample/project.properties +++ b/examples/android/androidVideoExample/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-22 android.library.reference.1=../../../addons/ofxAndroid/ofAndroidLib diff --git a/examples/android/androidVideoExample/settings.gradle b/examples/android/androidVideoExample/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/examples/android/androidVideoExample/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/events/eventsExample/src/ofApp.cpp b/examples/events/eventsExample/src/ofApp.cpp index 0dd8e836aa4..17996369d3f 100644 --- a/examples/events/eventsExample/src/ofApp.cpp +++ b/examples/events/eventsExample/src/ofApp.cpp @@ -17,9 +17,6 @@ void ofApp::draw(){ timeString = "time: " + ofGetTimestampString("%H:%M:%S") + "\nelapsed time: " + ofToString(ofGetElapsedTimeMillis()); - float w = vagRounded.stringWidth(eventString); - float h = vagRounded.stringHeight(eventString); - ofSetHexColor(0xffffff); vagRounded.drawString(eventString, 98,198); diff --git a/examples/events/multiWindowOneAppExample/src/main.cpp b/examples/events/multiWindowOneAppExample/src/main.cpp index 1a724f9e5ab..805f27df293 100644 --- a/examples/events/multiWindowOneAppExample/src/main.cpp +++ b/examples/events/multiWindowOneAppExample/src/main.cpp @@ -15,6 +15,8 @@ int main( ){ settings.height = 300; settings.setPosition(ofVec2f(0,0)); settings.resizable = false; + // uncomment next line to share main's OpenGL resources with gui + //settings.shareContextWith = mainWindow; shared_ptr guiWindow = ofCreateWindow(settings); guiWindow->setVerticalSync(false); diff --git a/examples/gl/areaLightExample/src/main.cpp b/examples/gl/areaLightExample/src/main.cpp index bd31d82e82e..87df8eb8236 100644 --- a/examples/gl/areaLightExample/src/main.cpp +++ b/examples/gl/areaLightExample/src/main.cpp @@ -4,7 +4,7 @@ //======================================================================== int main( ){ ofGLWindowSettings s; - s.setGLVersion(3,3); + s.setGLVersion(3,2); ofCreateWindow(s); // this kicks off the running of my app diff --git a/examples/gl/gpuParticleSystemExample/src/ofApp.cpp b/examples/gl/gpuParticleSystemExample/src/ofApp.cpp index 216139a83f9..e9a86b650aa 100644 --- a/examples/gl/gpuParticleSystemExample/src/ofApp.cpp +++ b/examples/gl/gpuParticleSystemExample/src/ofApp.cpp @@ -37,7 +37,7 @@ void ofApp::setup(){ numParticles = textureRes * textureRes; // 1. Making arrays of float pixels with position information - float * pos = new float[numParticles*3]; + vector pos(numParticles*3); for (int x = 0; x < textureRes; x++){ for (int y = 0; y < textureRes; y++){ int i = textureRes * y + x; @@ -47,25 +47,23 @@ void ofApp::setup(){ pos[i*3 + 2] = 0.0; } } - // Load this information in to the FBO�s texture - posPingPong.allocate(textureRes, textureRes,GL_RGB32F); - posPingPong.src->getTexture().loadData(pos, textureRes, textureRes, GL_RGB); - posPingPong.dst->getTexture().loadData(pos, textureRes, textureRes, GL_RGB); - delete [] pos; // Delete the array + // Load this information in to the FBO's texture + posPingPong.allocate(textureRes, textureRes, GL_RGB32F); + posPingPong.src->getTexture().loadData(pos.data(), textureRes, textureRes, GL_RGB); + posPingPong.dst->getTexture().loadData(pos.data(), textureRes, textureRes, GL_RGB); // 2. Making arrays of float pixels with velocity information and the load it to a texture - float * vel = new float[numParticles*3]; + vector vel(numParticles*3); for (int i = 0; i < numParticles; i++){ vel[i*3 + 0] = ofRandom(-1.0,1.0); vel[i*3 + 1] = ofRandom(-1.0,1.0); vel[i*3 + 2] = 1.0; } - // Load this information in to the FBO�s texture - velPingPong.allocate(textureRes, textureRes,GL_RGB32F); - velPingPong.src->getTexture().loadData(vel, textureRes, textureRes, GL_RGB); - velPingPong.dst->getTexture().loadData(vel, textureRes, textureRes, GL_RGB); - delete [] vel; // Delete the array + // Load this information in to the FBO's texture + velPingPong.allocate(textureRes, textureRes, GL_RGB32F); + velPingPong.src->getTexture().loadData(vel.data(), textureRes, textureRes, GL_RGB); + velPingPong.dst->getTexture().loadData(vel.data(), textureRes, textureRes, GL_RGB); // Loading and setings of the variables of the textures of the particles sparkImg.load("spark.png"); @@ -91,9 +89,9 @@ void ofApp::setup(){ //-------------------------------------------------------------- void ofApp::update(){ - // In each cycle it�s going to update the velocity first and the the position + // In each cycle it's going to update the velocity first and the the position // Each one one with a different shader and FBO. - // Because on GPU you can�t write over the texture that you are reading we are + // Because on GPU you can't write over the texture that you are reading we are // using to pair of ofFbo attached together on what we call pingPongBuffer // Learn more about Ping-Pong at: // @@ -102,7 +100,7 @@ void ofApp::update(){ // Velocities PingPong // - // It calculates the next frame and see if it�s there any collition + // It calculates the next frame and see if it's there any collition // then updates the velocity with that information // velPingPong.dst->begin(); @@ -146,11 +144,11 @@ void ofApp::update(){ // Rendering // // 1. Sending this vertex to the Vertex Shader. - // Each one it�s draw exactly on the position that match where it�s stored on both vel and pos textures - // So on the Vertex Shader (that�s is first at the pipeline) can search for it information and move it + // Each one it's draw exactly on the position that match where it's stored on both vel and pos textures + // So on the Vertex Shader (that's is first at the pipeline) can search for it information and move it // to it right position. - // 2. Once it�s in the right place the Geometry Shader make 6 more vertex in order to make a billboard - // 3. that then on the Fragment Shader it�s going to be filled with the pixels of sparkImg texture + // 2. Once it's in the right place the Geometry Shader make 6 more vertex in order to make a billboard + // 3. that then on the Fragment Shader is going to be filled with the pixels of sparkImg texture // renderFBO.begin(); ofClear(0,0,0,0); diff --git a/examples/gl/gpuParticleSystemExample/src/ofApp.h b/examples/gl/gpuParticleSystemExample/src/ofApp.h index 20aaad80621..ea382d05888 100644 --- a/examples/gl/gpuParticleSystemExample/src/ofApp.h +++ b/examples/gl/gpuParticleSystemExample/src/ofApp.h @@ -25,7 +25,7 @@ // struct pingPongBuffer { public: - void allocate( int _width, int _height, int _internalformat = GL_RGBA, float _dissipation = 1.0f){ + void allocate( int _width, int _height, int _internalformat = GL_RGBA){ // Allocate for(int i = 0; i < 2; i++){ FBOs[i].allocate(_width,_height, _internalformat ); @@ -34,16 +34,10 @@ struct pingPongBuffer { // Clean clear(); - - // Set everything to 0 - flag = 0; - swap(); - flag = 0; } void swap(){ - src = &(FBOs[(flag)%2]); - dst = &(FBOs[++(flag)%2]); + std::swap(src,dst); } void clear(){ @@ -55,12 +49,11 @@ struct pingPongBuffer { } ofFbo& operator[]( int n ){ return FBOs[n];} - - ofFbo *src; // Source -> Ping - ofFbo *dst; // Destination -> Pong + ofFbo *src = &FBOs[0]; // Source -> Ping + ofFbo *dst = &FBOs[1]; // Destination -> Pong + private: - ofFbo FBOs[2]; // Real addresses of ping/pong FBOs - int flag; // Integer for making a quick swap + ofFbo FBOs[2]; // Real addresses of ping/pong FBOs }; diff --git a/examples/gl/shaderExample/src/main.cpp b/examples/gl/shaderExample/src/main.cpp index c09200580b2..cda92e80fb4 100644 --- a/examples/gl/shaderExample/src/main.cpp +++ b/examples/gl/shaderExample/src/main.cpp @@ -1,20 +1,23 @@ #include "ofMain.h" #include "ofApp.h" -#ifdef TARGET_OPENGLES -#include "ofGLProgrammableRenderer.h" -#endif + //======================================================================== int main( ){ ofSetLogLevel(OF_LOG_VERBOSE); + int windowWidth = 1024; + int windowHeight = 500; + #ifdef TARGET_OPENGLES - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); + ofGLESWindowSettings settings; + settings.width = windowWidth; + settings.height = windowHeight; + settings.setGLESVersion(2); + ofCreateWindow(settings); + #else + ofSetupOpenGL(windowWidth, windowHeight, OF_WINDOW); #endif - ofSetupOpenGL(1024,500, 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 ofApp()); } diff --git a/examples/gl/textureBufferInstancedExample/src/ofApp.cpp b/examples/gl/textureBufferInstancedExample/src/ofApp.cpp index 1e7e6be9d8d..d738db8ba65 100644 --- a/examples/gl/textureBufferInstancedExample/src/ofApp.cpp +++ b/examples/gl/textureBufferInstancedExample/src/ofApp.cpp @@ -34,7 +34,7 @@ void ofApp::setup(){ // we want each box to have a different color so let's add // as many colors as boxes mesh.getColors().resize(matrices.size()); - for(int i=0;i(label_param.set("LabelName", "label without labelname"), labelconfig); + + /* + * FPS plotter + */ + panel1.add(); + + /* + * minimal button and toggle + */ + panel1.add(toggle_param.set("show header", true)); + toggle_param.addListener(this, &ofApp::toggleGroupHeader); + panel1.add(button.setup("simple button")); + + /* + * rotary slider + */ + rotary.setup("rotary"); + rotary.add(slider_param.set("slider", 0.5, 0, 1)); + panel1.add(rotary); + + /* + * labels can not only show string values but any ofParameter with a toString()-function + */ + panel1.add(matrix_active_name.set("element name", "")); + panel1.add(matrix_active_index.set("element index", -1)); + + /* + * matrix with only one allowed active toggle, listener to use labels above to show current index + */ + matrix_params.push_back(ofParameter ("only", false)); + matrix_params.push_back(ofParameter ("one", false)); + matrix_params.push_back(ofParameter ("toggle", false)); + matrix_params.push_back(ofParameter ("can", false)); + matrix_params.push_back(ofParameter ("be", false)); + matrix_params.push_back(ofParameter ("active", false)); + + matrix.setup("matrix", 3); + matrix.setExclusiveToggles(true); + matrix.getActiveToggleIndex().addListener(this, &ofApp::updateMatrixIndex); + for(unsigned int i = 0; i < matrix_params.size(); i++){ + matrix.add(matrix_params.at(i)); + } + panel1.add(matrix); + + /* + * input fields + */ + panel1.add(floatfield_param.set("float input",3.5,0,500)); + panel1.add(textfield_param.set("text input","type in here")); + + /* + * horizontal panel + */ + panel2.setup("horizontal", "", 260, 10); + panel2.setLayout(ofxBaseGui::Horizontal); + panel2.setBorderColor(ofColor::black); + + ofxToggle::Config toggle_config; + toggle_config.shape.width = 90; + panel2.add (toggle1_param.set("toggle1", false), toggle_config); + panel2.add (toggle2_param.set("toggle2", false), toggle_config); + panel2.add (toggle3_param.set("toggle3", false), toggle_config); + panel2.add (toggle4_param.set("toggle4", false), toggle_config); + + /* + * horizontal panel with vertical sliders and spacer + */ + panel3.setup("vertical sliders, spacer", "", 260, 80); + panel3.setLayout(ofxBaseGui::Horizontal); + + ofxBaseGui::Config slider_config; + slider_config.layout = ofxBaseGui::Vertical; + + panel3.add (slider1_param.set("slider1", 1. / 7., 0, 1), slider_config); + panel3.addSpacer(42); + panel3.add (slider2_param.set("slider2", 5. / 7., 0, 1), slider_config); + panel3.add (slider3_param.set("slider3", 4. / 7., 0, 1), slider_config); + panel3.add (slider4_param.set("slider4", 6. / 7., 0, 1), slider_config); + + panel3.getControl("slider1")->setSize(40, 130); + panel3.getControl("slider2")->setSize(50, 130); + panel3.getControl("slider3")->setSize(60, 130); + panel3.getControl("slider4")->setSize(70, 130); + + /* + * set precision of sliders + */ + panel4.setup("slider precision","", 260, 240); + ofxFloatSlider::Config slider_config2; + slider_config2.precision = 1; + panel4.add (slider1_param, slider_config2); + panel4.add (slider2_param, slider_config2); + panel4.add (slider3_param, slider_config2); + panel4.add (slider4_param, slider_config2); + + + cameraMatrixParameters.setName("cameras"); + cameraMatrixParameters.add(cam0.set("cam0",false)); + cameraMatrixParameters.add(cam1.set("cam1",false)); + cameraMatrixParameters.add(cam2.set("cam2",false)); + cameraMatrixParameters.add(cam3.set("cam3",false)); + + panel5.setup("ofParameterGroup", "", 260, 440); + matrixCam.setup(cameraMatrixParameters, 4); + matrixCam.setExclusiveToggles(true); + panel5.add(matrixCam); + +} + +//-------------------------------------------------------------- +void ofApp::exit(){ +} + +//-------------------------------------------------------------- +void ofApp::update(){ +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + + if(toggle1_param.get()){ + ofSetColor(ofColor::royalBlue); + }else{ + if(toggle2_param.get()){ + ofSetColor(ofColor::azure); + }else{ + if(matrix_params.at(0).get()){ + ofSetColor(ofColor::burlyWood); + }else{ + ofSetColor(ofColor::fromHex(0x2da1e3)); + } + } + } + + ofDrawRectangle(ofGetWindowRect()); + + ofSetColor(255); + + panel1.draw(); + panel2.draw(); + panel3.draw(); + panel4.draw(); + panel5.draw(); + +} + +void ofApp::toggleGroupHeader(bool & val){ + rotary.setShowHeader(val); + matrix.setShowHeader(val); + panel1.setShowHeader(val); + panel2.setShowHeader(val); + panel3.setShowHeader(val); + panel4.setShowHeader(val); + panel5.setShowHeader(val); +} + +void ofApp::updateMatrixIndex(int &index){ + matrix_active_index = index; + matrix_active_name = matrix.getControl(index)->getName(); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + switch(key){ + case 'f': { + ofToggleFullscreen(); + break; + } + + default: + break; + } + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(ofMouseEventArgs & args){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/examples/gui/advancedGuiExample/src/ofApp.h b/examples/gui/advancedGuiExample/src/ofApp.h new file mode 100644 index 00000000000..a229ac17126 --- /dev/null +++ b/examples/gui/advancedGuiExample/src/ofApp.h @@ -0,0 +1,57 @@ +#pragma once + +#include "ofMain.h" +#include "ofxGui.h" +#include "ofxInputField.h" + +class ofApp : public ofBaseApp { + + public: + void setup(); + void update(); + void draw(); + + void exit(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(ofMouseEventArgs & args); + void mouseDragged(ofMouseEventArgs & args); + void mousePressed(ofMouseEventArgs & args); + void mouseReleased(ofMouseEventArgs & args); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + private: + + ofxPanel panel1, panel2, panel3, panel4, panel5; + ofxGuiGroup rotary; + ofxGuiMatrix matrix; + ofParameter matrix_active_name; + ofParameter matrix_active_index; + ofParameter floatfield_param; + ofParameter textfield_param; + + ofxMinimalButton button; + + ofParameter label_param; + ofParameter toggle_param; + ofParameter slider_param; + ofParameter toggle1_param, toggle2_param, toggle3_param, toggle4_param; + ofParameter slider1_param, slider2_param, slider3_param, slider4_param; + vector > matrix_params; + ofParameterGroup g; + + ofParameterGroup cameraMatrixParameters; + ofParameter cam0; + ofParameter cam2; + ofParameter cam3; + ofParameter cam1; + ofxGuiMatrix matrixCam; + + void toggleGroupHeader(bool & val); + void updateMatrixIndex(int& index); + +}; + diff --git a/examples/gui/guiExample/src/ofApp.cpp b/examples/gui/guiExample/src/ofApp.cpp index 4d1751bb2bd..f68f6290a8c 100644 --- a/examples/gui/guiExample/src/ofApp.cpp +++ b/examples/gui/guiExample/src/ofApp.cpp @@ -2,91 +2,91 @@ //-------------------------------------------------------------- void ofApp::setup(){ - ofSetVerticalSync(true); + ofSetVerticalSync(true); - // we add this listener before setting up so the initial circle resolution is correct - circleResolution.addListener(this, &ofApp::circleResolutionChanged); - ringButton.addListener(this, &ofApp::ringButtonPressed); + // we add this listener before setting up so the initial circle resolution is correct + circleResolution.addListener(this, &ofApp::circleResolutionChanged); + ringButton.addListener(this, &ofApp::ringButtonPressed); - gui.setup(); // most of the time you don't need a name - gui.add(filled.setup("fill", true)); - gui.add(radius.setup("radius", 140, 10, 300)); - gui.add(center.setup("center", ofVec2f(ofGetWidth()*.5, ofGetHeight()*.5), ofVec2f(0, 0), ofVec2f(ofGetWidth(), ofGetHeight()))); - gui.add(color.setup("color", ofColor(100, 100, 140), ofColor(0, 0), ofColor(255, 255))); - gui.add(circleResolution.setup("circle res", 5, 3, 90)); - gui.add(twoCircles.setup("two circles")); - gui.add(ringButton.setup("ring")); - gui.add(screenSize.setup("screen size", ofToString(ofGetWidth())+"x"+ofToString(ofGetHeight()))); + gui.setup(); // most of the time you don't need a name + gui.add(filled.setup("fill", true)); + gui.add(radius.setup("radius", 140, 10, 300)); + gui.add(center.setup("center", ofVec2f(ofGetWidth()*.5, ofGetHeight()*.5), ofVec2f(0, 0), ofVec2f(ofGetWidth(), ofGetHeight()))); + gui.add(color.setup("color", ofColor(100, 100, 140), ofColor(0, 0), ofColor(255, 255))); + gui.add(circleResolution.setup("circle res", 5, 3, 90)); + gui.add(twoCircles.setup("two circles")); + gui.add(ringButton.setup("ring")); + gui.add(screenSize.setup("screen size", ofToString(ofGetWidth())+"x"+ofToString(ofGetHeight()))); - bHide = false; + bHide = false; - ring.load("ring.wav"); + ring.load("ring.wav"); } //-------------------------------------------------------------- void ofApp::exit(){ - ringButton.removeListener(this, &ofApp::ringButtonPressed); + ringButton.removeListener(this, &ofApp::ringButtonPressed); } //-------------------------------------------------------------- void ofApp::circleResolutionChanged(int &circleResolution){ - ofSetCircleResolution(circleResolution); + ofSetCircleResolution(circleResolution); } //-------------------------------------------------------------- void ofApp::ringButtonPressed(){ - ring.play(); + ring.play(); } //-------------------------------------------------------------- void ofApp::update(){ - ofSetCircleResolution(circleResolution); + ofSetCircleResolution(circleResolution); } //-------------------------------------------------------------- void ofApp::draw(){ ofBackgroundGradient(ofColor::white, ofColor::gray); - - if(filled){ - ofFill(); - }else{ - ofNoFill(); - } - - ofSetColor(color); - if(twoCircles){ - ofDrawCircle(center->x-radius*.5, center->y, radius ); - ofDrawCircle(center->x+radius*.5, center->y, radius ); - }else{ - ofDrawCircle((ofVec2f)center, radius ); - } - - // auto draw? - // should the gui control hiding? - if(!bHide){ - gui.draw(); - } + + if(filled){ + ofFill(); + }else{ + ofNoFill(); + } + + ofSetColor(color); + if(twoCircles){ + ofDrawCircle(center->x-radius*.5, center->y, radius ); + ofDrawCircle(center->x+radius*.5, center->y, radius ); + }else{ + ofDrawCircle((ofVec2f)center, radius ); + } + + // auto draw? + // should the gui control hiding? + if(!bHide){ + gui.draw(); + } } //-------------------------------------------------------------- void ofApp::keyPressed(int key){ - if(key == 'h'){ - bHide = !bHide; - } - else if(key == 's'){ - gui.saveToFile("settings.xml"); - } - else if(key == 'l'){ - gui.loadFromFile("settings.xml"); - } - else if(key == ' '){ - color = ofColor(255); - } + if(key == 'h'){ + bHide = !bHide; + } + else if(key == 's'){ + gui.saveToFile("settings.xml"); + } + else if(key == 'l'){ + gui.loadFromFile("settings.xml"); + } + else if(key == ' '){ + color = ofColor(255); + } } //-------------------------------------------------------------- void ofApp::keyReleased(int key){ - + } //-------------------------------------------------------------- @@ -101,12 +101,12 @@ void ofApp::mouseDragged(int x, int y, int button){ //-------------------------------------------------------------- void ofApp::mousePressed(int x, int y, int button){ - + } //-------------------------------------------------------------- void ofApp::mouseReleased(int x, int y, int button){ - + } //-------------------------------------------------------------- @@ -126,10 +126,10 @@ void ofApp::windowResized(int w, int h){ //-------------------------------------------------------------- void ofApp::gotMessage(ofMessage msg){ - + } //-------------------------------------------------------------- -void ofApp::dragEvent(ofDragInfo dragInfo){ - +void ofApp::dragEvent(ofDragInfo dragInfo){ + } diff --git a/examples/gui/guiFromParametersExample/src/ofApp.cpp b/examples/gui/guiFromParametersExample/src/ofApp.cpp index 62b80eac28c..a11d05ee9b7 100644 --- a/examples/gui/guiFromParametersExample/src/ofApp.cpp +++ b/examples/gui/guiFromParametersExample/src/ofApp.cpp @@ -7,7 +7,7 @@ void ofApp::setup(){ // we add this listener before setting up so the initial circle resolution is correct circleResolution.addListener(this, &ofApp::circleResolutionChanged); - ringButton.addListener(this,&ofApp::ringButtonPressed); + ringButton.addListener(this,&ofApp::ringButtonPressed); gui.setup("panel"); // most of the time you don't need a name but don't forget to call setup gui.add(filled.set("bFill", true)); @@ -15,13 +15,13 @@ void ofApp::setup(){ gui.add(center.set("center",ofVec2f(ofGetWidth()*.5,ofGetHeight()*.5),ofVec2f(0,0),ofVec2f(ofGetWidth(),ofGetHeight()))); gui.add(color.set("color",ofColor(100,100,140),ofColor(0,0),ofColor(255,255))); gui.add(circleResolution.set("circleRes", 5, 3, 90)); - gui.add(twoCircles.setup("twoCircles")); - gui.add(ringButton.setup("ring")); + gui.add(twoCircles.set("twoCircles", false)); + gui.add(ringButton.set("ring")); gui.add(screenSize.set("screenSize", "")); bHide = false; - ring.loadSound("ring.wav"); + ring.load("ring.wav"); } //-------------------------------------------------------------- diff --git a/examples/gui/guiFromParametersExample/src/ofApp.h b/examples/gui/guiFromParametersExample/src/ofApp.h index 11e9bee4749..3f3bc98ae07 100644 --- a/examples/gui/guiFromParametersExample/src/ofApp.h +++ b/examples/gui/guiFromParametersExample/src/ofApp.h @@ -34,8 +34,8 @@ class ofApp : public ofBaseApp{ ofParameter center; ofParameter circleResolution; ofParameter filled; - ofxButton twoCircles; - ofxButton ringButton; + ofParameter twoCircles; + ofParameter ringButton; ofParameter screenSize; ofxPanel gui; diff --git a/examples/gui/pagesExample/addons.make b/examples/gui/pagesExample/addons.make new file mode 100644 index 00000000000..f47512dc0e8 --- /dev/null +++ b/examples/gui/pagesExample/addons.make @@ -0,0 +1 @@ +ofxGui diff --git a/examples/gui/pagesExample/src/main.cpp b/examples/gui/pagesExample/src/main.cpp new file mode 100644 index 00000000000..43496c9ced8 --- /dev/null +++ b/examples/gui/pagesExample/src/main.cpp @@ -0,0 +1,14 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main(){ + + ofSetupOpenGL(1024, 768, 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 ofApp()); + +} diff --git a/examples/gui/pagesExample/src/ofApp.cpp b/examples/gui/pagesExample/src/ofApp.cpp new file mode 100644 index 00000000000..60251cbf9f3 --- /dev/null +++ b/examples/gui/pagesExample/src/ofApp.cpp @@ -0,0 +1,117 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup(){ + + ofSetLogLevel(OF_LOG_VERBOSE); + + setupPage1(); + setupPage2(); + setupPage3(); + + page.setup("single page"); + page.setSize(300, 300); + page.add(panel3); + + page1.setup("page 1"); + page1.add(panel1); + + page2.setup("page 2"); + page2.add(panel2); + + tabbed_pages.setup("tabbed pages", "", page.getShape().getRight() + 10); + tabbed_pages.setSize(500, 300); + tabbed_pages.add(page1); + tabbed_pages.add(page2); + +} + +//-------------------------------------------------------------- +void ofApp::exit(){ +} + +//-------------------------------------------------------------- +void ofApp::update(){ +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + + ofSetColor(255); + + page.draw(); + + tabbed_pages.draw(); + +} + +void ofApp::setupPage1(){ + panel1.setup("panel1"); + panel1.add(slider_param.set("slider", 0.5, 0, 1)); +} + +void ofApp::setupPage2(){ + panel2.setup("horizontal", "", 60, 10); + panel2.setShowHeader(false); + panel2.setExclusiveToggles(true); + panel2.add(toggle2_param.set("toggle2", false)); + panel2.add(toggle3_param.set("toggle3", false)); + panel2.add(toggle4_param.set("toggle4", false)); +} + +void ofApp::setupPage3(){ + panel3.setup("just some toggles", "", 60, 66); + panel3.setExclusiveToggles(true); + panel3.add(toggle2_param); + panel3.add(toggle3_param); + panel3.add(toggle4_param); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + switch(key){ + case 'f': { + ofToggleFullscreen(); + break; + } + + default: + break; + } + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(ofMouseEventArgs & args){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(ofMouseEventArgs & args){ +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/examples/gui/pagesExample/src/ofApp.h b/examples/gui/pagesExample/src/ofApp.h new file mode 100644 index 00000000000..2facb2b4555 --- /dev/null +++ b/examples/gui/pagesExample/src/ofApp.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ofMain.h" +#include "ofxGui.h" + +class ofApp : public ofBaseApp { + + public: + void setup(); + void update(); + void draw(); + + void exit(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(ofMouseEventArgs & args); + void mouseDragged(ofMouseEventArgs & args); + void mousePressed(ofMouseEventArgs & args); + void mouseReleased(ofMouseEventArgs & args); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + private: + + ofxGuiPage page; + + ofxTabbedPages tabbed_pages; + ofxGuiPage page1, page2; + + ofxPanel panel1, panel2, panel3; + + void setupPage1(); + void setupPage2(); + void setupPage3(); + + ofParameter slider_param; + ofParameter toggle2_param, toggle3_param, toggle4_param; + +}; + diff --git a/examples/ios/CoreLocationExample/src/main.mm b/examples/ios/CoreLocationExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/CoreLocationExample/src/main.mm +++ b/examples/ios/CoreLocationExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/CoreLocationExample/src/ofApp.h b/examples/ios/CoreLocationExample/src/ofApp.h index 908951ba7dd..85651549438 100644 --- a/examples/ios/CoreLocationExample/src/ofApp.h +++ b/examples/ios/CoreLocationExample/src/ofApp.h @@ -1,8 +1,7 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" +#include "ofxiOSCoreLocation.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/ImagePickerExample/src/main.mm b/examples/ios/ImagePickerExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/ImagePickerExample/src/main.mm +++ b/examples/ios/ImagePickerExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/ImagePickerExample/src/ofApp.h b/examples/ios/ImagePickerExample/src/ofApp.h index 17949c84ad2..9d576c3dbc6 100644 --- a/examples/ios/ImagePickerExample/src/ofApp.h +++ b/examples/ios/ImagePickerExample/src/ofApp.h @@ -1,8 +1,7 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" +#include "ofxiOSImagePicker.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/KeyboardExample/src/main.mm b/examples/ios/KeyboardExample/src/main.mm index 1c3912a69b7..56a59a3139f 100644 --- a/examples/ios/KeyboardExample/src/main.mm +++ b/examples/ios/KeyboardExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/KeyboardExample/src/ofApp.h b/examples/ios/KeyboardExample/src/ofApp.h index 20b7c799dfb..9cd96e80d10 100644 --- a/examples/ios/KeyboardExample/src/ofApp.h +++ b/examples/ios/KeyboardExample/src/ofApp.h @@ -1,8 +1,7 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" +#include "ofxiOSKeyboard.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/MapKitExample/src/main.mm b/examples/ios/MapKitExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/MapKitExample/src/main.mm +++ b/examples/ios/MapKitExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/MapKitExample/src/ofApp.h b/examples/ios/MapKitExample/src/ofApp.h index 48984409e59..3ccfa034106 100644 --- a/examples/ios/MapKitExample/src/ofApp.h +++ b/examples/ios/MapKitExample/src/ofApp.h @@ -1,7 +1,7 @@ #pragma once -#include "ofMain.h" -#include "ofxiOSExtras.h" +#include "ofxiOS.h" +#include "ofxiOSMapKit.h" class ofApp : public ofxiOSApp, ofxiOSMapKitListener{ diff --git a/examples/ios/MapKitExample/src/ofApp.mm b/examples/ios/MapKitExample/src/ofApp.mm index 6154ec5d7c0..ced4c1926a4 100644 --- a/examples/ios/MapKitExample/src/ofApp.mm +++ b/examples/ios/MapKitExample/src/ofApp.mm @@ -81,7 +81,7 @@ // draw black circle in middle of screen ofSetColor(0, 0, 0); ofNoFill(); - ofCircle(ofGetWidth()/2, ofGetHeight()/2, 10); + ofDrawCircle(ofGetWidth()/2, ofGetHeight()/2, 10); ofFill(); diff --git a/examples/ios/PrimitivesExample/src/main.mm b/examples/ios/PrimitivesExample/src/main.mm index dd9880f6e02..9dd4abda322 100644 --- a/examples/ios/PrimitivesExample/src/main.mm +++ b/examples/ios/PrimitivesExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/PrimitivesExample/src/ofApp.h b/examples/ios/PrimitivesExample/src/ofApp.h index e036bd504b4..7c452ea9d70 100644 --- a/examples/ios/PrimitivesExample/src/ofApp.h +++ b/examples/ios/PrimitivesExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/TouchAndAccelExample/src/Ball.h b/examples/ios/TouchAndAccelExample/src/Ball.h index 241b902edb3..90fd3f9773b 100644 --- a/examples/ios/TouchAndAccelExample/src/Ball.h +++ b/examples/ios/TouchAndAccelExample/src/Ball.h @@ -63,10 +63,10 @@ class Ball{ void draw() { if( bDragged ){ ofSetColor(touchCol); - ofCircle(pos.x, pos.y, 80); + ofDrawCircle(pos.x, pos.y, 80); }else{ ofSetColor(col); - ofCircle(pos.x, pos.y, RADIUS); + ofDrawCircle(pos.x, pos.y, RADIUS); } } diff --git a/examples/ios/TouchAndAccelExample/src/main.mm b/examples/ios/TouchAndAccelExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/TouchAndAccelExample/src/main.mm +++ b/examples/ios/TouchAndAccelExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/TouchAndAccelExample/src/ofApp.h b/examples/ios/TouchAndAccelExample/src/ofApp.h index 7c6d078298a..0965721138b 100644 --- a/examples/ios/TouchAndAccelExample/src/ofApp.h +++ b/examples/ios/TouchAndAccelExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #include "Ball.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/TouchAndAccelExample/src/ofApp.mm b/examples/ios/TouchAndAccelExample/src/ofApp.mm index 9b6b94e01c0..4911c99319b 100644 --- a/examples/ios/TouchAndAccelExample/src/ofApp.mm +++ b/examples/ios/TouchAndAccelExample/src/ofApp.mm @@ -59,27 +59,27 @@ //-------------------------------------------------------------- void ofApp::touchDown(ofTouchEventArgs & touch){ - ofLog(OF_LOG_VERBOSE, "touch %d down at (%d,%d)", touch.id, touch.x, touch.y); + ofLog(OF_LOG_VERBOSE, "touch %d down at (%i,%i)", touch.id, (int)touch.x, (int)touch.y); balls[touch.id].moveTo(touch.x, touch.y); balls[touch.id].bDragged = true; } //-------------------------------------------------------------- void ofApp::touchMoved(ofTouchEventArgs & touch){ - ofLog(OF_LOG_VERBOSE, "touch %d moved at (%d,%d)", touch.id, touch.x, touch.y); + ofLog(OF_LOG_VERBOSE, "touch %d moved at (%i,%i)", touch.id, (int)touch.x, (int)touch.y); balls[touch.id].moveTo(touch.x, touch.y); balls[touch.id].bDragged = true; } //-------------------------------------------------------------- void ofApp::touchUp(ofTouchEventArgs & touch){ - ofLog(OF_LOG_VERBOSE, "touch %d up at (%d,%d)", touch.id, touch.x, touch.y); + ofLog(OF_LOG_VERBOSE, "touch %d up at (%i,%i)", touch.id, (int)touch.x, (int)touch.y); balls[touch.id].bDragged = false; } //-------------------------------------------------------------- void ofApp::touchDoubleTap(ofTouchEventArgs & touch){ - ofLog(OF_LOG_VERBOSE, "touch %d double tap at (%d,%d)", touch.id, touch.x, touch.y); + ofLog(OF_LOG_VERBOSE, "touch %d double tap at (%i,%i)", touch.id, (int)touch.x, (int)touch.y); } //-------------------------------------------------------------- diff --git a/examples/ios/advancedEventsExample/src/eventsObject.h b/examples/ios/advancedEventsExample/src/eventsObject.h index 988ff01e9e7..37ed29ec325 100644 --- a/examples/ios/advancedEventsExample/src/eventsObject.h +++ b/examples/ios/advancedEventsExample/src/eventsObject.h @@ -1,4 +1,5 @@ -#include "ofMain.h" +#pragma once + #include "ofEvents.h" class eventsObject{ diff --git a/examples/ios/advancedEventsExample/src/main.mm b/examples/ios/advancedEventsExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/advancedEventsExample/src/main.mm +++ b/examples/ios/advancedEventsExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/advancedEventsExample/src/ofApp.h b/examples/ios/advancedEventsExample/src/ofApp.h index f0180d7cdc6..19a0ee3a247 100644 --- a/examples/ios/advancedEventsExample/src/ofApp.h +++ b/examples/ios/advancedEventsExample/src/ofApp.h @@ -1,9 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" - #include "eventsObject.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/advancedGraphics/src/main.mm b/examples/ios/advancedGraphics/src/main.mm index 205c8758270..e829193b20f 100644 --- a/examples/ios/advancedGraphics/src/main.mm +++ b/examples/ios/advancedGraphics/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/advancedGraphics/src/ofApp.h b/examples/ios/advancedGraphics/src/ofApp.h index 591de47b6ef..cf1c8fb345f 100644 --- a/examples/ios/advancedGraphics/src/ofApp.h +++ b/examples/ios/advancedGraphics/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/advancedGraphics/src/ofApp.mm b/examples/ios/advancedGraphics/src/ofApp.mm index ce51e2bcd11..d90c4de7679 100644 --- a/examples/ios/advancedGraphics/src/ofApp.mm +++ b/examples/ios/advancedGraphics/src/ofApp.mm @@ -122,15 +122,15 @@ //draw a red circle ofSetColor(255,0, 0); - ofCircle(-50, -25, 100); + ofDrawCircle(-50, -25, 100); //draw a green circle ofSetColor(0,255, 0); - ofCircle(50, -25, 100); + ofDrawCircle(50, -25, 100); //draw a blue circle ofSetColor(0, 0, 255); - ofCircle(0, 57, 100); + ofDrawCircle(0, 57, 100); ofPopMatrix(); diff --git a/examples/ios/assimpExample/src/main.mm b/examples/ios/assimpExample/src/main.mm index 205c8758270..e829193b20f 100644 --- a/examples/ios/assimpExample/src/main.mm +++ b/examples/ios/assimpExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/assimpExample/src/ofApp.h b/examples/ios/assimpExample/src/ofApp.h index 9b399037058..13c064ebb23 100644 --- a/examples/ios/assimpExample/src/ofApp.h +++ b/examples/ios/assimpExample/src/ofApp.h @@ -1,12 +1,7 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" -#include "ofMain.h" - #include "ofxAssimpModelLoader.h" -#include "ofVboMesh.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/audioInputExample/src/main.mm b/examples/ios/audioInputExample/src/main.mm index 16159c9471c..b7fa9f6114a 100644 --- a/examples/ios/audioInputExample/src/main.mm +++ b/examples/ios/audioInputExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/audioInputExample/src/ofApp.h b/examples/ios/audioInputExample/src/ofApp.h index 3d8b9acfb01..f96063a9c27 100644 --- a/examples/ios/audioInputExample/src/ofApp.h +++ b/examples/ios/audioInputExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/audioInputExample/src/ofApp.mm b/examples/ios/audioInputExample/src/ofApp.mm index b4b27396cb9..4f9cc71ea59 100644 --- a/examples/ios/audioInputExample/src/ofApp.mm +++ b/examples/ios/audioInputExample/src/ofApp.mm @@ -1,6 +1,4 @@ -#import - #include "ofApp.h" // IMPORTANT!!! if your sound doesn't work in the simulator diff --git a/examples/ios/audioOutputExample/src/main.mm b/examples/ios/audioOutputExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/audioOutputExample/src/main.mm +++ b/examples/ios/audioOutputExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/audioOutputExample/src/ofApp.h b/examples/ios/audioOutputExample/src/ofApp.h index ab3dc7106f8..51af88348a2 100644 --- a/examples/ios/audioOutputExample/src/ofApp.h +++ b/examples/ios/audioOutputExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/dirListExample/src/main.mm b/examples/ios/dirListExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/dirListExample/src/main.mm +++ b/examples/ios/dirListExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/dirListExample/src/ofApp.h b/examples/ios/dirListExample/src/ofApp.h index 17394d47036..8200ccd5568 100644 --- a/examples/ios/dirListExample/src/ofApp.h +++ b/examples/ios/dirListExample/src/ofApp.h @@ -1,9 +1,6 @@ -#ifndef _TEST_APP -#define _TEST_APP +#pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp { @@ -34,6 +31,3 @@ class ofApp : public ofxiOSApp { int currentImage; }; - -#endif - diff --git a/examples/ios/dirListExample/src/ofApp.mm b/examples/ios/dirListExample/src/ofApp.mm index 5be2f0437d5..89edcc19707 100644 --- a/examples/ios/dirListExample/src/ofApp.mm +++ b/examples/ios/dirListExample/src/ofApp.mm @@ -29,13 +29,13 @@ if (nImages > 0){ ofSetHexColor(0xffffff); - images[currentImage].draw(210, textSpace, images[currentImage].width/1.5, images[currentImage].height/1.5); + images[currentImage].draw(210, textSpace, images[currentImage].getWidth()/1.5, images[currentImage].getHeight()/1.5); ofSetHexColor(0x999999); string pathInfo = "current path is: "; pathInfo += DIR.getPath(currentImage); ofDrawBitmapString(pathInfo, 20, 20); - ofDrawBitmapString("touch screen to advance image \n\nmany thanks to hikaru furuhashi\nfor the OFs!" , 210, images[currentImage].height/1.5 + 20 + textSpace); + ofDrawBitmapString("touch screen to advance image \n\nmany thanks to hikaru furuhashi\nfor the OFs!" , 210, images[currentImage].getHeight()/1.5 + 20 + textSpace); } ofSetHexColor(0x000000); diff --git a/examples/ios/emptyExample/src/main.mm b/examples/ios/emptyExample/src/main.mm index 8dbc6f6053b..35371845679 100644 --- a/examples/ios/emptyExample/src/main.mm +++ b/examples/ios/emptyExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/emptyExample/src/ofApp.h b/examples/ios/emptyExample/src/ofApp.h index f6248f2b9e8..60509cff2e0 100644 --- a/examples/ios/emptyExample/src/ofApp.h +++ b/examples/ios/emptyExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/eventsExample/src/main.mm b/examples/ios/eventsExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/eventsExample/src/main.mm +++ b/examples/ios/eventsExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/eventsExample/src/ofApp.h b/examples/ios/eventsExample/src/ofApp.h index 10757697f68..0aaa51408f1 100644 --- a/examples/ios/eventsExample/src/ofApp.h +++ b/examples/ios/eventsExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/fontShapesExample/src/main.mm b/examples/ios/fontShapesExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/fontShapesExample/src/main.mm +++ b/examples/ios/fontShapesExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/fontShapesExample/src/ofApp.h b/examples/ios/fontShapesExample/src/ofApp.h index 0534eca95f9..22fdef0f8d8 100644 --- a/examples/ios/fontShapesExample/src/ofApp.h +++ b/examples/ios/fontShapesExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/fontsExample/src/main.mm b/examples/ios/fontsExample/src/main.mm index ec78681aaf2..931b4775fa0 100644 --- a/examples/ios/fontsExample/src/main.mm +++ b/examples/ios/fontsExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/fontsExample/src/ofApp.h b/examples/ios/fontsExample/src/ofApp.h index 9d1197ea5d6..3d305322964 100644 --- a/examples/ios/fontsExample/src/ofApp.h +++ b/examples/ios/fontsExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/graphicsExample/src/main.mm b/examples/ios/graphicsExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/graphicsExample/src/main.mm +++ b/examples/ios/graphicsExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/graphicsExample/src/ofApp.h b/examples/ios/graphicsExample/src/ofApp.h index c82a783d4a5..6c261ac53d9 100644 --- a/examples/ios/graphicsExample/src/ofApp.h +++ b/examples/ios/graphicsExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/graphicsExample/src/ofApp.mm b/examples/ios/graphicsExample/src/ofApp.mm index 237c38cbfe8..459dfb4ce48 100644 --- a/examples/ios/graphicsExample/src/ofApp.mm +++ b/examples/ios/graphicsExample/src/ofApp.mm @@ -26,12 +26,12 @@ ofSetColor(255,130,0); float radius = 50 + 10 * sin(counter); ofFill(); // draw "filled shapes" - ofCircle(100,400,radius); + ofDrawCircle(100,400,radius); // now just an outline ofNoFill(); ofSetHexColor(0xCCCCCC); - ofCircle(100,400,80); + ofDrawCircle(100,400,80); // use the bitMap type // note, this can be slow on some graphics cards diff --git a/examples/ios/iPhoneGuiExample/src/main.mm b/examples/ios/iPhoneGuiExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/iPhoneGuiExample/src/main.mm +++ b/examples/ios/iPhoneGuiExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/iPhoneGuiExample/src/ofApp.h b/examples/ios/iPhoneGuiExample/src/ofApp.h index 18dfe385508..49e7522325e 100644 --- a/examples/ios/iPhoneGuiExample/src/ofApp.h +++ b/examples/ios/iPhoneGuiExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" // Note: // If the app is not compiling, try removing the MyGuiView.xib reference diff --git a/examples/ios/imageLoaderExample/src/main.mm b/examples/ios/imageLoaderExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/imageLoaderExample/src/main.mm +++ b/examples/ios/imageLoaderExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/imageLoaderExample/src/ofApp.h b/examples/ios/imageLoaderExample/src/ofApp.h index 8aaaf3764d7..ef3ef8fb12c 100644 --- a/examples/ios/imageLoaderExample/src/ofApp.h +++ b/examples/ios/imageLoaderExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/imageLoaderExample/src/ofApp.mm b/examples/ios/imageLoaderExample/src/ofApp.mm index 6485b57679b..6539e58b00d 100644 --- a/examples/ios/imageLoaderExample/src/ofApp.mm +++ b/examples/ios/imageLoaderExample/src/ofApp.mm @@ -8,7 +8,7 @@ gears.load("images/gears.gif"); tdf.load("images/tdf_1972_poster.jpg"); tdfSmall.load("images/tdf_1972_poster.jpg"); - tdfSmall.resize(tdf.width / 4, tdf.height / 4); + tdfSmall.resize(tdf.getWidth() / 4, tdf.getHeight() / 4); tdfSmall.setImageType(OF_IMAGE_GRAYSCALE); transparency.load("images/transparency.png"); bikeIcon.load("images/bike_icon.png"); @@ -43,14 +43,14 @@ // getting the pixels out of an image, // and then use the values to draw circles - unsigned char * pixels = bikeIcon.getPixels(); - int w = bikeIcon.width; - int h = bikeIcon.height; + unsigned char * pixels = bikeIcon.getPixels().getData(); + int w = bikeIcon.getWidth(); + int h = bikeIcon.getHeight(); for (int i = 0; i < w; i++){ for (int j = 0; j < h; j++){ int value = pixels[j * w + i]; float pct = 1 - (value / 255.0f); - ofCircle(i*10,500 + j*10,1 + 5*pct); + ofDrawCircle(i*10,500 + j*10,1 + 5*pct); } } diff --git a/examples/ios/iosCustomSizeExample/src/main.mm b/examples/ios/iosCustomSizeExample/src/main.mm index a21beaa1dd3..a90dbf77836 100644 --- a/examples/ios/iosCustomSizeExample/src/main.mm +++ b/examples/ios/iosCustomSizeExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main(){ @@ -15,10 +13,9 @@ int main(){ settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated. settings.glesVersion = OFXIOS_RENDERER_ES1; // type of renderer to use, ES1, ES2, etc. - shared_ptr windowBase = ofCreateWindow(settings); - ofAppiOSWindow* window = static_cast(windowBase.get()); + ofAppiOSWindow * window = (ofAppiOSWindow *)(ofCreateWindow(settings).get()); - bool bUseNative = false; + bool bUseNative = true; if (bUseNative){ /** * diff --git a/examples/ios/iosCustomSizeExample/src/ofApp.h b/examples/ios/iosCustomSizeExample/src/ofApp.h index f6248f2b9e8..60509cff2e0 100644 --- a/examples/ios/iosCustomSizeExample/src/ofApp.h +++ b/examples/ios/iosCustomSizeExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/iosES2ShaderExample/src/main.mm b/examples/ios/iosES2ShaderExample/src/main.mm index 548057ba2ff..c964e3a17d4 100644 --- a/examples/ios/iosES2ShaderExample/src/main.mm +++ b/examples/ios/iosES2ShaderExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/iosES2ShaderExample/src/ofApp.h b/examples/ios/iosES2ShaderExample/src/ofApp.h index 72d3a5fcefd..e0b533e0f9a 100644 --- a/examples/ios/iosES2ShaderExample/src/ofApp.h +++ b/examples/ios/iosES2ShaderExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/iosExternalDisplayExample/src/main.mm b/examples/ios/iosExternalDisplayExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/iosExternalDisplayExample/src/main.mm +++ b/examples/ios/iosExternalDisplayExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/iosExternalDisplayExample/src/ofApp.h b/examples/ios/iosExternalDisplayExample/src/ofApp.h index 7a514cbc09d..55487e96f3b 100644 --- a/examples/ios/iosExternalDisplayExample/src/ofApp.h +++ b/examples/ios/iosExternalDisplayExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #include "ofxiOSExternalDisplay.h" class ofApp : public ofxiOSApp, public ofxiOSExternalDisplay { diff --git a/examples/ios/iosExternalDisplayExample/src/ofApp.mm b/examples/ios/iosExternalDisplayExample/src/ofApp.mm index 62c69755339..944a2f36cca 100644 --- a/examples/ios/iosExternalDisplayExample/src/ofApp.mm +++ b/examples/ios/iosExternalDisplayExample/src/ofApp.mm @@ -285,6 +285,7 @@ //-------------------------------------------------------------- void ofApp::externalDisplayConnected(){ + [ofxiOSGetAppDelegate() createExternalWindowWithPreferredMode]; // create external window as soon as external screen is connected to prevent unwanted mirroring. ofLogVerbose("external display connected."); presentExternalDisplayPopup(); } diff --git a/tutorials/shader/02_simpleVertexDisplacement/addons.make b/examples/ios/iosNativeARCExample/addons.make similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/addons.make rename to examples/ios/iosNativeARCExample/addons.make diff --git a/examples/ios/iosNativeARCExample/bin/data/fonts/frabk.ttf b/examples/ios/iosNativeARCExample/bin/data/fonts/frabk.ttf new file mode 100644 index 00000000000..21c4ecfc553 Binary files /dev/null and b/examples/ios/iosNativeARCExample/bin/data/fonts/frabk.ttf differ diff --git a/examples/ios/iosNativeARCExample/bin/data/fonts/mono0755.ttf b/examples/ios/iosNativeARCExample/bin/data/fonts/mono0755.ttf new file mode 100644 index 00000000000..ffee24f3670 Binary files /dev/null and b/examples/ios/iosNativeARCExample/bin/data/fonts/mono0755.ttf differ diff --git a/examples/ios/iosNativeARCExample/bin/data/images/dive.jpg b/examples/ios/iosNativeARCExample/bin/data/images/dive.jpg new file mode 100644 index 00000000000..a47a3b1f277 Binary files /dev/null and b/examples/ios/iosNativeARCExample/bin/data/images/dive.jpg differ diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.h b/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.h new file mode 100644 index 00000000000..31743cad7ff --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.h @@ -0,0 +1,10 @@ +// +// CustomAppViewController.h +// Created by lukasz karluk on 8/02/12. +// + +#import "ofxiOSViewController.h" + +@interface CircleAppViewController : ofxiOSViewController + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.mm b/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.mm new file mode 100644 index 00000000000..aaa782cf1eb --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/CircleAppViewController.mm @@ -0,0 +1,23 @@ +// +// CustomAppViewController.m +// Created by lukasz karluk on 8/02/12. +// + +#import "CircleAppViewController.h" +#import "ofxiOSExtras.h" +#import "ofAppiOSWindow.h" + +@implementation CircleAppViewController + +- (id) initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { + + ofxiOSGetOFWindow()->setOrientation( OF_ORIENTATION_DEFAULT ); //-- default portait orientation. + + return self = [super initWithFrame:frame app:app]; +} + +- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return NO; +} + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.h b/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.h new file mode 100644 index 00000000000..4f5e154a301 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.h @@ -0,0 +1,10 @@ +// +// CustomAppViewController.h +// Created by lukasz karluk on 8/02/12. +// + +#import "ofxiOSViewController.h" + +@interface ImageAppViewController : ofxiOSViewController + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.mm b/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.mm new file mode 100644 index 00000000000..8450a471ce8 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/ImageAppViewController.mm @@ -0,0 +1,23 @@ +// +// CustomAppViewController.m +// Created by lukasz karluk on 8/02/12. +// + +#import "ImageAppViewController.h" +#import "ofxiOSExtras.h" +#import "ofAppiOSWindow.h" + +@implementation ImageAppViewController + +- (id) initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { + + ofxiOSGetOFWindow()->setOrientation( OF_ORIENTATION_DEFAULT ); //-- default portait orientation. + + return self = [super initWithFrame:frame app:app]; +} + +- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return NO; +} + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.h b/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.h new file mode 100644 index 00000000000..8de3369476c --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.h @@ -0,0 +1,10 @@ +// +// CustomAppViewController.h +// Created by lukasz karluk on 8/02/12. +// + +#import "ofxiOSViewController.h" + +@interface SquareAppViewController : ofxiOSViewController + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.mm b/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.mm new file mode 100644 index 00000000000..4620a1e71a7 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/SquareAppViewController.mm @@ -0,0 +1,23 @@ +// +// CustomAppViewController.m +// Created by lukasz karluk on 8/02/12. +// + +#import "SquareAppViewController.h" +#import "ofxiOSExtras.h" +#import "ofAppiOSWindow.h" + +@implementation SquareAppViewController + +- (id) initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { + + ofxiOSGetOFWindow()->setOrientation( OF_ORIENTATION_DEFAULT ); //-- default portait orientation. + + return self = [super initWithFrame:frame app:app]; +} + +- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return NO; +} + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.h b/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.h new file mode 100644 index 00000000000..e2f45110250 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.h @@ -0,0 +1,10 @@ +// +// CustomAppViewController.h +// Created by lukasz karluk on 8/02/12. +// + +#import "ofxiOSViewController.h" + +@interface TriangleAppViewController : ofxiOSViewController + +@end diff --git a/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.mm b/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.mm new file mode 100644 index 00000000000..3ce2f172ce0 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/AppViewControllers/TriangleAppViewController.mm @@ -0,0 +1,23 @@ +// +// CustomAppViewController.m +// Created by lukasz karluk on 8/02/12. +// + +#import "TriangleAppViewController.h" +#import "ofxiOSExtras.h" +#import "ofAppiOSWindow.h" + +@implementation TriangleAppViewController + +- (id) initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { + + ofxiOSGetOFWindow()->setOrientation( OF_ORIENTATION_DEFAULT ); //-- default portait orientation. + + return self = [super initWithFrame:frame app:app]; +} + +- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return NO; +} + +@end diff --git a/examples/ios/iosNativeARCExample/src/Apps/CircleApp.h b/examples/ios/iosNativeARCExample/src/Apps/CircleApp.h new file mode 100644 index 00000000000..573e0349554 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/CircleApp.h @@ -0,0 +1,32 @@ +#pragma once + +#include "ofxiOS.h" + +class CircleApp : public ofxiOSApp { + +public: + + CircleApp (); + ~CircleApp (); + + void setup(); + void update(); + void draw(); + void exit(); + + void touchDown(ofTouchEventArgs &touch); + void touchMoved(ofTouchEventArgs &touch); + void touchUp(ofTouchEventArgs &touch); + void touchDoubleTap(ofTouchEventArgs &touch); + void touchCancelled(ofTouchEventArgs &touch); + + void lostFocus(); + void gotFocus(); + void gotMemoryWarning(); + void deviceOrientationChanged(int newOrientation); + + ofTrueTypeFont font; + +}; + + diff --git a/examples/ios/iosNativeARCExample/src/Apps/CircleApp.mm b/examples/ios/iosNativeARCExample/src/Apps/CircleApp.mm new file mode 100644 index 00000000000..7d301e05f75 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/CircleApp.mm @@ -0,0 +1,117 @@ +#include "CircleApp.h" + +//-------------------------------------------------------------- +CircleApp :: CircleApp () { + cout << "creating CircleApp" << endl; + //add this to listen to orientation events etc. + ofxiOSAlerts.addListener(this); +} + +//-------------------------------------------------------------- +CircleApp :: ~CircleApp () { + cout << "destroying CircleApp" << endl; + //add this to listen to orientation events etc. + ofxiOSAlerts.removeListener(this); +} + +//-------------------------------------------------------------- +void CircleApp::setup() { + ofBackground(127); + + int fontSize = 8; + if (ofxiOSGetOFWindow()-> isRetinaSupportedOnDevice()) + fontSize *= 2; + + font.load("fonts/frabk.ttf", fontSize); + +} + +//-------------------------------------------------------------- +void CircleApp::update(){ + +} + +//-------------------------------------------------------------- +void CircleApp::draw() { + int x = ofGetWidth() * 0.5; + int y = ofGetHeight() * 0.5; + int r = MIN(ofGetWidth(), ofGetHeight()) * 0.3; + int p = 0; + + ofSetColor(ofColor::red); + ofDrawCircle(x, y, r); + + x = ofGetWidth() * 0.2; + y = ofGetHeight() * 0.11; + p = ofGetHeight() * 0.035; + + ofSetColor(ofColor::white); + font.drawString("frame num = " + ofToString(ofGetFrameNum() ), x, y+=p); + font.drawString("frame rate = " + ofToString(ofGetFrameRate() ), x, y+=p); + font.drawString("screen width = " + ofToString(ofGetWidth() ), x, y+=p); + font.drawString("screen height = " + ofToString(ofGetHeight() ), x, y+=p); +} + +//-------------------------------------------------------------- +void CircleApp::exit() { + // +} + +//-------------------------------------------------------------- +void CircleApp::touchDown(ofTouchEventArgs &touch){ + int orient = ofGetOrientation(); + if(orient<4){ + orient++; + }else{ + orient = 1; + } + ofSetOrientation((ofOrientation)orient); +} + +//-------------------------------------------------------------- +void CircleApp::touchMoved(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void CircleApp::touchUp(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void CircleApp::touchDoubleTap(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void CircleApp::lostFocus(){ + +} + +//-------------------------------------------------------------- +void CircleApp::gotFocus(){ + +} + +//-------------------------------------------------------------- +void CircleApp::gotMemoryWarning(){ + +} + +//-------------------------------------------------------------- +void CircleApp::deviceOrientationChanged(int newOrientation){ + if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)){ + // code for landscape orientation + cout<<"CircleApp::deviceOrientationChanged to landscape"<isRetinaSupportedOnDevice()) + fontSize *= 2; + + font.load("fonts/frabk.ttf", fontSize); + + image.load("images/dive.jpg"); +} + +//-------------------------------------------------------------- +void ImageApp::update(){ + +} + +//-------------------------------------------------------------- +void ImageApp::draw() { + int x = (ofGetWidth() - image.getWidth()) * 0.5; + int y = (ofGetHeight() - image.getHeight()) * 0.5; + int p = 0; + + ofSetColor(ofColor::white); + image.draw(x, y); + + x = ofGetWidth() * 0.2; + y = ofGetHeight() * 0.11; + p = ofGetHeight() * 0.035; + + ofSetColor(ofColor::white); + font.drawString("frame num = " + ofToString( ofGetFrameNum() ), x, y+=p); + font.drawString("frame rate = " + ofToString( ofGetFrameRate() ), x, y+=p); + font.drawString("screen width = " + ofToString( ofGetWidth() ), x, y+=p); + font.drawString("screen height = " + ofToString( ofGetHeight() ), x, y+=p); +} + +//-------------------------------------------------------------- +void ImageApp::exit() { + // +} + +//-------------------------------------------------------------- +void ImageApp::touchDown(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void ImageApp::touchMoved(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void ImageApp::touchUp(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void ImageApp::touchDoubleTap(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void ImageApp::lostFocus(){ + +} + +//-------------------------------------------------------------- +void ImageApp::gotFocus(){ + +} + +//-------------------------------------------------------------- +void ImageApp::gotMemoryWarning(){ + +} + +//-------------------------------------------------------------- +void ImageApp::deviceOrientationChanged(int newOrientation){ + +} + + +//-------------------------------------------------------------- +void ImageApp::touchCancelled(ofTouchEventArgs& args){ + +} + diff --git a/examples/ios/iosNativeARCExample/src/Apps/SquareApp.h b/examples/ios/iosNativeARCExample/src/Apps/SquareApp.h new file mode 100644 index 00000000000..e371d255c66 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/SquareApp.h @@ -0,0 +1,31 @@ +#pragma once + +#include "ofxiOS.h" + +class SquareApp : public ofxiOSApp { + +public: + + SquareApp (); + ~SquareApp (); + + void setup(); + void update(); + void draw(); + void exit(); + + void touchDown(ofTouchEventArgs &touch); + void touchMoved(ofTouchEventArgs &touch); + void touchUp(ofTouchEventArgs &touch); + void touchDoubleTap(ofTouchEventArgs &touch); + void touchCancelled(ofTouchEventArgs &touch); + + void lostFocus(); + void gotFocus(); + void gotMemoryWarning(); + void deviceOrientationChanged(int newOrientation); + + ofTrueTypeFont font; +}; + + diff --git a/examples/ios/iosNativeARCExample/src/Apps/SquareApp.mm b/examples/ios/iosNativeARCExample/src/Apps/SquareApp.mm new file mode 100644 index 00000000000..d71094a7294 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/SquareApp.mm @@ -0,0 +1,103 @@ +#include "SquareApp.h" + +//-------------------------------------------------------------- +SquareApp :: SquareApp () { + cout << "creating SquareApp" << endl; +} + +//-------------------------------------------------------------- +SquareApp :: ~SquareApp () { + cout << "destroying SquareApp" << endl; +} + +//-------------------------------------------------------------- +void SquareApp::setup() { + ofBackground(127); + + int fontSize = 8; + if (ofxiOSGetOFWindow()->isRetinaSupportedOnDevice()) + fontSize *= 2; + + font.load("fonts/frabk.ttf", fontSize); +} + +//-------------------------------------------------------------- +void SquareApp::update(){ + +} + +//-------------------------------------------------------------- +void SquareApp::draw() { + ofEnableAlphaBlending(); + + int w = MIN(ofGetWidth(), ofGetHeight()) * 0.6; + int h = w; + int x = (ofGetWidth() - w) * 0.5; + int y = (ofGetHeight() - h) * 0.5; + int p = 0; + + ofSetColor(ofColor::red); + ofDrawRectangle(x, y, w, h); + + x = ofGetWidth() * 0.2; + y = ofGetHeight() * 0.11; + p = ofGetHeight() * 0.035; + + ofSetColor(ofColor::white); + font.drawString("frame num = " + ofToString( ofGetFrameNum() ), x, y+=p); + font.drawString("frame rate = " + ofToString( ofGetFrameRate() ), x, y+=p); + font.drawString("screen width = " + ofToString( ofGetWidth() ), x, y+=p); + font.drawString("screen height = " + ofToString( ofGetHeight() ), x, y+=p); +} + +//-------------------------------------------------------------- +void SquareApp::exit() { + // +} + +//-------------------------------------------------------------- +void SquareApp::touchDown(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void SquareApp::touchMoved(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void SquareApp::touchUp(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void SquareApp::touchDoubleTap(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void SquareApp::lostFocus(){ + +} + +//-------------------------------------------------------------- +void SquareApp::gotFocus(){ + +} + +//-------------------------------------------------------------- +void SquareApp::gotMemoryWarning(){ + +} + +//-------------------------------------------------------------- +void SquareApp::deviceOrientationChanged(int newOrientation){ + +} + + +//-------------------------------------------------------------- +void SquareApp::touchCancelled(ofTouchEventArgs& args){ + +} + diff --git a/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.h b/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.h new file mode 100644 index 00000000000..086e416b235 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.h @@ -0,0 +1,31 @@ +#pragma once + +#include "ofxiOS.h" + +class TriangleApp : public ofxiOSApp { + +public: + + TriangleApp (); + ~TriangleApp (); + + void setup(); + void update(); + void draw(); + void exit(); + + void touchDown(ofTouchEventArgs &touch); + void touchMoved(ofTouchEventArgs &touch); + void touchUp(ofTouchEventArgs &touch); + void touchDoubleTap(ofTouchEventArgs &touch); + void touchCancelled(ofTouchEventArgs &touch); + + void lostFocus(); + void gotFocus(); + void gotMemoryWarning(); + void deviceOrientationChanged(int newOrientation); + + ofTrueTypeFont font; +}; + + diff --git a/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.mm b/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.mm new file mode 100644 index 00000000000..646dc61e4f9 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/Apps/TriangleApp.mm @@ -0,0 +1,101 @@ +#include "TriangleApp.h" + +//-------------------------------------------------------------- +TriangleApp :: TriangleApp () { + cout << "creating TriangleApp" << endl; +} + +//-------------------------------------------------------------- +TriangleApp :: ~TriangleApp () { + cout << "destroying TriangleApp" << endl; +} + +//-------------------------------------------------------------- +void TriangleApp::setup() { + ofBackground(127); + + int fontSize = 8; + if (ofxiOSGetOFWindow()->isRetinaSupportedOnDevice()) + fontSize *= 2; + + font.load("fonts/frabk.ttf", fontSize); +} + +//-------------------------------------------------------------- +void TriangleApp::update(){ + +} + +//-------------------------------------------------------------- +void TriangleApp::draw() { + int a = MIN(ofGetWidth(), ofGetHeight()) * 0.3; + int b = sqrt( a * a + a * a ); + int x = ofGetWidth() * 0.5; + int y = ofGetHeight() * 0.5; + int p = 0; + + ofSetColor(ofColor::red); + ofDrawTriangle(x, y - a, x + b, y + b, x - b, y + b); + + x = ofGetWidth() * 0.2; + y = ofGetHeight() * 0.11; + p = ofGetHeight() * 0.035; + + ofSetColor(ofColor::white); + font.drawString("frame num = " + ofToString( ofGetFrameNum() ), x, y+=p); + font.drawString("frame rate = " + ofToString( ofGetFrameRate() ), x, y+=p); + font.drawString("screen width = " + ofToString( ofGetWidth() ), x, y+=p); + font.drawString("screen height = " + ofToString( ofGetHeight() ), x, y+=p); +} + +//-------------------------------------------------------------- +void TriangleApp::exit() { + // +} + +//-------------------------------------------------------------- +void TriangleApp::touchDown(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void TriangleApp::touchMoved(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void TriangleApp::touchUp(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void TriangleApp::touchDoubleTap(ofTouchEventArgs &touch){ + +} + +//-------------------------------------------------------------- +void TriangleApp::lostFocus(){ + +} + +//-------------------------------------------------------------- +void TriangleApp::gotFocus(){ + +} + +//-------------------------------------------------------------- +void TriangleApp::gotMemoryWarning(){ + +} + +//-------------------------------------------------------------- +void TriangleApp::deviceOrientationChanged(int newOrientation){ + +} + + +//-------------------------------------------------------------- +void TriangleApp::touchCancelled(ofTouchEventArgs& args){ + +} + diff --git a/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.h b/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.h new file mode 100644 index 00000000000..be38a852dd7 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.h @@ -0,0 +1,14 @@ +// +// MyAppDelegate.h +// Created by lukasz karluk on 12/12/11. +// + +#import "ofxiOSAppDelegate.h" + +@interface MyAppDelegate : ofxiOSAppDelegate { + // +} + +@property (nonatomic, retain) UINavigationController* navigationController; + +@end diff --git a/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.mm b/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.mm new file mode 100644 index 00000000000..a89ddf836b1 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/UI/MyAppDelegate.mm @@ -0,0 +1,45 @@ +// +// MyAppDelegate.m +// Created by lukasz karluk on 12/12/11. +// + +#import "MyAppDelegate.h" +#import "MyAppViewController.h" + +@implementation MyAppDelegate + +@synthesize navigationController; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + [super applicationDidFinishLaunching:application]; + + /** + * + * Below is where you insert your own UIViewController and take control of the App. + * In this example im creating a UINavigationController and adding it as my RootViewController to the window. (this is essential) + * UINavigationController is handy for managing the navigation between multiple view controllers, more info here, + * http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html + * + * I then push oFAppViewController onto the UINavigationController stack. + * oFAppViewController is a custom view controller with a 3 button menu. + * + **/ + + self.navigationController = [[UINavigationController alloc] init]; + [self.window setRootViewController:self.navigationController]; + + [self.navigationController pushViewController:[[MyAppViewController alloc] init] animated:YES]; + + //--- style the UINavigationController + self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent; + self.navigationController.navigationBar.topItem.title = @"Home"; + + return YES; +} + +- (void) dealloc { + self.navigationController = nil; +} + +@end diff --git a/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.h b/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.h new file mode 100644 index 00000000000..df0ba656f6c --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.h @@ -0,0 +1,10 @@ +// +// MyAppViewController.h +// Created by lukasz karluk on 12/12/11. +// + +#import + +@interface MyAppViewController : UIViewController + +@end diff --git a/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.mm b/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.mm new file mode 100644 index 00000000000..40c184b8eb0 --- /dev/null +++ b/examples/ios/iosNativeARCExample/src/UI/MyAppViewController.mm @@ -0,0 +1,206 @@ +// +// MenuViewController.m +// Created by lukasz karluk on 12/12/11. +// Updated for iOS8+ by Andreas Borg 11/18/15 + +#import "MyAppViewController.h" + +#import "SquareAppViewController.h" +#import "SquareApp.h" + +#import "CircleAppViewController.h" +#import "CircleApp.h" + +#import "TriangleAppViewController.h" +#import "TriangleApp.h" + +#import "ImageAppViewController.h" +#import "ImageApp.h" + + + +@interface MyAppViewController() +@property UIScrollView* containerView; +@end + +@implementation MyAppViewController + + + +- (UIButton*) makeButtonWithFrame:(CGRect)frame + andText:(NSString*)text { + UIFont *font; + font = [UIFont fontWithName:@"Georgia" size:30]; + + UILabel *label; + label = [[ UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; + label.backgroundColor = [UIColor colorWithWhite:1 alpha:0.95]; + label.textColor = [UIColor colorWithWhite:0 alpha:1]; + label.text = [text uppercaseString]; + label.textAlignment = NSTextAlignmentCenter; + label.font = font; + label.userInteractionEnabled = NO; + label.exclusiveTouch = NO; + + UIButton* button = [[UIButton alloc] initWithFrame:frame]; + [button setBackgroundColor:[UIColor clearColor]]; + [button addSubview:label]; + + return button; +} + +- (void)loadView { + [super loadView]; + + + + self.view.backgroundColor = [UIColor grayColor]; + + + CGRect screenRect = [[UIScreen mainScreen] bounds]; + + CGRect scrollViewFrame = CGRectMake(0.f, + 0.f, + screenRect.size.width, + screenRect.size.height); + + self.containerView = [[UIScrollView alloc] initWithFrame:scrollViewFrame]; + self.containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.containerView.backgroundColor = [UIColor clearColor]; + self.containerView.showsHorizontalScrollIndicator = NO; + self.containerView.showsVerticalScrollIndicator = YES; + self.containerView.alwaysBounceVertical = YES; + [self.view addSubview:self.containerView]; + + NSArray *buttonTitles; + buttonTitles = [NSArray arrayWithObjects: @"square", @"circle", @"triangle", @"image", nil]; + + NSInteger buttonY = 44; // make room for navigation bar. + NSInteger buttonGap = 2; + NSInteger buttonHeight = (screenRect.size.height - 44) / [buttonTitles count] - buttonGap * ([buttonTitles count] - 1); + CGRect buttonRect = CGRectMake(0, 0, screenRect.size.width, buttonHeight); + + for (int i = 0; i < [buttonTitles count]; i++) { + UIButton *button; + button = [self makeButtonWithFrame:CGRectMake(0, buttonY, buttonRect.size.width, buttonRect.size.height) + andText:[buttonTitles objectAtIndex:i]]; + [self.containerView addSubview:button ]; + + if (i== 0) + [button addTarget:self action:@selector(button1Pressed:) forControlEvents:UIControlEventTouchUpInside]; + else if (i==1) + [button addTarget:self action:@selector(button2Pressed:) forControlEvents:UIControlEventTouchUpInside]; + else if (i==2) + [button addTarget:self action:@selector(button3Pressed:) forControlEvents:UIControlEventTouchUpInside]; + else if (i==3) + [button addTarget:self action:@selector(button4Pressed:) forControlEvents:UIControlEventTouchUpInside]; + + buttonY += buttonRect.size.height; + buttonY += buttonGap; + } + + self.containerView.contentSize = CGSizeMake(buttonRect.size.width, buttonRect.size.height * 3); +} + +- (void)button1Pressed:(id)sender { + SquareAppViewController *viewController; + viewController = [[SquareAppViewController alloc] initWithFrame:[[UIScreen mainScreen] bounds] + app:new SquareApp()]; + + [self.navigationController pushViewController:viewController animated:YES]; + self.navigationController.navigationBar.topItem.title = @"SquareApp"; +} + +- (void)button2Pressed:(id)sender { + CircleAppViewController *viewController; + viewController = [[CircleAppViewController alloc] initWithFrame:[[UIScreen mainScreen] bounds] + app:new CircleApp()]; + + [self.navigationController pushViewController:viewController animated:YES]; + self.navigationController.navigationBar.topItem.title = @"CircleApp"; +} + +- (void)button3Pressed:(id)sender { + TriangleAppViewController *viewController; + viewController = [[TriangleAppViewController alloc] initWithFrame:[[UIScreen mainScreen] bounds] + app:new TriangleApp()]; + + [self.navigationController pushViewController:viewController animated:YES]; + self.navigationController.navigationBar.topItem.title = @"TriangleApp"; +} + +- (void)button4Pressed:(id)sender { + ImageAppViewController *viewController; + viewController = [[ImageAppViewController alloc] initWithFrame:[[UIScreen mainScreen] bounds] + app:new ImageApp()]; + + [self.navigationController pushViewController:viewController animated:YES]; + self.navigationController.navigationBar.topItem.title = @"ImageApp"; +} +// iOS7- +//borg +- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return NO; +/* + BOOL bRotate = NO; + bRotate = bRotate || (toInterfaceOrientation == UIInterfaceOrientationPortrait); + bRotate = bRotate || (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown); + return bRotate; + */ +} + + + +// iOS8+ version of willAnimateRotationToInterfaceOrientation +//borg +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + //this only reports accurately when this is actually in view. If you enter an app, + //then rotate and exit, it will not be updating correctly..hence still needs + //separate updateLayout checking active rotation + cout<<"MyAppViewController - w "<startAppWithDelegate("MyAppDelegate"); + + + +} \ No newline at end of file diff --git a/examples/ios/iosNativeExample/src/AppViewControllers/CircleAppViewController.mm b/examples/ios/iosNativeExample/src/AppViewControllers/CircleAppViewController.mm index 7fb1b3987c3..9e7dcc1ce5e 100644 --- a/examples/ios/iosNativeExample/src/AppViewControllers/CircleAppViewController.mm +++ b/examples/ios/iosNativeExample/src/AppViewControllers/CircleAppViewController.mm @@ -4,7 +4,8 @@ // #import "CircleAppViewController.h" -#import "ofxiOSExtras.h" +#include "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" @implementation CircleAppViewController diff --git a/examples/ios/iosNativeExample/src/AppViewControllers/ImageAppViewController.mm b/examples/ios/iosNativeExample/src/AppViewControllers/ImageAppViewController.mm index b376fbf6f70..afbcb5d03c5 100644 --- a/examples/ios/iosNativeExample/src/AppViewControllers/ImageAppViewController.mm +++ b/examples/ios/iosNativeExample/src/AppViewControllers/ImageAppViewController.mm @@ -4,7 +4,8 @@ // #import "ImageAppViewController.h" -#import "ofxiOSExtras.h" +#include "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" @implementation ImageAppViewController diff --git a/examples/ios/iosNativeExample/src/AppViewControllers/SquareAppViewController.mm b/examples/ios/iosNativeExample/src/AppViewControllers/SquareAppViewController.mm index eb0c4f75f52..a65e9a7afa4 100644 --- a/examples/ios/iosNativeExample/src/AppViewControllers/SquareAppViewController.mm +++ b/examples/ios/iosNativeExample/src/AppViewControllers/SquareAppViewController.mm @@ -4,7 +4,8 @@ // #import "SquareAppViewController.h" -#import "ofxiOSExtras.h" +#include "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" @implementation SquareAppViewController diff --git a/examples/ios/iosNativeExample/src/AppViewControllers/TriangleAppViewController.mm b/examples/ios/iosNativeExample/src/AppViewControllers/TriangleAppViewController.mm index 97869d348e2..424cd044678 100644 --- a/examples/ios/iosNativeExample/src/AppViewControllers/TriangleAppViewController.mm +++ b/examples/ios/iosNativeExample/src/AppViewControllers/TriangleAppViewController.mm @@ -4,7 +4,8 @@ // #import "TriangleAppViewController.h" -#import "ofxiOSExtras.h" +#include "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" @implementation TriangleAppViewController diff --git a/examples/ios/iosNativeExample/src/Apps/CircleApp.h b/examples/ios/iosNativeExample/src/Apps/CircleApp.h index 680b4f93736..573e0349554 100644 --- a/examples/ios/iosNativeExample/src/Apps/CircleApp.h +++ b/examples/ios/iosNativeExample/src/Apps/CircleApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class CircleApp : public ofxiOSApp { diff --git a/examples/ios/iosNativeExample/src/Apps/CircleApp.mm b/examples/ios/iosNativeExample/src/Apps/CircleApp.mm index 31e1ef7fc73..2635362415d 100644 --- a/examples/ios/iosNativeExample/src/Apps/CircleApp.mm +++ b/examples/ios/iosNativeExample/src/Apps/CircleApp.mm @@ -34,7 +34,7 @@ int p = 0; ofSetColor(ofColor::red); - ofCircle(x, y, r); + ofDrawCircle(x, y, r); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosNativeExample/src/Apps/ImageApp.h b/examples/ios/iosNativeExample/src/Apps/ImageApp.h index ae019feb08d..6f2e5ef331b 100644 --- a/examples/ios/iosNativeExample/src/Apps/ImageApp.h +++ b/examples/ios/iosNativeExample/src/Apps/ImageApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ImageApp : public ofxiOSApp { diff --git a/examples/ios/iosNativeExample/src/Apps/ImageApp.mm b/examples/ios/iosNativeExample/src/Apps/ImageApp.mm index 8a09ecb1ff5..573a649da19 100644 --- a/examples/ios/iosNativeExample/src/Apps/ImageApp.mm +++ b/examples/ios/iosNativeExample/src/Apps/ImageApp.mm @@ -30,8 +30,8 @@ //-------------------------------------------------------------- void ImageApp::draw() { - int x = (ofGetWidth() - image.width) * 0.5; - int y = (ofGetHeight() - image.height) * 0.5; + int x = (ofGetWidth() - image.getWidth()) * 0.5; + int y = (ofGetHeight() - image.getHeight()) * 0.5; int p = 0; ofSetColor(ofColor::white); diff --git a/examples/ios/iosNativeExample/src/Apps/SquareApp.h b/examples/ios/iosNativeExample/src/Apps/SquareApp.h index 8bac9f30f8b..e371d255c66 100644 --- a/examples/ios/iosNativeExample/src/Apps/SquareApp.h +++ b/examples/ios/iosNativeExample/src/Apps/SquareApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class SquareApp : public ofxiOSApp { diff --git a/examples/ios/iosNativeExample/src/Apps/SquareApp.mm b/examples/ios/iosNativeExample/src/Apps/SquareApp.mm index b4a633796c1..5de6ea54f8e 100644 --- a/examples/ios/iosNativeExample/src/Apps/SquareApp.mm +++ b/examples/ios/iosNativeExample/src/Apps/SquareApp.mm @@ -37,7 +37,7 @@ int p = 0; ofSetColor(ofColor::red); - ofRect(x, y, w, h); + ofDrawRectangle(x, y, w, h); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosNativeExample/src/Apps/TriangleApp.h b/examples/ios/iosNativeExample/src/Apps/TriangleApp.h index 4ce8e78513e..086e416b235 100644 --- a/examples/ios/iosNativeExample/src/Apps/TriangleApp.h +++ b/examples/ios/iosNativeExample/src/Apps/TriangleApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class TriangleApp : public ofxiOSApp { diff --git a/examples/ios/iosNativeExample/src/Apps/TriangleApp.mm b/examples/ios/iosNativeExample/src/Apps/TriangleApp.mm index 84a49f44a6c..41e35efe8a5 100644 --- a/examples/ios/iosNativeExample/src/Apps/TriangleApp.mm +++ b/examples/ios/iosNativeExample/src/Apps/TriangleApp.mm @@ -35,7 +35,7 @@ int p = 0; ofSetColor(ofColor::red); - ofTriangle(x, y - a, x + b, y + b, x - b, y + b); + ofDrawTriangle(x, y - a, x + b, y + b, x - b, y + b); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosNativeExample/src/main.mm b/examples/ios/iosNativeExample/src/main.mm index e4d77c778a2..0dbc62c6871 100644 --- a/examples/ios/iosNativeExample/src/main.mm +++ b/examples/ios/iosNativeExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "SquareApp.h" int main(){ @@ -15,8 +13,7 @@ int main(){ settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated. settings.glesVersion = OFXIOS_RENDERER_ES1; // type of renderer to use, ES1, ES2, etc. - shared_ptr windowBase = ofCreateWindow(settings); - ofAppiOSWindow * window = (ofAppiOSWindow *)(windowBase.get()); + ofAppiOSWindow * window = (ofAppiOSWindow *)(ofCreateWindow(settings).get()); bool bUseNative = true; if (bUseNative){ diff --git a/examples/ios/iosNativeExample/src/ofApp.h b/examples/ios/iosNativeExample/src/ofApp.h index f6248f2b9e8..60509cff2e0 100644 --- a/examples/ios/iosNativeExample/src/ofApp.h +++ b/examples/ios/iosNativeExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/iosOrientationExample/src/main.mm b/examples/ios/iosOrientationExample/src/main.mm index 1c3912a69b7..812ff353375 100644 --- a/examples/ios/iosOrientationExample/src/main.mm +++ b/examples/ios/iosOrientationExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { @@ -11,9 +9,10 @@ int main() { settings.enableDepth = false; // enables depth buffer for 3d drawing. settings.enableAntiAliasing = false; // enables anti-aliasing which smooths out graphics on the screen. settings.numOfAntiAliasingSamples = 0; // number of samples used for anti-aliasing. - settings.enableHardwareOrientation = true; // enables native view orientation. + settings.enableHardwareOrientation = false; // enables native view orientation. settings.enableHardwareOrientationAnimation = true; // enables native orientation changes to be animated. settings.glesVersion = OFXIOS_RENDERER_ES1; // type of renderer to use, ES1, ES2, etc. + settings.setupOrientation = OF_ORIENTATION_90_LEFT; // set default orientation for setup ofCreateWindow(settings); diff --git a/examples/ios/iosOrientationExample/src/ofApp.h b/examples/ios/iosOrientationExample/src/ofApp.h index 357a2bbf883..291af9c5aef 100644 --- a/examples/ios/iosOrientationExample/src/ofApp.h +++ b/examples/ios/iosOrientationExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/iosOrientationExample/src/ofApp.mm b/examples/ios/iosOrientationExample/src/ofApp.mm index e1a1924b6ae..e1399085260 100644 --- a/examples/ios/iosOrientationExample/src/ofApp.mm +++ b/examples/ios/iosOrientationExample/src/ofApp.mm @@ -6,7 +6,6 @@ void ofApp::setup(){ ofBackground(70); - ofSetOrientation(OF_ORIENTATION_90_LEFT); bAuto = false; } diff --git a/examples/ios/iosStoryboardExample/src/Apps/CircleApp.h b/examples/ios/iosStoryboardExample/src/Apps/CircleApp.h index 680b4f93736..573e0349554 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/CircleApp.h +++ b/examples/ios/iosStoryboardExample/src/Apps/CircleApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class CircleApp : public ofxiOSApp { diff --git a/examples/ios/iosStoryboardExample/src/Apps/CircleApp.mm b/examples/ios/iosStoryboardExample/src/Apps/CircleApp.mm index 44fb2d83015..dedb53debac 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/CircleApp.mm +++ b/examples/ios/iosStoryboardExample/src/Apps/CircleApp.mm @@ -35,7 +35,7 @@ int p = 0; ofSetColor(ofColor::red); - ofCircle(x, y, r); + ofDrawCircle(x, y, r); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosStoryboardExample/src/Apps/ImageApp.h b/examples/ios/iosStoryboardExample/src/Apps/ImageApp.h index ae019feb08d..6f2e5ef331b 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/ImageApp.h +++ b/examples/ios/iosStoryboardExample/src/Apps/ImageApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ImageApp : public ofxiOSApp { diff --git a/examples/ios/iosStoryboardExample/src/Apps/ImageApp.mm b/examples/ios/iosStoryboardExample/src/Apps/ImageApp.mm index 3807e50836b..de3e8b37f36 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/ImageApp.mm +++ b/examples/ios/iosStoryboardExample/src/Apps/ImageApp.mm @@ -31,8 +31,8 @@ //-------------------------------------------------------------- void ImageApp::draw() { - int x = (ofGetWidth() - image.width) * 0.5; - int y = (ofGetHeight() - image.height) * 0.5; + int x = (ofGetWidth() - image.getWidth()) * 0.5; + int y = (ofGetHeight() - image.getHeight()) * 0.5; int p = 0; ofSetColor(ofColor::white); diff --git a/examples/ios/iosStoryboardExample/src/Apps/SquareApp.h b/examples/ios/iosStoryboardExample/src/Apps/SquareApp.h index 8bac9f30f8b..e371d255c66 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/SquareApp.h +++ b/examples/ios/iosStoryboardExample/src/Apps/SquareApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class SquareApp : public ofxiOSApp { diff --git a/examples/ios/iosStoryboardExample/src/Apps/SquareApp.mm b/examples/ios/iosStoryboardExample/src/Apps/SquareApp.mm index 4fd9cb5ae6c..99dca6ae7eb 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/SquareApp.mm +++ b/examples/ios/iosStoryboardExample/src/Apps/SquareApp.mm @@ -38,7 +38,7 @@ int p = 0; ofSetColor(ofColor::red); - ofRect(x, y, w, h); + ofDrawRectangle(x, y, w, h); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.h b/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.h index 4ce8e78513e..086e416b235 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.h +++ b/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class TriangleApp : public ofxiOSApp { diff --git a/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.mm b/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.mm index 0cfa5b9e434..390c79dc708 100644 --- a/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.mm +++ b/examples/ios/iosStoryboardExample/src/Apps/TriangleApp.mm @@ -36,7 +36,7 @@ int p = 0; ofSetColor(ofColor::red); - ofTriangle(x, y - a, x + b, y + b, x - b, y + b); + ofDrawTriangle(x, y - a, x + b, y + b, x - b, y + b); x = ofGetWidth() * 0.2; y = ofGetHeight() * 0.11; diff --git a/examples/ios/iosStoryboardExample/src/main.mm b/examples/ios/iosStoryboardExample/src/main.mm index 95d8e3db688..1ea2aa6bc41 100644 --- a/examples/ios/iosStoryboardExample/src/main.mm +++ b/examples/ios/iosStoryboardExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "SquareApp.h" int main(){ @@ -15,8 +13,7 @@ int main(){ settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated. settings.glesVersion = OFXIOS_RENDERER_ES1; // type of renderer to use, ES1, ES2, etc. - shared_ptr windowBase = ofCreateWindow(settings); - ofAppiOSWindow * window = (ofAppiOSWindow *)(windowBase.get()); + ofAppiOSWindow * window = (ofAppiOSWindow *)(ofCreateWindow(settings).get()); bool bUseNative = true; if (bUseNative){ diff --git a/examples/ios/iosStoryboardExample/src/ofApp.h b/examples/ios/iosStoryboardExample/src/ofApp.h index f6248f2b9e8..60509cff2e0 100644 --- a/examples/ios/iosStoryboardExample/src/ofApp.h +++ b/examples/ios/iosStoryboardExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/moviePlayerExample/src/main.mm b/examples/ios/moviePlayerExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/moviePlayerExample/src/main.mm +++ b/examples/ios/moviePlayerExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/moviePlayerExample/src/ofApp.h b/examples/ios/moviePlayerExample/src/ofApp.h index 2aef87e11ab..be614532257 100644 --- a/examples/ios/moviePlayerExample/src/ofApp.h +++ b/examples/ios/moviePlayerExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/ofxGuiExample/src/main.mm b/examples/ios/ofxGuiExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/ofxGuiExample/src/main.mm +++ b/examples/ios/ofxGuiExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/ofxGuiExample/src/ofApp.h b/examples/ios/ofxGuiExample/src/ofApp.h index ede9b4fd336..a5dd2f27d3f 100644 --- a/examples/ios/ofxGuiExample/src/ofApp.h +++ b/examples/ios/ofxGuiExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once - #include "ofxiOS.h" -#include "ofxiOSExtras.h" #include "ofxGui.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/ofxGuiExample/src/ofApp.mm b/examples/ios/ofxGuiExample/src/ofApp.mm index e8d69014236..a1309f5f5cc 100644 --- a/examples/ios/ofxGuiExample/src/ofApp.mm +++ b/examples/ios/ofxGuiExample/src/ofApp.mm @@ -60,10 +60,10 @@ ofSetColor(color); if(twoCircles){ - ofCircle(center->x-radius*.5, center->y, radius ); - ofCircle(center->x+radius*.5, center->y, radius ); + ofDrawCircle(center->x-radius*.5, center->y, radius ); + ofDrawCircle(center->x+radius*.5, center->y, radius ); }else{ - ofCircle((ofVec2f)center, radius ); + ofDrawCircle((ofVec2f)center, radius ); } if( bHide ){ diff --git a/examples/ios/opencvExample/src/main.mm b/examples/ios/opencvExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/opencvExample/src/main.mm +++ b/examples/ios/opencvExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/opencvExample/src/ofApp.h b/examples/ios/opencvExample/src/ofApp.h index da14653b59e..901ae50a394 100644 --- a/examples/ios/opencvExample/src/ofApp.h +++ b/examples/ios/opencvExample/src/ofApp.h @@ -1,12 +1,7 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" - - -//ON IPHONE NOTE INCLUDE THIS BEFORE ANYTHING ELSE #include "ofxOpenCv.h" //warning video player doesn't currently work - use live video only diff --git a/examples/ios/opencvExample/src/ofApp.mm b/examples/ios/opencvExample/src/ofApp.mm index 3eaf9490844..8cc2d41a6d3 100644 --- a/examples/ios/opencvExample/src/ofApp.mm +++ b/examples/ios/opencvExample/src/ofApp.mm @@ -48,15 +48,15 @@ if (bNewFrame){ #ifdef _USE_LIVE_VIDEO - if( vidGrabber.getPixels() != NULL ){ + if( vidGrabber.getPixels().getData() != NULL ){ #else - if( vidPlayer.getPixels() != NULL && vidPlayer.getWidth() > 0 ){ + if( vidPlayer.getPixels().getData() != NULL && vidPlayer.getWidth() > 0 ){ #endif #ifdef _USE_LIVE_VIDEO - colorImg.setFromPixels(vidGrabber.getPixels(), capW, capH); + colorImg.setFromPixels(vidGrabber.getPixels().getData(), capW, capH); #else - colorImg.setFromPixels(vidPlayer.getPixels(), capW, capH); + colorImg.setFromPixels(vidPlayer.getPixels().getData(), capW, capH); #endif grayImage = colorImg; diff --git a/examples/ios/opencvFaceExample/src/main.mm b/examples/ios/opencvFaceExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/opencvFaceExample/src/main.mm +++ b/examples/ios/opencvFaceExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/opencvFaceExample/src/ofApp.h b/examples/ios/opencvFaceExample/src/ofApp.h index a70f5f06777..82162e8f61d 100644 --- a/examples/ios/opencvFaceExample/src/ofApp.h +++ b/examples/ios/opencvFaceExample/src/ofApp.h @@ -1,14 +1,9 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" - -//ON IPHONE NOTE INCLUDE THIS BEFORE ANYTHING ELSE #include "ofxOpenCv.h" - //UNCOMMENT TO USE CAMERA. CAMERA ONLY WORKS ON DEVICE NOT SIMULATOR //#define USE_CAMERA diff --git a/examples/ios/oscReceiverExample/src/main.mm b/examples/ios/oscReceiverExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/oscReceiverExample/src/main.mm +++ b/examples/ios/oscReceiverExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/oscReceiverExample/src/ofApp.h b/examples/ios/oscReceiverExample/src/ofApp.h index 625de8b9bc0..6ebcae5ddb3 100644 --- a/examples/ios/oscReceiverExample/src/ofApp.h +++ b/examples/ios/oscReceiverExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #include "ofxOsc.h" // listen on port 12345 diff --git a/examples/ios/oscReceiverExample/src/ofApp.mm b/examples/ios/oscReceiverExample/src/ofApp.mm index 2e1073912e2..ea95e55326f 100644 --- a/examples/ios/oscReceiverExample/src/ofApp.mm +++ b/examples/ios/oscReceiverExample/src/ofApp.mm @@ -31,7 +31,7 @@ while( receiver.hasWaitingMessages() ){ // get the next message ofxOscMessage m; - receiver.getNextMessage( &m ); + receiver.getNextMessage(m); // check for mouse moved message if( m.getAddress() == "/mouse/position" ){ diff --git a/examples/ios/oscSenderExample/src/main.mm b/examples/ios/oscSenderExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/oscSenderExample/src/main.mm +++ b/examples/ios/oscSenderExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/oscSenderExample/src/ofApp.h b/examples/ios/oscSenderExample/src/ofApp.h index f500d051a47..ee60c3ebd02 100644 --- a/examples/ios/oscSenderExample/src/ofApp.h +++ b/examples/ios/oscSenderExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #include "ofxOsc.h" #define HOST "localhost" diff --git a/examples/ios/polygonExample/src/main.mm b/examples/ios/polygonExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/polygonExample/src/main.mm +++ b/examples/ios/polygonExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/polygonExample/src/ofApp.h b/examples/ios/polygonExample/src/ofApp.h index 0c6090a7177..21399ccb4e2 100644 --- a/examples/ios/polygonExample/src/ofApp.h +++ b/examples/ios/polygonExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" typedef struct{ diff --git a/examples/ios/polygonExample/src/ofApp.mm b/examples/ios/polygonExample/src/ofApp.mm index 62ce0b030f2..f3b776be9e8 100644 --- a/examples/ios/polygonExample/src/ofApp.mm +++ b/examples/ios/polygonExample/src/ofApp.mm @@ -221,7 +221,7 @@ for (int i = 0; i < nCurveVertices; i++){ if (curveVertices[i].bOver == true) ofFill(); else ofNoFill(); - ofCircle(curveVertices[i].x, curveVertices[i].y,4); + ofDrawCircle(curveVertices[i].x, curveVertices[i].y,4); } ofDisableAlphaBlending(); //------------------------------------- @@ -258,10 +258,10 @@ ofEnableAlphaBlending(); ofFill(); ofSetColor(0,0,0,40); - ofCircle(x0,y0,4); - ofCircle(x1,y1,4); - ofCircle(x2,y2,4); - ofCircle(x3,y3,4); + ofDrawCircle(x0,y0,4); + ofDrawCircle(x1,y1,4); + ofDrawCircle(x2,y2,4); + ofDrawCircle(x3,y3,4); ofDisableAlphaBlending(); diff --git a/examples/ios/soundPlayerExample/src/main.mm b/examples/ios/soundPlayerExample/src/main.mm index 16159c9471c..b7fa9f6114a 100644 --- a/examples/ios/soundPlayerExample/src/main.mm +++ b/examples/ios/soundPlayerExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/soundPlayerExample/src/ofApp.h b/examples/ios/soundPlayerExample/src/ofApp.h index 3b20b30ceb2..5d8b66450f0 100644 --- a/examples/ios/soundPlayerExample/src/ofApp.h +++ b/examples/ios/soundPlayerExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #import "AVSoundPlayer.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/textureExample/src/main.mm b/examples/ios/textureExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/textureExample/src/main.mm +++ b/examples/ios/textureExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/textureExample/src/ofApp.h b/examples/ios/textureExample/src/ofApp.h index e8a75f7f309..f964c376792 100644 --- a/examples/ios/textureExample/src/ofApp.h +++ b/examples/ios/textureExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/vboExample/src/main.mm b/examples/ios/vboExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/vboExample/src/main.mm +++ b/examples/ios/vboExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/vboExample/src/ofApp.h b/examples/ios/vboExample/src/ofApp.h index 975e7db1c5b..859d8a15265 100644 --- a/examples/ios/vboExample/src/ofApp.h +++ b/examples/ios/vboExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" #define GRID_WIDTH 16 #define GRID_HEIGHT 16 diff --git a/examples/ios/videoGrabberExample/src/main.mm b/examples/ios/videoGrabberExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/videoGrabberExample/src/main.mm +++ b/examples/ios/videoGrabberExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/videoGrabberExample/src/ofApp.h b/examples/ios/videoGrabberExample/src/ofApp.h index f4398cecbba..a5c9cecb34d 100644 --- a/examples/ios/videoGrabberExample/src/ofApp.h +++ b/examples/ios/videoGrabberExample/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp{ diff --git a/examples/ios/xmlSettingsExample/src/main.mm b/examples/ios/xmlSettingsExample/src/main.mm index 507068e0939..900a27323a7 100644 --- a/examples/ios/xmlSettingsExample/src/main.mm +++ b/examples/ios/xmlSettingsExample/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/examples/ios/xmlSettingsExample/src/ofApp.h b/examples/ios/xmlSettingsExample/src/ofApp.h index 955b2c2ffe7..e0d98798163 100644 --- a/examples/ios/xmlSettingsExample/src/ofApp.h +++ b/examples/ios/xmlSettingsExample/src/ofApp.h @@ -1,10 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" -#include "ofMain.h" - #include "ofxXmlSettings.h" #define NUM_PTS 800 diff --git a/tutorials/shader/03_simpleShaderInteraction/addons.make b/examples/shader/01_simpleColorQuad/addons.make similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/addons.make rename to examples/shader/01_simpleColorQuad/addons.make diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersES2/shader.frag b/examples/shader/01_simpleColorQuad/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersES2/shader.frag rename to examples/shader/01_simpleColorQuad/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersES2/shader.vert b/examples/shader/01_simpleColorQuad/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersES2/shader.vert rename to examples/shader/01_simpleColorQuad/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.frag b/examples/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.frag rename to examples/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.vert b/examples/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.vert rename to examples/shader/01_simpleColorQuad/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.frag b/examples/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.frag rename to examples/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.vert b/examples/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.vert rename to examples/shader/01_simpleColorQuad/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/01_simpleColorQuad/src/main.cpp b/examples/shader/01_simpleColorQuad/src/main.cpp new file mode 100644 index 00000000000..75b78368b98 --- /dev/null +++ b/examples/shader/01_simpleColorQuad/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/01_simpleColorQuad/src/ofApp.cpp b/examples/shader/01_simpleColorQuad/src/ofApp.cpp similarity index 100% rename from tutorials/shader/01_simpleColorQuad/src/ofApp.cpp rename to examples/shader/01_simpleColorQuad/src/ofApp.cpp diff --git a/tutorials/shader/01_simpleColorQuad/src/ofApp.h b/examples/shader/01_simpleColorQuad/src/ofApp.h similarity index 100% rename from tutorials/shader/01_simpleColorQuad/src/ofApp.h rename to examples/shader/01_simpleColorQuad/src/ofApp.h diff --git a/tutorials/shader/04_simpleTexturing/addons.make b/examples/shader/02_simpleVertexDisplacement/addons.make similarity index 100% rename from tutorials/shader/04_simpleTexturing/addons.make rename to examples/shader/02_simpleVertexDisplacement/addons.make diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.frag b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.frag rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.vert b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.vert rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.frag b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.frag rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.vert b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.vert rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.frag b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.frag rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.vert b/examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.vert rename to examples/shader/02_simpleVertexDisplacement/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/02_simpleVertexDisplacement/src/main.cpp b/examples/shader/02_simpleVertexDisplacement/src/main.cpp new file mode 100644 index 00000000000..32d9a7b1d74 --- /dev/null +++ b/examples/shader/02_simpleVertexDisplacement/src/main.cpp @@ -0,0 +1,17 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/02_simpleVertexDisplacement/src/ofApp.cpp b/examples/shader/02_simpleVertexDisplacement/src/ofApp.cpp similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/src/ofApp.cpp rename to examples/shader/02_simpleVertexDisplacement/src/ofApp.cpp diff --git a/tutorials/shader/02_simpleVertexDisplacement/src/ofApp.h b/examples/shader/02_simpleVertexDisplacement/src/ofApp.h similarity index 100% rename from tutorials/shader/02_simpleVertexDisplacement/src/ofApp.h rename to examples/shader/02_simpleVertexDisplacement/src/ofApp.h diff --git a/tutorials/shader/05_alphaMasking/addons.make b/examples/shader/03_simpleShaderInteraction/addons.make similarity index 100% rename from tutorials/shader/05_alphaMasking/addons.make rename to examples/shader/03_simpleShaderInteraction/addons.make diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.frag b/examples/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.frag rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.vert b/examples/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.vert rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.frag b/examples/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.frag rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.vert b/examples/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.vert rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.frag b/examples/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.frag rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.vert b/examples/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.vert rename to examples/shader/03_simpleShaderInteraction/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/03_simpleShaderInteraction/src/main.cpp b/examples/shader/03_simpleShaderInteraction/src/main.cpp new file mode 100644 index 00000000000..75b78368b98 --- /dev/null +++ b/examples/shader/03_simpleShaderInteraction/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/03_simpleShaderInteraction/src/ofApp.cpp b/examples/shader/03_simpleShaderInteraction/src/ofApp.cpp similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/src/ofApp.cpp rename to examples/shader/03_simpleShaderInteraction/src/ofApp.cpp diff --git a/tutorials/shader/03_simpleShaderInteraction/src/ofApp.h b/examples/shader/03_simpleShaderInteraction/src/ofApp.h similarity index 100% rename from tutorials/shader/03_simpleShaderInteraction/src/ofApp.h rename to examples/shader/03_simpleShaderInteraction/src/ofApp.h diff --git a/tutorials/shader/06_multiTexture/addons.make b/examples/shader/04_simpleTexturing/addons.make similarity index 100% rename from tutorials/shader/06_multiTexture/addons.make rename to examples/shader/04_simpleTexturing/addons.make diff --git a/tutorials/shader/04_simpleTexturing/bin/data/img.jpg b/examples/shader/04_simpleTexturing/bin/data/img.jpg similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/img.jpg rename to examples/shader/04_simpleTexturing/bin/data/img.jpg diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersES2/shader.frag b/examples/shader/04_simpleTexturing/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersES2/shader.frag rename to examples/shader/04_simpleTexturing/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersES2/shader.vert b/examples/shader/04_simpleTexturing/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersES2/shader.vert rename to examples/shader/04_simpleTexturing/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersGL2/shader.frag b/examples/shader/04_simpleTexturing/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersGL2/shader.frag rename to examples/shader/04_simpleTexturing/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersGL2/shader.vert b/examples/shader/04_simpleTexturing/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersGL2/shader.vert rename to examples/shader/04_simpleTexturing/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersGL3/shader.frag b/examples/shader/04_simpleTexturing/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersGL3/shader.frag rename to examples/shader/04_simpleTexturing/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/04_simpleTexturing/bin/data/shadersGL3/shader.vert b/examples/shader/04_simpleTexturing/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/04_simpleTexturing/bin/data/shadersGL3/shader.vert rename to examples/shader/04_simpleTexturing/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/04_simpleTexturing/src/main.cpp b/examples/shader/04_simpleTexturing/src/main.cpp new file mode 100644 index 00000000000..8c1c87d842a --- /dev/null +++ b/examples/shader/04_simpleTexturing/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/04_simpleTexturing/src/ofApp.cpp b/examples/shader/04_simpleTexturing/src/ofApp.cpp similarity index 100% rename from tutorials/shader/04_simpleTexturing/src/ofApp.cpp rename to examples/shader/04_simpleTexturing/src/ofApp.cpp diff --git a/tutorials/shader/04_simpleTexturing/src/ofApp.h b/examples/shader/04_simpleTexturing/src/ofApp.h similarity index 100% rename from tutorials/shader/04_simpleTexturing/src/ofApp.h rename to examples/shader/04_simpleTexturing/src/ofApp.h diff --git a/tutorials/shader/07_fboAlphaMask/addons.make b/examples/shader/05_alphaMasking/addons.make similarity index 100% rename from tutorials/shader/07_fboAlphaMask/addons.make rename to examples/shader/05_alphaMasking/addons.make diff --git a/libs/openFrameworksCompiled/lib/win_cb/.gitkeep b/examples/shader/05_alphaMasking/bin/data/.gitkeep similarity index 100% rename from libs/openFrameworksCompiled/lib/win_cb/.gitkeep rename to examples/shader/05_alphaMasking/bin/data/.gitkeep diff --git a/tutorials/shader/05_alphaMasking/bin/data/img.jpg b/examples/shader/05_alphaMasking/bin/data/img.jpg similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/img.jpg rename to examples/shader/05_alphaMasking/bin/data/img.jpg diff --git a/tutorials/shader/05_alphaMasking/bin/data/img_mask.png b/examples/shader/05_alphaMasking/bin/data/img_mask.png similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/img_mask.png rename to examples/shader/05_alphaMasking/bin/data/img_mask.png diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersES2/shader.frag b/examples/shader/05_alphaMasking/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersES2/shader.frag rename to examples/shader/05_alphaMasking/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersES2/shader.vert b/examples/shader/05_alphaMasking/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersES2/shader.vert rename to examples/shader/05_alphaMasking/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersGL2/shader.frag b/examples/shader/05_alphaMasking/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersGL2/shader.frag rename to examples/shader/05_alphaMasking/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersGL2/shader.vert b/examples/shader/05_alphaMasking/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersGL2/shader.vert rename to examples/shader/05_alphaMasking/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersGL3/shader.frag b/examples/shader/05_alphaMasking/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersGL3/shader.frag rename to examples/shader/05_alphaMasking/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/05_alphaMasking/bin/data/shadersGL3/shader.vert b/examples/shader/05_alphaMasking/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/shadersGL3/shader.vert rename to examples/shader/05_alphaMasking/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/05_alphaMasking/src/main.cpp b/examples/shader/05_alphaMasking/src/main.cpp new file mode 100644 index 00000000000..75b78368b98 --- /dev/null +++ b/examples/shader/05_alphaMasking/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/05_alphaMasking/src/ofApp.cpp b/examples/shader/05_alphaMasking/src/ofApp.cpp similarity index 100% rename from tutorials/shader/05_alphaMasking/src/ofApp.cpp rename to examples/shader/05_alphaMasking/src/ofApp.cpp diff --git a/tutorials/shader/05_alphaMasking/src/ofApp.h b/examples/shader/05_alphaMasking/src/ofApp.h similarity index 100% rename from tutorials/shader/05_alphaMasking/src/ofApp.h rename to examples/shader/05_alphaMasking/src/ofApp.h diff --git a/tutorials/shader/08_displacementMap/addons.make b/examples/shader/06_multiTexture/addons.make similarity index 100% rename from tutorials/shader/08_displacementMap/addons.make rename to examples/shader/06_multiTexture/addons.make diff --git a/scripts/linux/template/linux/bin/data/.gitkeep b/examples/shader/06_multiTexture/bin/data/.gitkeep similarity index 100% rename from scripts/linux/template/linux/bin/data/.gitkeep rename to examples/shader/06_multiTexture/bin/data/.gitkeep diff --git a/tutorials/shader/06_multiTexture/bin/data/img.jpg b/examples/shader/06_multiTexture/bin/data/img.jpg similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/img.jpg rename to examples/shader/06_multiTexture/bin/data/img.jpg diff --git a/tutorials/shader/06_multiTexture/bin/data/mask.jpg b/examples/shader/06_multiTexture/bin/data/mask.jpg similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/mask.jpg rename to examples/shader/06_multiTexture/bin/data/mask.jpg diff --git a/tutorials/shader/06_multiTexture/bin/data/movie.mov b/examples/shader/06_multiTexture/bin/data/movie.mov similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/movie.mov rename to examples/shader/06_multiTexture/bin/data/movie.mov diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersES2/shader.frag b/examples/shader/06_multiTexture/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersES2/shader.frag rename to examples/shader/06_multiTexture/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersES2/shader.vert b/examples/shader/06_multiTexture/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersES2/shader.vert rename to examples/shader/06_multiTexture/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersGL2/shader.frag b/examples/shader/06_multiTexture/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersGL2/shader.frag rename to examples/shader/06_multiTexture/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersGL2/shader.vert b/examples/shader/06_multiTexture/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersGL2/shader.vert rename to examples/shader/06_multiTexture/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersGL3/shader.frag b/examples/shader/06_multiTexture/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersGL3/shader.frag rename to examples/shader/06_multiTexture/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/06_multiTexture/bin/data/shadersGL3/shader.vert b/examples/shader/06_multiTexture/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/shadersGL3/shader.vert rename to examples/shader/06_multiTexture/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/06_multiTexture/src/main.cpp b/examples/shader/06_multiTexture/src/main.cpp new file mode 100644 index 00000000000..6a6927c7a4a --- /dev/null +++ b/examples/shader/06_multiTexture/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/06_multiTexture/src/ofApp.cpp b/examples/shader/06_multiTexture/src/ofApp.cpp similarity index 100% rename from tutorials/shader/06_multiTexture/src/ofApp.cpp rename to examples/shader/06_multiTexture/src/ofApp.cpp diff --git a/tutorials/shader/06_multiTexture/src/ofApp.h b/examples/shader/06_multiTexture/src/ofApp.h similarity index 100% rename from tutorials/shader/06_multiTexture/src/ofApp.h rename to examples/shader/06_multiTexture/src/ofApp.h diff --git a/tutorials/shader/09_gaussianBlurFilter/addons.make b/examples/shader/07_fboAlphaMask/addons.make similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/addons.make rename to examples/shader/07_fboAlphaMask/addons.make diff --git a/scripts/linux/template/linux64/bin/data/.gitkeep b/examples/shader/07_fboAlphaMask/bin/data/.gitkeep similarity index 100% rename from scripts/linux/template/linux64/bin/data/.gitkeep rename to examples/shader/07_fboAlphaMask/bin/data/.gitkeep diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/A.jpg b/examples/shader/07_fboAlphaMask/bin/data/A.jpg similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/A.jpg rename to examples/shader/07_fboAlphaMask/bin/data/A.jpg diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/B.jpg b/examples/shader/07_fboAlphaMask/bin/data/B.jpg similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/B.jpg rename to examples/shader/07_fboAlphaMask/bin/data/B.jpg diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/brush.png b/examples/shader/07_fboAlphaMask/bin/data/brush.png similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/brush.png rename to examples/shader/07_fboAlphaMask/bin/data/brush.png diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersES2/shader.frag b/examples/shader/07_fboAlphaMask/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersES2/shader.frag rename to examples/shader/07_fboAlphaMask/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersES2/shader.vert b/examples/shader/07_fboAlphaMask/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersES2/shader.vert rename to examples/shader/07_fboAlphaMask/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.frag b/examples/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.frag rename to examples/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.vert b/examples/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.vert rename to examples/shader/07_fboAlphaMask/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.frag b/examples/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.frag rename to examples/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.vert b/examples/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.vert rename to examples/shader/07_fboAlphaMask/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/07_fboAlphaMask/src/main.cpp b/examples/shader/07_fboAlphaMask/src/main.cpp new file mode 100644 index 00000000000..75b78368b98 --- /dev/null +++ b/examples/shader/07_fboAlphaMask/src/main.cpp @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/07_fboAlphaMask/src/ofApp.cpp b/examples/shader/07_fboAlphaMask/src/ofApp.cpp similarity index 100% rename from tutorials/shader/07_fboAlphaMask/src/ofApp.cpp rename to examples/shader/07_fboAlphaMask/src/ofApp.cpp diff --git a/tutorials/shader/07_fboAlphaMask/src/ofApp.h b/examples/shader/07_fboAlphaMask/src/ofApp.h similarity index 100% rename from tutorials/shader/07_fboAlphaMask/src/ofApp.h rename to examples/shader/07_fboAlphaMask/src/ofApp.h diff --git a/scripts/linux/template/linuxarmv6l/bin/data/.gitkeep b/examples/shader/08_displacementMap/addons.make similarity index 100% rename from scripts/linux/template/linuxarmv6l/bin/data/.gitkeep rename to examples/shader/08_displacementMap/addons.make diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersES2/shader.frag b/examples/shader/08_displacementMap/bin/data/shadersES2/shader.frag similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersES2/shader.frag rename to examples/shader/08_displacementMap/bin/data/shadersES2/shader.frag diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersES2/shader.vert b/examples/shader/08_displacementMap/bin/data/shadersES2/shader.vert similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersES2/shader.vert rename to examples/shader/08_displacementMap/bin/data/shadersES2/shader.vert diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersGL2/shader.frag b/examples/shader/08_displacementMap/bin/data/shadersGL2/shader.frag similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersGL2/shader.frag rename to examples/shader/08_displacementMap/bin/data/shadersGL2/shader.frag diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersGL2/shader.vert b/examples/shader/08_displacementMap/bin/data/shadersGL2/shader.vert similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersGL2/shader.vert rename to examples/shader/08_displacementMap/bin/data/shadersGL2/shader.vert diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersGL3/shader.frag b/examples/shader/08_displacementMap/bin/data/shadersGL3/shader.frag similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersGL3/shader.frag rename to examples/shader/08_displacementMap/bin/data/shadersGL3/shader.frag diff --git a/tutorials/shader/08_displacementMap/bin/data/shadersGL3/shader.vert b/examples/shader/08_displacementMap/bin/data/shadersGL3/shader.vert similarity index 100% rename from tutorials/shader/08_displacementMap/bin/data/shadersGL3/shader.vert rename to examples/shader/08_displacementMap/bin/data/shadersGL3/shader.vert diff --git a/examples/shader/08_displacementMap/src/main.cpp b/examples/shader/08_displacementMap/src/main.cpp new file mode 100644 index 00000000000..1409d7d289e --- /dev/null +++ b/examples/shader/08_displacementMap/src/main.cpp @@ -0,0 +1,17 @@ +#include "ofMain.h" +#include "ofApp.h" + + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/08_displacementMap/src/ofApp.cpp b/examples/shader/08_displacementMap/src/ofApp.cpp similarity index 100% rename from tutorials/shader/08_displacementMap/src/ofApp.cpp rename to examples/shader/08_displacementMap/src/ofApp.cpp diff --git a/tutorials/shader/08_displacementMap/src/ofApp.h b/examples/shader/08_displacementMap/src/ofApp.h similarity index 100% rename from tutorials/shader/08_displacementMap/src/ofApp.h rename to examples/shader/08_displacementMap/src/ofApp.h diff --git a/scripts/linux/template/linuxarmv7l/bin/data/.gitkeep b/examples/shader/09_gaussianBlurFilter/addons.make similarity index 100% rename from scripts/linux/template/linuxarmv7l/bin/data/.gitkeep rename to examples/shader/09_gaussianBlurFilter/addons.make diff --git a/scripts/osx/template/bin/data/.gitkeep b/examples/shader/09_gaussianBlurFilter/bin/data/.gitkeep similarity index 100% rename from scripts/osx/template/bin/data/.gitkeep rename to examples/shader/09_gaussianBlurFilter/bin/data/.gitkeep diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/img.jpg b/examples/shader/09_gaussianBlurFilter/bin/data/img.jpg similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/img.jpg rename to examples/shader/09_gaussianBlurFilter/bin/data/img.jpg diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurX.vert diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersES2/shaderBlurY.vert diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurX.vert diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL2/shaderBlurY.vert diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurX.vert diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.frag b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.frag similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.frag rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.frag diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.vert b/examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.vert similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.vert rename to examples/shader/09_gaussianBlurFilter/bin/data/shadersGL3/shaderBlurY.vert diff --git a/examples/shader/09_gaussianBlurFilter/src/main.cpp b/examples/shader/09_gaussianBlurFilter/src/main.cpp new file mode 100644 index 00000000000..1409d7d289e --- /dev/null +++ b/examples/shader/09_gaussianBlurFilter/src/main.cpp @@ -0,0 +1,17 @@ +#include "ofMain.h" +#include "ofApp.h" + + +//======================================================================== +int main( ){ + + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/tutorials/shader/09_gaussianBlurFilter/src/ofApp.cpp b/examples/shader/09_gaussianBlurFilter/src/ofApp.cpp similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/src/ofApp.cpp rename to examples/shader/09_gaussianBlurFilter/src/ofApp.cpp diff --git a/tutorials/shader/09_gaussianBlurFilter/src/ofApp.h b/examples/shader/09_gaussianBlurFilter/src/ofApp.h similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/src/ofApp.h rename to examples/shader/09_gaussianBlurFilter/src/ofApp.h diff --git a/examples/shader/README.md b/examples/shader/README.md new file mode 100644 index 00000000000..85359592823 --- /dev/null +++ b/examples/shader/README.md @@ -0,0 +1 @@ +The examples in this folder belong to the shaders tutorial in the openFrameworks web page: http://openframeworks.cc/tutorials/graphics/shaders.html diff --git a/examples/sound/audioInputExample/src/ofApp.cpp b/examples/sound/audioInputExample/src/ofApp.cpp index 1bc0205da5f..c6fad712305 100644 --- a/examples/sound/audioInputExample/src/ofApp.cpp +++ b/examples/sound/audioInputExample/src/ofApp.cpp @@ -7,20 +7,10 @@ void ofApp::setup(){ ofSetCircleResolution(80); ofBackground(54, 54, 54); - // 0 output channels, - // 2 input channels - // 44100 samples per second - // 256 samples per buffer - // 4 num buffers (latency) - soundStream.printDeviceList(); - //if you want to set a different device id - //soundStream.setDeviceID(0); //bear in mind the device id corresponds to all audio devices, including input-only and output-only devices. - int bufferSize = 256; - - + left.assign(bufferSize, 0.0); right.assign(bufferSize, 0.0); volHistory.assign(400, 0.0); @@ -30,7 +20,32 @@ void ofApp::setup(){ smoothedVol = 0.0; scaledVol = 0.0; - soundStream.setup(this, 0, 2, 44100, bufferSize, 4); + + ofSoundStreamSettings settings; + + // if you want to set the device id to be different than the default + // auto devices = soundStream.getDeviceList(); + // settings.device = devices[4]; + + // you can also get devices for an specific api + // auto devices = soundStream.getDevicesByApi(ofSoundDevice::Api::PULSE); + // settings.device = devices[0]; + + // or get the default device for an specific api: + // settings.api = ofSoundDevice::Api::PULSE; + + // or by name + auto devices = soundStream.getMatchingDevices("default"); + if(!devices.empty()){ + settings.setInDevice(devices[0]); + } + + settings.setInListener(this); + settings.sampleRate = 44100; + settings.numOutputChannels = 0; + settings.numInputChannels = 2; + settings.bufferSize = bufferSize; + soundStream.setup(settings); } @@ -139,7 +154,7 @@ void ofApp::draw(){ } //-------------------------------------------------------------- -void ofApp::audioIn(float * input, int bufferSize, int nChannels){ +void ofApp::audioIn(ofSoundBuffer & input){ float curVol = 0.0; @@ -147,7 +162,7 @@ void ofApp::audioIn(float * input, int bufferSize, int nChannels){ int numCounted = 0; //lets go through each sample and calculate the root mean square which is a rough way to calculate volume - for (int i = 0; i < bufferSize; i++){ + for (int i = 0; i < input.getNumFrames(); i++){ left[i] = input[i*2]*0.5; right[i] = input[i*2+1]*0.5; diff --git a/examples/sound/audioInputExample/src/ofApp.h b/examples/sound/audioInputExample/src/ofApp.h index b2c09197bc9..3edd4adaab4 100644 --- a/examples/sound/audioInputExample/src/ofApp.h +++ b/examples/sound/audioInputExample/src/ofApp.h @@ -22,7 +22,7 @@ class ofApp : public ofBaseApp{ void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); - void audioIn(float * input, int bufferSize, int nChannels); + void audioIn(ofSoundBuffer & input); vector left; vector right; diff --git a/examples/sound/audioOutputExample/src/ofApp.cpp b/examples/sound/audioOutputExample/src/ofApp.cpp index ac6c555e4e3..69b404cb5e6 100644 --- a/examples/sound/audioOutputExample/src/ofApp.cpp +++ b/examples/sound/audioOutputExample/src/ofApp.cpp @@ -4,12 +4,6 @@ void ofApp::setup(){ ofBackground(34, 34, 34); - - // 2 output channels, - // 0 input channels - // 22050 samples per second - // 512 samples per buffer - // 4 num buffers (latency) int bufferSize = 512; sampleRate = 44100; @@ -23,13 +17,49 @@ void ofApp::setup(){ rAudio.assign(bufferSize, 0.0); soundStream.printDeviceList(); - - //if you want to set the device id to be different than the default - //soundStream.setDeviceID(1); //note some devices are input only and some are output only - soundStream.setup(this, 2, 0, sampleRate, bufferSize, 4); + ofSoundStreamSettings settings; + + // if you want to set the device id to be different than the default: + // + // auto devices = soundStream.getDeviceList(); + // settings.setOutDevice(devices[3]); + + // you can also get devices for an specific api: + // + // auto devices = soundStream.getDeviceList(ofSoundDevice::Api::PULSE); + // settings.setOutDevice(devices[0]); + + // or get the default device for an specific api: + // + // settings.api = ofSoundDevice::Api::PULSE; + + // or by name: + // + // auto devices = soundStream.getMatchingDevices("default"); + // if(!devices.empty()){ + // settings.setOutDevice(devices[0]); + // } + +#ifdef TARGET_LINUX + // Latest linux versions default to the HDMI output + // this usually fixes that. Also check the list of available + // devices if sound doesn't work + auto devices = soundStream.getMatchingDevices("default"); + if(!devices.empty()){ + settings.setOutDevice(devices[0]); + } +#endif + + settings.setOutListener(this); + settings.sampleRate = sampleRate; + settings.numOutputChannels = 2; + settings.numInputChannels = 0; + settings.bufferSize = bufferSize; + soundStream.setup(settings); - ofSetFrameRate(60); + // on OSX: if you want to use ofSoundPlayer together with ofSoundStream you need to synchronize buffersizes. + // use ofFmodSetBuffersize(bufferSize) to set the buffersize in fmodx prior to loading a file. } @@ -176,7 +206,7 @@ void ofApp::windowResized(int w, int h){ } //-------------------------------------------------------------- -void ofApp::audioOut(float * output, int bufferSize, int nChannels){ +void ofApp::audioOut(ofSoundBuffer & buffer){ //pan = 0.5f; float leftScale = 1 - pan; float rightScale = pan; @@ -189,17 +219,17 @@ void ofApp::audioOut(float * output, int bufferSize, int nChannels){ if ( bNoise == true){ // ---------------------- noise -------------- - for (int i = 0; i < bufferSize; i++){ - lAudio[i] = output[i*nChannels ] = ofRandom(0, 1) * volume * leftScale; - rAudio[i] = output[i*nChannels + 1] = ofRandom(0, 1) * volume * rightScale; + for (int i = 0; i < buffer.getNumFrames(); i++){ + lAudio[i] = buffer[i*buffer.getNumChannels() ] = ofRandom(0, 1) * volume * leftScale; + rAudio[i] = buffer[i*buffer.getNumChannels() + 1] = ofRandom(0, 1) * volume * rightScale; } } else { phaseAdder = 0.95f * phaseAdder + 0.05f * phaseAdderTarget; - for (int i = 0; i < bufferSize; i++){ + for (int i = 0; i < buffer.getNumFrames(); i++){ phase += phaseAdder; float sample = sin(phase); - lAudio[i] = output[i*nChannels ] = sample * volume * leftScale; - rAudio[i] = output[i*nChannels + 1] = sample * volume * rightScale; + lAudio[i] = buffer[i*buffer.getNumChannels() ] = sample * volume * leftScale; + rAudio[i] = buffer[i*buffer.getNumChannels() + 1] = sample * volume * rightScale; } } diff --git a/examples/sound/audioOutputExample/src/ofApp.h b/examples/sound/audioOutputExample/src/ofApp.h index f3911b67f73..0a8d13a2a1d 100644 --- a/examples/sound/audioOutputExample/src/ofApp.h +++ b/examples/sound/audioOutputExample/src/ofApp.h @@ -22,7 +22,7 @@ class ofApp : public ofBaseApp{ void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); - void audioOut(float * input, int bufferSize, int nChannels); + void audioOut(ofSoundBuffer & buffer); ofSoundStream soundStream; diff --git a/examples/sound/soundBufferExample/src/ofApp.cpp b/examples/sound/soundBufferExample/src/ofApp.cpp index 33f260e72f8..871ad8850ef 100644 --- a/examples/sound/soundBufferExample/src/ofApp.cpp +++ b/examples/sound/soundBufferExample/src/ofApp.cpp @@ -30,7 +30,7 @@ void ofApp::update(){ // of the window waveform.clear(); - for(int i = 0; i < lastBuffer.getNumFrames(); i++) { + for(size_t i = 0; i < lastBuffer.getNumFrames(); i++) { float sample = lastBuffer.getSample(i, 0); float x = ofMap(i, 0, lastBuffer.getNumFrames(), 0, ofGetWidth()); float y = ofMap(sample, -1, 1, 0, ofGetHeight()); @@ -62,7 +62,7 @@ void ofApp::audioOut(ofSoundBuffer &outBuffer) { // frequencies, and pulses the volume of each sine wave individually. In // other words, 3 oscillators and 3 LFOs. - for(int i = 0; i < outBuffer.getNumFrames(); i++) { + for(size_t i = 0; i < outBuffer.getNumFrames(); i++) { // build up a chord out of sine waves at 3 different frequencies float sampleLow = sin(wavePhase); diff --git a/examples/sound/soundPlayerExample/src/ofApp.cpp b/examples/sound/soundPlayerExample/src/ofApp.cpp index b2edd2ab96a..7580534bf7e 100644 --- a/examples/sound/soundPlayerExample/src/ofApp.cpp +++ b/examples/sound/soundPlayerExample/src/ofApp.cpp @@ -2,6 +2,10 @@ //-------------------------------------------------------------- void ofApp::setup(){ + + // on OSX: if you want to use ofSoundPlayer together with ofSoundStream you need to synchronize buffersizes. + // use ofFmodSetBuffersize(bufferSize) to set the buffersize in fmodx prior to loading a file. + synth.load("sounds/synth.wav"); beats.load("sounds/1085.mp3"); vocals.load("sounds/Violet.mp3"); diff --git a/examples/utils/fileBufferLoadingCSVExample/src/ofApp.cpp b/examples/utils/fileBufferLoadingCSVExample/src/ofApp.cpp index b86015d1a33..592c61d28cc 100644 --- a/examples/utils/fileBufferLoadingCSVExample/src/ofApp.cpp +++ b/examples/utils/fileBufferLoadingCSVExample/src/ofApp.cpp @@ -18,29 +18,29 @@ void ofApp::setup(){ if(!file.exists()){ ofLogError("The file " + filePath + " is missing"); } - - ofBuffer buffer(file); + ofBuffer buffer(file); //Read file line by line for (ofBuffer::Line it = buffer.getLines().begin(), end = buffer.getLines().end(); it != end; ++it) { - string line = *it; - - //Split line into strings + string line = *it; + //Split line into strings vector words = ofSplitString(line, ","); - + //Store strings into a custom container - MorseCodeSymbol symbol; - symbol.character = words[0]; - symbol.code = words[1]; - - //Save MorseCodeSymbols for later - morseCodeSymbols.push_back(symbol); - - //Debug output - ofLogVerbose("symbol.character: " + symbol.character); - ofLogVerbose("symbol.code: " + symbol.code); + if (words.size()>=2) { + MorseCodeSymbol symbol; + symbol.character = words[0]; + symbol.code = words[1]; + + //Save MorseCodeSymbols for later + morseCodeSymbols.push_back(symbol); + + //Debug output + ofLogVerbose("symbol.character: " + symbol.character); + ofLogVerbose("symbol.code: " + symbol.code); + } } - + //Load our Morse code sounds player.setup(); } diff --git a/examples/utils/threadChannelExample/src/ImgAnalysisThread.cpp b/examples/utils/threadChannelExample/src/ImgAnalysisThread.cpp index 061b13451fd..2ff2ad7714e 100644 --- a/examples/utils/threadChannelExample/src/ImgAnalysisThread.cpp +++ b/examples/utils/threadChannelExample/src/ImgAnalysisThread.cpp @@ -29,7 +29,7 @@ void ImgAnalysisThread::analyze(ofPixels & pixels){ // send the frame to the thread for analyzing // this makes a copy but we can't avoid it anyway if // we want to update the grabber while analyzing - // previous frames + // previous frames toAnalyze.send(pixels); } @@ -44,6 +44,9 @@ void ImgAnalysisThread::update(){ newFrame = true; } if(newFrame){ + if(!texture.isAllocated()){ + texture.allocate(pixels); + } texture.loadData(pixels); } } @@ -61,44 +64,45 @@ ofTexture & ImgAnalysisThread::getTexture(){ } void ImgAnalysisThread::draw(float x, float y){ - texture.draw(x,y); + if(texture.isAllocated()){ + texture.draw(x,y); + }else{ + ofDrawBitmapString("No frames analyzed yet", x+20, y+20); + } } void ImgAnalysisThread::draw(float x, float y, float w, float h){ - texture.draw(x,y,w,h); + if(texture.isAllocated()){ + texture.draw(x,y,w,h); + }else{ + ofDrawBitmapString("No frames analyzed yet", x+20, y+20); + } } void ImgAnalysisThread::threadedFunction(){ - while(isThreadRunning()){ - // wait until there's a new frame - // this blocks the thread, so it doesn't use - // the CPU at all, until a frame arrives. - // also receive doesn't allocate or make any copies - ofPixels pixels; - if(toAnalyze.receive(pixels)){ - // we have a new frame, process it, the analysis - // here is just a thresholding for the sake of - // simplicity - pixels.setImageType(OF_IMAGE_GRAYSCALE); - for(int i=0;i80) pixels[i] = 255; - else pixels[i] = 0; - } + // wait until there's a new frame + // this blocks the thread, so it doesn't use + // the CPU at all, until a frame arrives. + // also receive doesn't allocate or make any copies + ofPixels pixels; + while(toAnalyze.receive(pixels)){ + // we have a new frame, process it, the analysis + // here is just a thresholding for the sake of + // simplicity + pixels.setImageType(OF_IMAGE_GRAYSCALE); + for(auto & p: pixels){ + if(p > 80) p = 255; + else p = 0; + } - // once processed send the result back to the - // main thread. in c++11 we can move it to - // avoid a copy + // once processed send the result back to the + // main thread. in c++11 we can move it to + // avoid a copy #if __cplusplus>=201103 - analyzed.send(std::move(pixels)); + analyzed.send(std::move(pixels)); #else - analyzed.send(pixels); + analyzed.send(pixels); #endif - }else{ - // if receive returns false the channel - // has been closed, go out of the while loop - // to end the thread - break; - } } } diff --git a/examples/video/videoPlayerExample/bin/data/movies/fingers.mov b/examples/video/videoPlayerExample/bin/data/movies/fingers.mov index 3cd4cba8fbe..768d45efb6b 100644 Binary files a/examples/video/videoPlayerExample/bin/data/movies/fingers.mov and b/examples/video/videoPlayerExample/bin/data/movies/fingers.mov differ diff --git a/export/linux/libs/libfmodex.so b/export/linux/libs/libfmodex.so index ede2f980826..ac9d2640b2f 100644 Binary files a/export/linux/libs/libfmodex.so and b/export/linux/libs/libfmodex.so differ diff --git a/export/linux/libs/libfmodexp.so b/export/linux/libs/libfmodexp.so deleted file mode 100644 index 8badce9032d..00000000000 Binary files a/export/linux/libs/libfmodexp.so and /dev/null differ diff --git a/export/linux64/libs/libfmodex.so b/export/linux64/libs/libfmodex.so index 9e5d07ebb58..4e91f5c27f3 100644 Binary files a/export/linux64/libs/libfmodex.so and b/export/linux64/libs/libfmodex.so differ diff --git a/export/linux64/libs/libfmodexp64.so b/export/linux64/libs/libfmodexp64.so deleted file mode 100644 index b12fb3084f7..00000000000 Binary files a/export/linux64/libs/libfmodexp64.so and /dev/null differ diff --git a/export/msys2/fmodex.dll b/export/msys2/fmodex.dll new file mode 100644 index 00000000000..9ab3989fcdc Binary files /dev/null and b/export/msys2/fmodex.dll differ diff --git a/export/osx/libs/libfmodex.dylib b/export/osx/libs/libfmodex.dylib index 545c4bad9fe..4ae02bc9e12 100644 Binary files a/export/osx/libs/libfmodex.dylib and b/export/osx/libs/libfmodex.dylib differ diff --git a/export/vs/Win32/fmodex.dll b/export/vs/Win32/fmodex.dll index e8ff8f01fe3..9ab3989fcdc 100644 Binary files a/export/vs/Win32/fmodex.dll and b/export/vs/Win32/fmodex.dll differ diff --git a/export/vs/Win32/fmodexL.dll b/export/vs/Win32/fmodexL.dll index b5c7125a57a..08a0fb4affa 100644 Binary files a/export/vs/Win32/fmodexL.dll and b/export/vs/Win32/fmodexL.dll differ diff --git a/export/vs/x64/fmodex64.dll b/export/vs/x64/fmodex64.dll index ff459efb07a..c8fe2bf3d0b 100644 Binary files a/export/vs/x64/fmodex64.dll and b/export/vs/x64/fmodex64.dll differ diff --git a/export/vs/x64/fmodexL64.dll b/export/vs/x64/fmodexL64.dll index ed1bfaf0c86..b4412cf28ad 100644 Binary files a/export/vs/x64/fmodexL64.dll and b/export/vs/x64/fmodexL64.dll differ diff --git a/export/win_cb/FreeImage.dll b/export/win_cb/FreeImage.dll deleted file mode 100644 index e5b1afe441c..00000000000 Binary files a/export/win_cb/FreeImage.dll and /dev/null differ diff --git a/export/win_cb/fmodex.dll b/export/win_cb/fmodex.dll deleted file mode 100644 index e8ff8f01fe3..00000000000 Binary files a/export/win_cb/fmodex.dll and /dev/null differ diff --git a/export/win_cb/glut.dll b/export/win_cb/glut.dll deleted file mode 100644 index 106646ff710..00000000000 Binary files a/export/win_cb/glut.dll and /dev/null differ diff --git a/export/win_cb/libassimp.dll b/export/win_cb/libassimp.dll deleted file mode 100644 index 9abe0a1e001..00000000000 Binary files a/export/win_cb/libassimp.dll and /dev/null differ diff --git a/export/win_cb/libfreetype-6.dll b/export/win_cb/libfreetype-6.dll deleted file mode 100644 index 82534340506..00000000000 Binary files a/export/win_cb/libfreetype-6.dll and /dev/null differ diff --git a/export/win_cb/zlib1.dll b/export/win_cb/zlib1.dll deleted file mode 100644 index 198f0ec7752..00000000000 Binary files a/export/win_cb/zlib1.dll and /dev/null differ diff --git a/libs/FreeImage/lib/android.zip b/libs/FreeImage/lib/android.zip deleted file mode 100644 index 3446f802dbe..00000000000 Binary files a/libs/FreeImage/lib/android.zip and /dev/null differ diff --git a/libs/FreeImage/lib/osx/freeimage.a b/libs/FreeImage/lib/osx/freeimage.a index b6de3b92c95..9db7c52a60d 100644 Binary files a/libs/FreeImage/lib/osx/freeimage.a and b/libs/FreeImage/lib/osx/freeimage.a differ diff --git a/libs/FreeImage/lib/win_cb/FreeImage.lib b/libs/FreeImage/lib/win_cb/FreeImage.lib deleted file mode 100644 index ccef3ef34db..00000000000 Binary files a/libs/FreeImage/lib/win_cb/FreeImage.lib and /dev/null differ diff --git a/libs/boost/include/boost/config/compiler/visualc.hpp b/libs/boost/include/boost/config/compiler/visualc.hpp index ce6bbeec78d..d17ce4b86c7 100644 --- a/libs/boost/include/boost/config/compiler/visualc.hpp +++ b/libs/boost/include/boost/config/compiler/visualc.hpp @@ -285,7 +285,7 @@ // // last known and checked version is 19.00.22129 (VC14 Preview): -#if (_MSC_VER > 1800 && _MSC_FULL_VER > 190022310) +#if (_MSC_VER > 1900 && _MSC_FULL_VER > 190022310) # if defined(BOOST_ASSERT_CONFIG) # error "Unknown compiler version - please run the configure tests and report the results" # else diff --git a/libs/boost/lib/ios/boost_filesystem.a b/libs/boost/lib/ios/boost_filesystem.a index c907def6f18..579bf434ae7 100644 Binary files a/libs/boost/lib/ios/boost_filesystem.a and b/libs/boost/lib/ios/boost_filesystem.a differ diff --git a/libs/boost/lib/ios/boost_system.a b/libs/boost/lib/ios/boost_system.a index e4e5f998678..5c3ca3654dd 100644 Binary files a/libs/boost/lib/ios/boost_system.a and b/libs/boost/lib/ios/boost_system.a differ diff --git a/libs/boost/lib/osx/boost_filesystem.a b/libs/boost/lib/osx/boost_filesystem.a index 22ec3651dc6..86b1c893185 100644 Binary files a/libs/boost/lib/osx/boost_filesystem.a and b/libs/boost/lib/osx/boost_filesystem.a differ diff --git a/libs/boost/lib/osx/boost_system.a b/libs/boost/lib/osx/boost_system.a index 14c880e3bbb..6f820554645 100644 Binary files a/libs/boost/lib/osx/boost_system.a and b/libs/boost/lib/osx/boost_system.a differ diff --git a/libs/cairo/lib/osx/cairo-script-interpreter.a b/libs/cairo/lib/osx/cairo-script-interpreter.a index c1445e7b00c..755fface8f8 100644 Binary files a/libs/cairo/lib/osx/cairo-script-interpreter.a and b/libs/cairo/lib/osx/cairo-script-interpreter.a differ diff --git a/libs/cairo/lib/osx/cairo.a b/libs/cairo/lib/osx/cairo.a index 108f3639e0e..a47f6541ab8 100644 Binary files a/libs/cairo/lib/osx/cairo.a and b/libs/cairo/lib/osx/cairo.a differ diff --git a/libs/cairo/lib/osx/pixman-1.a b/libs/cairo/lib/osx/pixman-1.a index 87083db77f7..dd9ae5ea3ea 100644 Binary files a/libs/cairo/lib/osx/pixman-1.a and b/libs/cairo/lib/osx/pixman-1.a differ diff --git a/libs/cairo/lib/osx/png.a b/libs/cairo/lib/osx/png.a index 694f1cbc566..2d5fa92c3c1 100644 Binary files a/libs/cairo/lib/osx/png.a and b/libs/cairo/lib/osx/png.a differ diff --git a/libs/cairo/lib/win_cb/libcairo.a b/libs/cairo/lib/win_cb/libcairo.a deleted file mode 100644 index 5be2cd9c0fb..00000000000 Binary files a/libs/cairo/lib/win_cb/libcairo.a and /dev/null differ diff --git a/libs/cairo/lib/win_cb/libpixman-1.a b/libs/cairo/lib/win_cb/libpixman-1.a deleted file mode 100644 index 96722448355..00000000000 Binary files a/libs/cairo/lib/win_cb/libpixman-1.a and /dev/null differ diff --git a/libs/fmodex/include/fmod.h b/libs/fmodex/include/fmod.h index f7384265421..58c2d1eb76e 100644 --- a/libs/fmodex/include/fmod.h +++ b/libs/fmodex/include/fmod.h @@ -1,7 +1,7 @@ /*$ preserve start $*/ /* ============================================================================================ */ -/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* This header is the base header for all other FMOD headers. If you are programming in C */ /* use this exclusively, or if you are programming C++ use this in conjunction with FMOD.HPP */ @@ -16,7 +16,7 @@ 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. */ -#define FMOD_VERSION 0x00044221 +#define FMOD_VERSION 0x00044459 /* Compiler specific settings. @@ -72,6 +72,7 @@ typedef struct FMOD_DSPCONNECTION FMOD_DSPCONNECTION; typedef struct FMOD_POLYGON FMOD_POLYGON; typedef struct FMOD_GEOMETRY FMOD_GEOMETRY; typedef struct FMOD_SYNCPOINT FMOD_SYNCPOINT; +typedef struct FMOD_ASYNCREADINFO FMOD_ASYNCREADINFO; typedef unsigned int FMOD_MODE; typedef unsigned int FMOD_TIMEUNIT; typedef unsigned int FMOD_INITFLAGS; @@ -291,7 +292,7 @@ typedef struct FMOD_FILE_ASYNCCANCELCALLBACK ] */ -typedef struct +struct FMOD_ASYNCREADINFO { void *handle; /* [r] The file handle that was filled out in the open callback. */ unsigned int offset; /* [r] Seek position, make sure you read from this file offset. */ @@ -303,7 +304,9 @@ typedef struct FMOD_RESULT result; /* [r/w] Result code, FMOD_OK tells the system it is ready to consume the data. Set this last! Default value = FMOD_ERR_NOTREADY. */ void *userdata; /* [r] User data pointer. */ -} FMOD_ASYNCREADINFO; + + const void (*done)(FMOD_ASYNCREADINFO *info, FMOD_RESULT result); /* FMOD file system wake up function. Use instead of 'result' with FMOD_INIT_ASYNCREAD_FAST to get semaphore based performance improvement. Call this when user file read is finished. Pass result of file read as a parameter. */ +}; /* @@ -321,6 +324,7 @@ typedef struct
  • FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_GC_INFO struct. This can be found in fmodgc.h.
  • FMOD_OUTPUTTYPE_WII - extradriverdata is a pointer to a FMOD_WII_INFO struct. This can be found in fmodwii.h.
  • FMOD_OUTPUTTYPE_ALSA - extradriverdata is a pointer to a FMOD_LINUX_EXTRADRIVERDATA struct. This can be found in fmodlinux.h.
    +
  • FMOD_OUTPUTTYPE_PULSEAUDIO - extradriverdata is a const char * representing the name of the application to appear in PulseAudio mixer GUIs.

    Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements.

    @@ -374,6 +378,8 @@ typedef enum FMOD_OUTPUTTYPE_NACL, /* Native Client - Native Client output. (Default on Native Client) */ FMOD_OUTPUTTYPE_WIIU, /* Wii U - Native Wii U output. (Default on Wii U) */ FMOD_OUTPUTTYPE_ASOUND, /* BlackBerry - Native BlackBerry asound output. (Default on BlackBerry) */ + FMOD_OUTPUTTYPE_AUDIOOUT, /* Orbis - Audio Out output. (Default on Orbis) */ + FMOD_OUTPUTTYPE_XAUDIO, /* Durango - XAudio2 output. */ FMOD_OUTPUTTYPE_MAX, /* Maximum number of output types supported. */ FMOD_OUTPUTTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ @@ -410,6 +416,7 @@ typedef enum #define FMOD_CAPS_OUTPUT_FORMAT_PCM32 0x00000040 /* Device can output to 32bit integer PCM. */ #define FMOD_CAPS_OUTPUT_FORMAT_PCMFLOAT 0x00000080 /* Device can output to 32bit floating point PCM. */ #define FMOD_CAPS_REVERB_LIMITED 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ +#define FMOD_CAPS_LOOPBACK 0x00004000 /* Device is a loopback recording device */ /* [DEFINE_END] */ /* @@ -579,7 +586,17 @@ typedef enum If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten.

    Output rate must be 44100, 48000 or 96000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned.
    - +
    + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX
    + ------------------------------------------------------
    + This mode is for 5.1 speaker arrangements using a stereo signal, to get a surround effect a Dolby Pro Logic II + hardware decoder / amplifier is needed.
    + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1.
    +
    + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten.
    +
    + Output rate must be 32000, 44100 or 48000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned.
    +
    FMOD_SPEAKERMODE_MYEARS
    ------------------------------------------------------
    This mode is for headphones. This will attempt to load a MyEars profile (see myears.net.au) and use it to generate @@ -611,6 +628,7 @@ typedef enum FMOD_SPEAKERMODE_7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ FMOD_SPEAKERMODE_SRS5_1_MATRIX, /* Stereo compatible output, embedded with surround information. SRS 5.1/Prologic/Prologic2 decoders will split the signal into a 5.1 speaker set-up or SRS virtual surround will decode into a 2-speaker/headphone setup. See remarks about limitations.*/ + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX, /* Stereo compatible output, embedded with surround information. Dolby Pro Logic II decoders will split the signal into a 5.1 speaker set-up. */ FMOD_SPEAKERMODE_MYEARS, /* Stereo output, but data is encoded using personalized HRTF algorithms. See myears.net.au */ FMOD_SPEAKERMODE_MAX, /* Maximum number of speaker modes supported. */ @@ -736,6 +754,8 @@ typedef enum #define FMOD_INIT_DISABLE_MYEARS_AUTODETECT 0x08000000 /* Win32 - Disables automatic setting of FMOD_SPEAKERMODE_STEREO to FMOD_SPEAKERMODE_MYEARS if the MyEars profile exists on the PC. MyEars is HRTF 7.1 downmixing through headphones. */ #define FMOD_INIT_PS3_DISABLEDTS 0x10000000 /* PS3 only - Disable DTS output mode selection */ #define FMOD_INIT_PS3_DISABLEDOLBYDIGITAL 0x20000000 /* PS3 only - Disable Dolby Digital output mode selection */ +#define FMOD_INIT_7POINT1_DOLBYMAPPING 0x40000000 /* PS3/PS4 only - FMOD uses the WAVEFORMATEX Microsoft 7.1 speaker mapping where the last 2 pairs of speakers are 'rears' then 'sides', but on PS3/PS4 these are mapped to 'surrounds' and 'backs'. Use this flag to swap fmod's last 2 pair of speakers on PS3/PS4 to avoid needing to do a special case for these platforms. */ +#define FMOD_INIT_ASYNCREAD_FAST 0x80000000 /* All platforms - Rather than setting FMOD_ASYNCREADINFO::result, call FMOD_ASYNCREADINFO::done to enable a semaphore based wait inside fmod, rather than the older method which can incur up to 10ms delay per read. */ /* [DEFINE_END] */ @@ -885,7 +905,7 @@ typedef enum #define FMOD_SOFTWARE 0x00000040 /* Makes the sound be mixed by the FMOD CPU based software mixer. Overrides FMOD_HARDWARE. Use this for FFT, DSP, compressed sample support, 2D multi-speaker support and other software related features. */ #define FMOD_CREATESTREAM 0x00000080 /* Decompress at runtime, streaming from the source provided (ie from disk). Overrides FMOD_CREATESAMPLE and FMOD_CREATECOMPRESSEDSAMPLE. Note a stream can only be played once at a time due to a stream only having 1 stream buffer and file handle. Open multiple streams to have them play concurrently. */ #define FMOD_CREATESAMPLE 0x00000100 /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format (ie PCM). Fastest for FMOD_SOFTWARE based playback and most flexible. */ -#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2, MP3, IMAADPCM or XMA into memory and leave it compressed. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not ADPCM, MPEG or XMA it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ +#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2/MP3/IMAADPCM/CELT/Vorbis/AT9 or XMA into memory and leave it compressed. CELT/Vorbis/AT9 encoding only supported in the FSB file format. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not one of the supported formats, it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ #define FMOD_OPENUSER 0x00000400 /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use Sound::lock and Sound::unlock to place sound data into the sound if this is the case. */ #define FMOD_OPENMEMORY 0x00000800 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. If used with FMOD_CREATESAMPLE or FMOD_CREATECOMPRESSEDSAMPLE, FMOD duplicates the memory into its own buffers. Your own buffer can be freed after open. If used with FMOD_CREATESTREAM, FMOD will stream out of the buffer whose pointer you passed in. In this case, your own buffer should not be freed until you have finished with and released the stream.*/ #define FMOD_OPENMEMORY_POINT 0x10000000 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used, as sound hardware on the other platforms (ie PC) cannot access main ram. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ @@ -1024,7 +1044,7 @@ typedef enum
    Note! Using FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED (on Mac only) requires the application to be running an event loop which will allow external changes to device list to be detected by FMOD.
    - Note! The 'system' object pointer will be null for FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED and FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED callbacks. + Note! The 'system' object pointer will be null for FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED callback. [PLATFORMS] Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android @@ -1041,9 +1061,10 @@ typedef enum FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, /* Called from System::update when the enumerated list of devices has changed. */ FMOD_SYSTEM_CALLBACKTYPE_DEVICELOST, /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ - FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. (NOTE - 'system' will be NULL in this callback type.) */ + FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. */ FMOD_SYSTEM_CALLBACKTYPE_BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ FMOD_SYSTEM_CALLBACKTYPE_BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_THREADDESTROYED, /* Called directly when a thread is destroyed. */ FMOD_SYSTEM_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ FMOD_SYSTEM_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ @@ -1486,7 +1507,7 @@ typedef struct FMOD_CREATESOUNDEXINFO int inclusionlistnum; /* [w] Optional. Specify 0 to ignore. This is the number of integers contained within the inclusionlist array. */ FMOD_SOUND_PCMREADCALLBACK pcmreadcallback; /* [w] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with FMOD_OPENUSER or for capturing decoded data as FMOD reads it. */ FMOD_SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [w] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setTime or Channel::setPosition within a multi-sample sound, and for when it is opened.*/ - FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [w] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag.*/ + FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [w] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag. Also called duing seeking, when setPosition is called or a stream is restarted. */ const char *dlsname; /* [w] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on Windows it will attempt to open /windows/system32/drivers/gm.dls or /windows/system32/drivers/etc/gm.dls, on Mac it will attempt to load /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls, otherwise the MIDI will fail to open. Current DLS support is for level 1 of the specification. */ const char *encryptionkey; /* [w] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ int maxpolyphony; /* [w] Optional. Specify 0 to ignore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ @@ -1781,13 +1802,14 @@ typedef struct FMOD_ADVANCEDSETTINGS int maxXMAcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 14,836 bytes per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ int maxCELTcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 32. */ int maxVORBIScodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Vorbis codecs consume 12,000 bytes per instance and this number will determine how many Vorbis channels can be played simultaneously. Default = 32. */ + int maxAT9Codecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. AT9 codecs consume 8,720 bytes per instance and this number will determine how many AT9 channels can be played simultaneously. Default = 32. */ int maxPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16. */ int ASIONumChannels; /* [r/w] Optional. Specify 0 to ignore. Number of channels available on the ASIO device. */ char **ASIOChannelList; /* [r/w] Optional. Specify 0 to ignore. Pointer to an array of strings (number of entries defined by ASIONumChannels) with ASIO channel names. */ FMOD_SPEAKER *ASIOSpeakerList; /* [r/w] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ int max3DReverbDSPs; /* [r/w] Optional. Specify 0 to ignore. The max number of 3d reverb DSP's in the system. (NOTE: CURRENTLY DISABLED / UNUSED) */ - float HRTFMinAngle; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ - float HRTFMaxAngle; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ + float HRTFMinAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ + float HRTFMaxAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ float HRTFFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ float vol0virtualvol; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ int eventqueuesize; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads, across all threads. Default = 32. */ @@ -1798,6 +1820,9 @@ typedef struct FMOD_ADVANCEDSETTINGS unsigned int maxSpectrumWaveDataBuffers; /* [r/w] Optional. Specify 0 to ignore. Tells System::init to allocate a pool of wavedata/spectrum buffers to prevent memory fragmentation, any additional buffers will be allocated normally. */ unsigned int musicSystemCacheDelay; /* [r/w] Optional. Specify 0 to ignore. The delay the music system should allow for loading a sample from disk (in milliseconds). Default = 400 ms. */ float distanceFilterCenterFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_DISTANCE_FILTERING. The default center frequency in Hz for the distance filtering effect. Default = 1500.0. */ + unsigned int stackSizeStream; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD Stream thread in bytes. Useful for custom codecs that use excess stack. Default 49,152 (48kb) */ + unsigned int stackSizeNonBlocking; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD_NONBLOCKING loading thread. Useful for custom codecs that use excess stack. Default 65,536 (64kb) */ + unsigned int stackSizeMixer; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD mixer thread. Useful for custom dsps that use excess stack. Default 49,152 (48kb) */ } FMOD_ADVANCEDSETTINGS; @@ -2051,6 +2076,7 @@ FMOD_RESULT F_API FMOD_Sound_Set3DCustomRolloff (FMOD_SOUND *sound, FMOD_VE FMOD_RESULT F_API FMOD_Sound_Get3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR **points, int *numpoints); FMOD_RESULT F_API FMOD_Sound_SetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND *subsound); FMOD_RESULT F_API FMOD_Sound_GetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND **subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSoundParent (FMOD_SOUND *sound, FMOD_SOUND **parentsound); FMOD_RESULT F_API FMOD_Sound_SetSubSoundSentence (FMOD_SOUND *sound, int *subsoundlist, int numsubsounds); FMOD_RESULT F_API FMOD_Sound_GetName (FMOD_SOUND *sound, char *name, int namelen); FMOD_RESULT F_API FMOD_Sound_GetLength (FMOD_SOUND *sound, unsigned int *length, FMOD_TIMEUNIT lengthtype); diff --git a/libs/fmodex/include/fmod.hpp b/libs/fmodex/include/fmod.hpp index 3684e0dbcce..22564cc18c9 100644 --- a/libs/fmodex/include/fmod.hpp +++ b/libs/fmodex/include/fmod.hpp @@ -1,5 +1,5 @@ /* ========================================================================================== */ -/* FMOD Ex - C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* Use this header in conjunction with fmod.h (which contains all the constants / callbacks) */ /* to develop using C++ classes. */ @@ -215,6 +215,7 @@ namespace FMOD FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); FMOD_RESULT F_API setSubSound (int index, Sound *subsound); FMOD_RESULT F_API getSubSound (int index, Sound **subsound); + FMOD_RESULT F_API getSubSoundParent (Sound **parentsound); FMOD_RESULT F_API setSubSoundSentence (int *subsoundlist, int numsubsounds); FMOD_RESULT F_API getName (char *name, int namelen); FMOD_RESULT F_API getLength (unsigned int *length, FMOD_TIMEUNIT lengthtype); diff --git a/libs/fmodex/include/fmod_codec.h b/libs/fmodex/include/fmod_codec.h index 6198afa1b79..d1e561a6e5e 100644 --- a/libs/fmodex/include/fmod_codec.h +++ b/libs/fmodex/include/fmod_codec.h @@ -1,5 +1,5 @@ /* ==================================================================================================== */ -/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* Use this header if you are wanting to develop your own file format plugin to use with */ /* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ diff --git a/libs/fmodex/include/fmod_dsp.h b/libs/fmodex/include/fmod_dsp.h index ad980fb3404..d2ab139012c 100644 --- a/libs/fmodex/include/fmod_dsp.h +++ b/libs/fmodex/include/fmod_dsp.h @@ -1,5 +1,5 @@ /* ========================================================================================== */ -/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* Use this header if you are interested in delving deeper into the FMOD software mixing / */ /* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ @@ -109,9 +109,12 @@ typedef struct FMOD_DSP_PARAMETERDESC When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type. [REMARKS] +
    Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    Members marked with [w] mean the variable can be written to. The user can set the value.

    + IMPORTANT: The 'paramdesc' member should point to static memory, as FMOD references the data internally using the pointer provided. Do not store these parameter description structures on the stack, or in heap memory that is freed while FMOD is using it.
    +
    There are 2 different ways to change a parameter in this architecture.
    One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used.
    The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin.
    diff --git a/libs/fmodex/include/fmod_errors.h b/libs/fmodex/include/fmod_errors.h index ae715b8a100..5af0cd0dde9 100644 --- a/libs/fmodex/include/fmod_errors.h +++ b/libs/fmodex/include/fmod_errors.h @@ -1,7 +1,7 @@ /*$ preserve start $*/ /* ============================================================================================== */ -/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* Use this header if you want to store or display a string version / english explanation of */ /* the FMOD error codes. */ diff --git a/libs/fmodex/include/fmod_memoryinfo.h b/libs/fmodex/include/fmod_memoryinfo.h index e6cdab6ec2e..b4a5d704182 100644 --- a/libs/fmodex/include/fmod_memoryinfo.h +++ b/libs/fmodex/include/fmod_memoryinfo.h @@ -1,5 +1,5 @@ /* ============================================================================================= */ -/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2011. */ +/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2014. */ /* */ /* Use this header if you are interested in getting detailed information on FMOD's memory */ /* usage. See the documentation for more details. */ diff --git a/libs/fmodex/include/fmod_output.h b/libs/fmodex/include/fmod_output.h index e690efa2f05..22afddb483c 100644 --- a/libs/fmodex/include/fmod_output.h +++ b/libs/fmodex/include/fmod_output.h @@ -1,5 +1,5 @@ /* ==================================================================================================== */ -/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ +/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ /* */ /* Use this header if you are wanting to develop your own output plugin to use with */ /* FMOD's output system. With this header you can make your own output plugin that FMOD */ diff --git a/libs/fmodex/include/fmodlinux.h b/libs/fmodex/include/fmodlinux.h index 1399ca1e9c5..780bba05498 100644 --- a/libs/fmodex/include/fmodlinux.h +++ b/libs/fmodex/include/fmodlinux.h @@ -1,5 +1,5 @@ /* =========================================================================================== */ -/* FMOD Linux Specific header file. Copyright (c), Firelight Technologies Pty, Ltd. 2005-2009. */ +/* FMOD Linux Specific header file. Copyright (c), Firelight Technologies Pty, Ltd. 2005-2014. */ /* =========================================================================================== */ #ifndef _FMODLINUX_H diff --git a/libs/fmodex/lib/linux/libfmodex.so b/libs/fmodex/lib/linux/libfmodex.so old mode 100644 new mode 100755 index dcd0a5c25ea..ac9d2640b2f Binary files a/libs/fmodex/lib/linux/libfmodex.so and b/libs/fmodex/lib/linux/libfmodex.so differ diff --git a/libs/fmodex/lib/linux64/libfmodex.so b/libs/fmodex/lib/linux64/libfmodex.so old mode 100644 new mode 100755 index ca841a4f5d3..4e91f5c27f3 Binary files a/libs/fmodex/lib/linux64/libfmodex.so and b/libs/fmodex/lib/linux64/libfmodex.so differ diff --git a/libs/fmodex/lib/win_cb/libfmodex.a b/libs/fmodex/lib/msys2/libfmodex.a similarity index 79% rename from libs/fmodex/lib/win_cb/libfmodex.a rename to libs/fmodex/lib/msys2/libfmodex.a index 7b903fd02c7..d1c87ed4553 100644 Binary files a/libs/fmodex/lib/win_cb/libfmodex.a and b/libs/fmodex/lib/msys2/libfmodex.a differ diff --git a/libs/fmodex/lib/win_cb/libfmodexL.a b/libs/fmodex/lib/msys2/libfmodexL.a similarity index 80% rename from libs/fmodex/lib/win_cb/libfmodexL.a rename to libs/fmodex/lib/msys2/libfmodexL.a index 983e263475b..50c0782d872 100644 Binary files a/libs/fmodex/lib/win_cb/libfmodexL.a and b/libs/fmodex/lib/msys2/libfmodexL.a differ diff --git a/libs/fmodex/lib/osx/libfmodex.dylib b/libs/fmodex/lib/osx/libfmodex.dylib index 545c4bad9fe..4ae02bc9e12 100644 Binary files a/libs/fmodex/lib/osx/libfmodex.dylib and b/libs/fmodex/lib/osx/libfmodex.dylib differ diff --git a/libs/fmodex/lib/vs/Win32/fmodexL_vc.lib b/libs/fmodex/lib/vs/Win32/fmodexL_vc.lib index 8652e80fae0..bc602bb6f7e 100644 Binary files a/libs/fmodex/lib/vs/Win32/fmodexL_vc.lib and b/libs/fmodex/lib/vs/Win32/fmodexL_vc.lib differ diff --git a/libs/fmodex/lib/vs/Win32/fmodex_vc.lib b/libs/fmodex/lib/vs/Win32/fmodex_vc.lib index 06bb002fbad..0070e09fe56 100644 Binary files a/libs/fmodex/lib/vs/Win32/fmodex_vc.lib and b/libs/fmodex/lib/vs/Win32/fmodex_vc.lib differ diff --git a/libs/fmodex/lib/vs/x64/fmodex64_vc.lib b/libs/fmodex/lib/vs/x64/fmodex64_vc.lib index 466f3fd803f..3a12fffacc3 100644 Binary files a/libs/fmodex/lib/vs/x64/fmodex64_vc.lib and b/libs/fmodex/lib/vs/x64/fmodex64_vc.lib differ diff --git a/libs/fmodex/lib/vs/x64/fmodexL64_vc.lib b/libs/fmodex/lib/vs/x64/fmodexL64_vc.lib index a98c2da929b..0c13bf9b7b8 100644 Binary files a/libs/fmodex/lib/vs/x64/fmodexL64_vc.lib and b/libs/fmodex/lib/vs/x64/fmodexL64_vc.lib differ diff --git a/libs/fmodex/license/LICENSE.TXT b/libs/fmodex/license/LICENSE.TXT new file mode 100644 index 00000000000..77a6e17be43 --- /dev/null +++ b/libs/fmodex/license/LICENSE.TXT @@ -0,0 +1,151 @@ +FMOD, FMOD Ex, FMOD Designer and FMOD Studio are +Copyright � 2005-2015 Firelight Technologies Pty, Ltd. + +GRANT OF LICENSE +---------------- +THIS END USER LICENSE AGREEMENT GRANTS THE USER, THE RIGHT TO USE FMOD, +IN ITS LIBRARY AND TOOL FORM, IN THEIR OWN PRODUCTS, BE THEY FOR PERSONAL, +EDUCATIONAL OR COMMERCIAL USE. +THE USER MUST ADHERE TO THE LICENSING MODEL PROVIDED BY FIRELIGHT +TECHNOLOGIES, AND MUST APPLY FOR A LICENSE IF NECESSARY. THE FOLLOWING +LICENSES ARE AVAILABLE. + +FMOD NON-COMMERCIAL LICENSE +------------------------------------ +IF YOUR PRODUCT IS NOT INTENDED FOR COMMERCIAL GAIN AND DOES NOT +INCLUDE THE FMOD LIBRARY FOR RESALE, LICENSE OR OTHER COMMERCIAL +DISTRIBUTION, THEN USE OF FMOD IS FREE OF CHARGE. THERE ARE NO +LICENSE FEES FOR NON-COMMERCIAL APPLICATIONS. +THE USER MAY USE THIS EULA AS EVIDENCE OF THEIR LICENSE WITHOUT +CONTACTING FIRELIGHT TECHNOLOGIES. + +CONDITIONS/LIMITATIONS: +- WHEN USING THIS LICENSE, THE FMOD LIBRARY CANNOT BE USED FOR + RESALE OR OTHER COMMERCIAL DISTRIBUTION +- THIS LICENSE CANNOT BE USED FOR PRODUCTS WHICH DO NOT MAKE + PROFIT BUT ARE STILL COMMERCIALLY RELEASED +- THIS LICENSE CANNOT BE USED FOR COMMERCIAL SERVICES, WHERE THE + EXECUTABLE CONTAINING FMOD IS NOT SOLD, BUT THE DATA IS. +- WHEN USING FMOD, A CREDIT LINE IS REQUIRED IN EITHER DOCUMENTATION, + OR 'ON SCREEN' FORMAT (IF POSSIBLE). IT SHOULD CONTAIN AT LEAST + THE WORDS "FMOD" (OR "FMOD STUDIO" IF APPLICABLE) AND + "FIRELIGHT TECHNOLOGIES." + LOGOS ARE AVAILABLE FOR BOX OR MANUAL ART, BUT ARE NOT MANDATORY. + AN EXAMPLE CREDIT COULD BE: + + FMOD Sound System, copyright � Firelight Technologies Pty, Ltd., 1994-2015. + OR + FMOD Studio, copyright � Firelight Technologies Pty, Ltd., 1994-2015. + OR + Audio Engine supplied by FMOD by Firelight Technologies. + + NOTE THIS IN ADVANCE, AS IT MUST BE DONE BEFORE SHIPPING YOUR + PRODUCT WITH FMOD. + +FMOD FREE FOR INDIES LICENSE (FMOD STUDIO ONLY) +------------------------------------------------ +INDIE DEVELOPERS ARE CONSIDERED BY OUR LICENSING MODEL, DEVELOPERS THAT DEVELOP +A TITLE FOR UNDER $100K USD (TYPICALLY CONSIDERED AN 'INDIE' TITLE) TOTAL +BUDGET, MEANING YOUR TOTAL COSTS ARE LESS THAN $100K USD AT TIME OF SHIPPING, +YOU CAN USE FMOD FOR FREE. + +CONDITIONS/LIMITATIONS +- PLEASE WRITE TO SALES@FMOD.COM WITH THE NAME OF YOUR TITLE, RELEASE DATE + AND PLATFORMS SO WE CAN REGISTER YOU IN OUR SYSTEM. +- THERE IS NO RESTRICTION ON PLATFORM, ANY PLATFORM COMBINATION MAY BE USED. +- INCOME IS NOT RELEVANT TO THE BUDGET LEVEL, IT MUST BE EXPENSE RELATED. +- WHEN USING FMOD, A CREDIT LINE IS REQUIRED IN EITHER DOCUMENTATION, + OR 'ON SCREEN' FORMAT (IF POSSIBLE). IT SHOULD CONTAIN AT LEAST + THE WORDS FMOD STUDIO AND FIRELIGHT TECHNOLOGIES. + LOGOS ARE AVAILABLE FOR BOX OR MANUAL ART, BUT ARE NOT MANDATORY. + AN EXAMPLE CREDIT COULD BE: + + FMOD STUDIO, COPYRIGHT � FIRELIGHT TECHNOLOGIES PTY, LTD., 1994-2015. + +COMMERCIAL USAGE (FMOD EX AND FMOD STUDIO) +------------------------------------------ +IF THE PRODUCT THAT USES FMOD IS INTENDED TO GENERATE INCOME, VIA DIRECT SALES +OR INDIRECT REVENUE (SUCH AS ADVERTISING, DONATIONS, CONTRACT FEE) THEN THE +DEVELOPER MUST APPLY TO FIRELIGHT TECHNOLOGIES FOR A COMMERCIAL LICENSE (UNLESS +THE USER QUALIFIES FOR AN FMOD STUDIO 'INDIE LICENSE'). +TO APPLY FOR THIS LICENSE WRITE TO SALES@FMOD.COM WITH THE RELEVANT DETAILS. + +REDISTRIBUTION LICENSE (FMOD EX AND FMOD STUDIO) +------------------------------------------------ +IF THE USER WISHES TO REDISTRIBUTE FMOD AS PART OF AN ENGINE OR TOOL SOLUTION, +THE USER MUST APPLY TO FIRELIGHT TECHNOLOGIES TO BE GRANTED A 'REDISTRIBUTION +LICENSE'. +TO APPLY FOR THIS LICENSE WRITE TO SALES@FMOD.COM WITH THE RELEVANT DETAILS. + +WARRANTY AND LIMITATION OF LIABILITY +------------------------------------ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FMOD Uses Ogg Vorbis codec. BSD license. +----------------------------------------- +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +For Android platform code. +-------------------------- +Copyright (C) 2010 The Android Open Source Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/libs/freetype/include/freetype2/config/ftconfig.h b/libs/freetype/include/freetype2/config/ftconfig.h index d98a3116bb0..22d70fd35be 100644 --- a/libs/freetype/include/freetype2/config/ftconfig.h +++ b/libs/freetype/include/freetype2/config/ftconfig.h @@ -266,7 +266,16 @@ FT_BEGIN_HEADER #define FT_INT64 long #define FT_UINT64 unsigned long -#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + /*************************************************************************/ + /* */ + /* A 64-bit data type may create compilation problems if you compile */ + /* in strict ANSI mode. To avoid them, we disable other 64-bit data */ + /* types if __STDC__ is defined. You can however ignore this rule */ + /* by defining the FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ + /* */ +#elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#if defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ /* this compiler provides the __int64 type */ #define FT_LONG64 @@ -300,27 +309,9 @@ FT_BEGIN_HEADER #define FT_INT64 long long int #define FT_UINT64 unsigned long long int -#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ - - - /*************************************************************************/ - /* */ - /* A 64-bit data type will create compilation problems if you compile */ - /* in strict ANSI mode. To avoid them, we disable its use if __STDC__ */ - /* is defined. You can however ignore this rule by defining the */ - /* FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ - /* */ -#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) - -#ifdef __STDC__ - - /* undefine the 64-bit macros in strict ANSI compilation mode */ -#undef FT_LONG64 -#undef FT_INT64 - -#endif /* __STDC__ */ +#endif /* _MSC_VER */ -#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */ +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ #ifdef FT_LONG64 typedef FT_INT64 FT_Int64; @@ -333,219 +324,6 @@ FT_BEGIN_HEADER #define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT -#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER - /* Provide assembler fragments for performance-critical functions. */ - /* These must be defined `static __inline__' with GCC. */ - -#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ - -#define FT_MULFIX_ASSEMBLER FT_MulFix_arm - - /* documentation is in freetype.h */ - - static __inline FT_Int32 - FT_MulFix_arm( FT_Int32 a, - FT_Int32 b ) - { - register FT_Int32 t, t2; - - - __asm - { - smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ - mov a, t, asr #31 /* a = (hi >> 31) */ - add a, a, #0x8000 /* a += 0x8000 */ - adds t2, t2, a /* t2 += a */ - adc t, t, #0 /* t += carry */ - mov a, t2, lsr #16 /* a = t2 >> 16 */ - orr a, a, t, lsl #16 /* a |= t << 16 */ - } - return a; - } - -#endif /* __CC_ARM || __ARMCC__ */ - - -#ifdef __GNUC__ - -#if defined( __arm__ ) && \ - ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ - !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_arm - - /* documentation is in freetype.h */ - - static __inline__ FT_Int32 - FT_MulFix_arm( FT_Int32 a, - FT_Int32 b ) - { - register FT_Int32 t, t2; - - - __asm__ __volatile__ ( - "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ - "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ -#if defined( __clang__ ) && defined( __thumb2__ ) - "add.w %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ -#else - "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ -#endif - "adds %1, %1, %0\n\t" /* %1 += %0 */ - "adc %2, %2, #0\n\t" /* %2 += carry */ - "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ - "orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ - : "=r"(a), "=&r"(t2), "=&r"(t) - : "r"(a), "r"(b) - : "cc" ); - return a; - } - -#endif /* __arm__ && */ - /* ( __thumb2__ || !__thumb__ ) && */ - /* !( __CC_ARM || __ARMCC__ ) */ - - -#if defined( __i386__ ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 - - /* documentation is in freetype.h */ - - static __inline__ FT_Int32 - FT_MulFix_i386( FT_Int32 a, - FT_Int32 b ) - { - register FT_Int32 result; - - - __asm__ __volatile__ ( - "imul %%edx\n" - "movl %%edx, %%ecx\n" - "sarl $31, %%ecx\n" - "addl $0x8000, %%ecx\n" - "addl %%ecx, %%eax\n" - "adcl $0, %%edx\n" - "shrl $16, %%eax\n" - "shll $16, %%edx\n" - "addl %%edx, %%eax\n" - : "=a"(result), "=d"(b) - : "a"(a), "d"(b) - : "%ecx", "cc" ); - return result; - } - -#endif /* i386 */ - -#endif /* __GNUC__ */ - - -#ifdef _MSC_VER /* Visual C++ */ - -#ifdef _M_IX86 - -#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 - - /* documentation is in freetype.h */ - - static __inline FT_Int32 - FT_MulFix_i386( FT_Int32 a, - FT_Int32 b ) - { - register FT_Int32 result; - - __asm - { - mov eax, a - mov edx, b - imul edx - mov ecx, edx - sar ecx, 31 - add ecx, 8000h - add eax, ecx - adc edx, 0 - shr eax, 16 - shl edx, 16 - add eax, edx - mov result, eax - } - return result; - } - -#endif /* _M_IX86 */ - -#endif /* _MSC_VER */ - - -#if defined( __GNUC__ ) && defined( __x86_64__ ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 - - static __inline__ FT_Int32 - FT_MulFix_x86_64( FT_Int32 a, - FT_Int32 b ) - { - /* Temporarily disable the warning that C90 doesn't support */ - /* `long long'. */ -#if ( __GNUC__ > 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 6 ) ) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wlong-long" -#endif - -#if 1 - /* Technically not an assembly fragment, but GCC does a really good */ - /* job at inlining it and generating good machine code for it. */ - long long ret, tmp; - - - ret = (long long)a * b; - tmp = ret >> 63; - ret += 0x8000 + tmp; - - return (FT_Int32)( ret >> 16 ); -#else - - /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ - /* code from the lines below. The main issue is that `wide_a' is not */ - /* properly initialized by sign-extending `a'. Instead, the generated */ - /* machine code assumes that the register that contains `a' on input */ - /* can be used directly as a 64-bit value, which is wrong most of the */ - /* time. */ - long long wide_a = (long long)a; - long long wide_b = (long long)b; - long long result; - - - __asm__ __volatile__ ( - "imul %2, %1\n" - "mov %1, %0\n" - "sar $63, %0\n" - "lea 0x8000(%1, %0), %0\n" - "sar $16, %0\n" - : "=&r"(result), "=&r"(wide_a) - : "r"(wide_b) - : "cc" ); - - return (FT_Int32)result; -#endif - -#if ( __GNUC__ > 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 6 ) ) -#pragma GCC diagnostic pop -#endif - } - -#endif /* __GNUC__ && __x86_64__ */ - -#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ - - -#ifdef FT_CONFIG_OPTION_INLINE_MULFIX -#ifdef FT_MULFIX_ASSEMBLER -#define FT_MULFIX_INLINED FT_MULFIX_ASSEMBLER -#endif -#endif - - #ifdef FT_MAKE_OPTION_SINGLE_OBJECT #define FT_LOCAL( x ) static x diff --git a/libs/freetype/include/freetype2/config/ftoption.h b/libs/freetype/include/freetype2/config/ftoption.h index 5b11f0e0305..2b0b67e7af3 100644 --- a/libs/freetype/include/freetype2/config/ftoption.h +++ b/libs/freetype/include/freetype2/config/ftoption.h @@ -4,7 +4,7 @@ /* */ /* User-selectable configuration macros (specification only). */ /* */ -/* Copyright 1996-2013 by */ +/* Copyright 1996-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -61,7 +61,7 @@ FT_BEGIN_HEADER /* that are statically linked to the library at compile time. By */ /* default, this file is . */ /* */ - /* We highly recommend using the third method whenever possible. */ + /* We highly recommend using the third method whenever possible. */ /* */ /*************************************************************************/ @@ -216,7 +216,7 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ - /* PNG bitmap support. */ + /* PNG bitmap support. */ /* */ /* FreeType now handles loading color bitmap glyphs in the PNG format. */ /* This requires help from the external libpng library. Uncompressed */ @@ -230,7 +230,7 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ - /* HarfBuzz support. */ + /* HarfBuzz support. */ /* */ /* FreeType uses the HarfBuzz library to improve auto-hinting of */ /* OpenType fonts. If available, many glyphs not directly addressable */ @@ -771,6 +771,30 @@ FT_BEGIN_HEADER /*************************************************************************/ + /*************************************************************************/ + /* */ + /* Using CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4} it is */ + /* possible to set up the default values of the four control points that */ + /* define the stem darkening behaviour of the (new) CFF engine. For */ + /* more details please read the documentation of the */ + /* `darkening-parameters' property of the cff driver module (file */ + /* `ftcffdrv.h'), which allows the control at run-time. */ + /* */ + /* Do *not* undefine these macros! */ + /* */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + /*************************************************************************/ /* */ /* CFF_CONFIG_OPTION_OLD_ENGINE controls whether the pre-Adobe CFF */ @@ -820,8 +844,8 @@ FT_BEGIN_HEADER /* - * This macro is obsolete. Support has been removed in FreeType - * version 2.5. + * This macro is obsolete. Support has been removed in FreeType + * version 2.5. */ /* #define FT_CONFIG_OPTION_OLD_INTERNALS */ @@ -837,6 +861,35 @@ FT_BEGIN_HEADER #define TT_USE_BYTECODE_INTERPRETER #endif + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set' in file `cffdrivr.c'. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + FT_END_HEADER diff --git a/libs/freetype/include/freetype2/freetype.h b/libs/freetype/include/freetype2/freetype.h index fb62b625fe8..27fd44bfc23 100644 --- a/libs/freetype/include/freetype2/freetype.h +++ b/libs/freetype/include/freetype2/freetype.h @@ -113,7 +113,8 @@ FT_BEGIN_HEADER /* The FreeType~2 base font interface. */ /* */ /* */ - /* This section describes the public high-level API of FreeType~2. */ + /* This section describes the most important public high-level API */ + /* functions of FreeType~2. */ /* */ /* */ /* FT_Library */ @@ -122,6 +123,7 @@ FT_BEGIN_HEADER /* FT_GlyphSlot */ /* FT_CharMap */ /* FT_Encoding */ + /* FT_ENC_TAG */ /* */ /* FT_FaceRec */ /* */ @@ -138,8 +140,22 @@ FT_BEGIN_HEADER /* FT_FACE_FLAG_MULTIPLE_MASTERS */ /* FT_FACE_FLAG_GLYPH_NAMES */ /* FT_FACE_FLAG_EXTERNAL_STREAM */ - /* FT_FACE_FLAG_FAST_GLYPHS */ /* FT_FACE_FLAG_HINTER */ + /* FT_FACE_FLAG_TRICKY */ + /* */ + /* FT_HAS_HORIZONTAL */ + /* FT_HAS_VERTICAL */ + /* FT_HAS_KERNING */ + /* FT_HAS_FIXED_SIZES */ + /* FT_HAS_GLYPH_NAMES */ + /* FT_HAS_MULTIPLE_MASTERS */ + /* FT_HAS_COLOR */ + /* */ + /* FT_IS_SFNT */ + /* FT_IS_SCALABLE */ + /* FT_IS_FIXED_WIDTH */ + /* FT_IS_CID_KEYED */ + /* FT_IS_TRICKY */ /* */ /* FT_STYLE_FLAG_BOLD */ /* FT_STYLE_FLAG_ITALIC */ @@ -158,6 +174,7 @@ FT_BEGIN_HEADER /* */ /* FT_New_Face */ /* FT_Done_Face */ + /* FT_Reference_Face */ /* FT_New_Memory_Face */ /* FT_Open_Face */ /* FT_Open_Args */ @@ -170,10 +187,13 @@ FT_BEGIN_HEADER /* FT_Request_Size */ /* FT_Select_Size */ /* FT_Size_Request_Type */ + /* FT_Size_RequestRec */ /* FT_Size_Request */ /* FT_Set_Transform */ /* FT_Load_Glyph */ /* FT_Get_Char_Index */ + /* FT_Get_First_Char */ + /* FT_Get_Next_Char */ /* FT_Get_Name_Index */ /* FT_Load_Char */ /* */ @@ -190,11 +210,11 @@ FT_BEGIN_HEADER /* FT_LOAD_NO_SCALE */ /* FT_LOAD_NO_HINTING */ /* FT_LOAD_NO_BITMAP */ - /* FT_LOAD_CROP_BITMAP */ + /* FT_LOAD_NO_AUTOHINT */ + /* FT_LOAD_COLOR */ /* */ /* FT_LOAD_VERTICAL_LAYOUT */ /* FT_LOAD_IGNORE_TRANSFORM */ - /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ /* FT_LOAD_FORCE_AUTOHINT */ /* FT_LOAD_NO_RECURSE */ /* FT_LOAD_PEDANTIC */ @@ -205,6 +225,8 @@ FT_BEGIN_HEADER /* FT_LOAD_TARGET_LCD */ /* FT_LOAD_TARGET_LCD_V */ /* */ + /* FT_LOAD_TARGET_MODE */ + /* */ /* FT_Render_Glyph */ /* FT_Render_Mode */ /* FT_Get_Kerning */ @@ -218,14 +240,22 @@ FT_BEGIN_HEADER /* FT_Set_Charmap */ /* FT_Get_Charmap_Index */ /* */ - /* FT_FSTYPE_INSTALLABLE_EMBEDDING */ - /* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING */ - /* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING */ - /* FT_FSTYPE_EDITABLE_EMBEDDING */ - /* FT_FSTYPE_NO_SUBSETTING */ - /* FT_FSTYPE_BITMAP_EMBEDDING_ONLY */ - /* */ /* FT_Get_FSType_Flags */ + /* FT_Get_SubGlyph_Info */ + /* */ + /* FT_Face_Internal */ + /* FT_Size_Internal */ + /* FT_Slot_Internal */ + /* */ + /* FT_FACE_FLAG_XXX */ + /* FT_STYLE_FLAG_XXX */ + /* FT_OPEN_XXX */ + /* FT_LOAD_XXX */ + /* FT_LOAD_TARGET_XXX */ + /* FT_SUBGLYPH_FLAG_XXX */ + /* FT_FSTYPE_XXX */ + /* */ + /* FT_HAS_FAST_GLYPHS */ /* */ /*************************************************************************/ @@ -376,6 +406,13 @@ FT_BEGIN_HEADER typedef struct FT_LibraryRec_ *FT_Library; + /*************************************************************************/ + /* */ + /*
    */ + /* module_management */ + /* */ + /*************************************************************************/ + /*************************************************************************/ /* */ /* */ @@ -415,6 +452,13 @@ FT_BEGIN_HEADER typedef struct FT_RendererRec_* FT_Renderer; + /*************************************************************************/ + /* */ + /*
    */ + /* base_interface */ + /* */ + /*************************************************************************/ + /*************************************************************************/ /* */ /* */ @@ -727,15 +771,8 @@ FT_BEGIN_HEADER } FT_Encoding; - /*************************************************************************/ - /* */ - /* */ - /* ft_encoding_xxx */ - /* */ - /* */ - /* These constants are deprecated; use the corresponding @FT_Encoding */ - /* values instead. */ - /* */ + /* these constants are deprecated; use the corresponding `FT_Encoding' */ + /* values instead */ #define ft_encoding_none FT_ENCODING_NONE #define ft_encoding_unicode FT_ENCODING_UNICODE #define ft_encoding_symbol FT_ENCODING_MS_SYMBOL @@ -1570,15 +1607,15 @@ FT_BEGIN_HEADER /* change between calls of @FT_Load_Glyph and a */ /* few other functions. */ /* */ - /* bitmap_left :: This is the bitmap's left bearing expressed */ - /* in integer pixels. Of course, this is only */ - /* valid if the format is */ - /* @FT_GLYPH_FORMAT_BITMAP. */ + /* bitmap_left :: The bitmap's left bearing expressed in */ + /* integer pixels. Only valid if the format is */ + /* @FT_GLYPH_FORMAT_BITMAP, this is, if the */ + /* glyph slot contains a bitmap. */ /* */ - /* bitmap_top :: This is the bitmap's top bearing expressed in */ - /* integer pixels. Remember that this is the */ - /* distance from the baseline to the top-most */ - /* glyph scanline, upwards y~coordinates being */ + /* bitmap_top :: The bitmap's top bearing expressed in integer */ + /* pixels. Remember that this is the distance */ + /* from the baseline to the top-most glyph */ + /* scanline, upwards y~coordinates being */ /* *positive*. */ /* */ /* outline :: The outline descriptor for the current glyph */ @@ -1592,7 +1629,6 @@ FT_BEGIN_HEADER /* This field is only valid for the composite */ /* glyph format that should normally only be */ /* loaded with the @FT_LOAD_NO_RECURSE flag. */ - /* For now this is internal to FreeType. */ /* */ /* subglyphs :: An array of subglyph descriptors for */ /* composite glyphs. There are `num_subglyphs' */ @@ -1783,16 +1819,6 @@ FT_BEGIN_HEADER /* */ /* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */ /* */ - /* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */ - /* */ - /* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */ - /* */ - /* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */ - /* */ - /* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */ - /* */ - /* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */ - /* */ /* */ /* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */ /* flags are mutually exclusive. */ @@ -1803,11 +1829,14 @@ FT_BEGIN_HEADER #define FT_OPEN_DRIVER 0x8 #define FT_OPEN_PARAMS 0x10 -#define ft_open_memory FT_OPEN_MEMORY /* deprecated */ -#define ft_open_stream FT_OPEN_STREAM /* deprecated */ -#define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */ -#define ft_open_driver FT_OPEN_DRIVER /* deprecated */ -#define ft_open_params FT_OPEN_PARAMS /* deprecated */ + + /* these constants are deprecated; use the corresponding `FT_OPEN_XXX' */ + /* values instead */ +#define ft_open_memory FT_OPEN_MEMORY +#define ft_open_stream FT_OPEN_STREAM +#define ft_open_pathname FT_OPEN_PATHNAME +#define ft_open_driver FT_OPEN_DRIVER +#define ft_open_params FT_OPEN_PARAMS /*************************************************************************/ @@ -1872,22 +1901,22 @@ FT_BEGIN_HEADER /* The stream type is determined by the contents of `flags' that */ /* are tested in the following order by @FT_Open_Face: */ /* */ - /* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */ + /* If the @FT_OPEN_MEMORY bit is set, assume that this is a */ /* memory file of `memory_size' bytes, located at `memory_address'. */ /* The data are are not copied, and the client is responsible for */ /* releasing and destroying them _after_ the corresponding call to */ /* @FT_Done_Face. */ /* */ - /* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */ + /* Otherwise, if the @FT_OPEN_STREAM bit is set, assume that a */ /* custom input stream `stream' is used. */ /* */ - /* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */ + /* Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this */ /* is a normal file and use `pathname' to open it. */ /* */ - /* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */ + /* If the @FT_OPEN_DRIVER bit is set, @FT_Open_Face only tries to */ /* open the file with the driver whose handler is in `driver'. */ /* */ - /* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */ + /* If the @FT_OPEN_PARAMS bit is set, the parameters given by */ /* `num_params' and `params' is used. They are ignored otherwise. */ /* */ /* Ideally, both the `pathname' and `params' fields should be tagged */ @@ -2541,11 +2570,6 @@ FT_BEGIN_HEADER * Indicates that the auto-hinter is preferred over the font's native * hinter. See also the note below. * - * FT_LOAD_CROP_BITMAP :: - * Indicates that the font driver should crop the loaded bitmap glyph - * (i.e., remove all space around its black bits). Not all drivers - * implement this. - * * FT_LOAD_PEDANTIC :: * Indicates that the font driver should perform pedantic verifications * during glyph loading. This is mostly used to detect broken glyphs @@ -2556,18 +2580,12 @@ FT_BEGIN_HEADER * result in partially hinted or distorted glyphs in case a glyph's * bytecode is buggy. * - * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: - * Ignored. Deprecated. - * * FT_LOAD_NO_RECURSE :: - * This flag is only used internally. It merely indicates that the - * font driver should not load composite glyphs recursively. Instead, - * it should set the `num_subglyph' and `subglyphs' values of the - * glyph slot accordingly, and set `glyph->format' to - * @FT_GLYPH_FORMAT_COMPOSITE. - * - * The description of sub-glyphs is not available to client - * applications for now. + * Indicate that the font driver should not load composite glyphs + * recursively. Instead, it should set the `num_subglyph' and + * `subglyphs' values of the glyph slot accordingly, and set + * `glyph->format' to @FT_GLYPH_FORMAT_COMPOSITE. The description of + * subglyphs can then be accessed with @FT_Get_SubGlyph_Info. * * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. * @@ -2600,6 +2618,12 @@ FT_BEGIN_HEADER * bitmaps transparently. Those bitmaps will be in the * @FT_PIXEL_MODE_GRAY format. * + * FT_LOAD_CROP_BITMAP :: + * Ignored. Deprecated. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Ignored. Deprecated. + * * @note: * By default, hinting is enabled and the font's native hinter (see * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can @@ -2836,19 +2860,8 @@ FT_BEGIN_HEADER } FT_Render_Mode; - /*************************************************************************/ - /* */ - /* */ - /* ft_render_mode_xxx */ - /* */ - /* */ - /* These constants are deprecated. Use the corresponding */ - /* @FT_Render_Mode values instead. */ - /* */ - /* */ - /* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */ - /* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */ - /* */ + /* these constants are deprecated; use the corresponding */ + /* `FT_Render_Mode' values instead */ #define ft_render_mode_normal FT_RENDER_MODE_NORMAL #define ft_render_mode_mono FT_RENDER_MODE_MONO @@ -2912,39 +2925,10 @@ FT_BEGIN_HEADER } FT_Kerning_Mode; - /*************************************************************************/ - /* */ - /* */ - /* ft_kerning_default */ - /* */ - /* */ - /* This constant is deprecated. Please use @FT_KERNING_DEFAULT */ - /* instead. */ - /* */ + /* these constants are deprecated; use the corresponding */ + /* `FT_Kerning_Mode' values instead */ #define ft_kerning_default FT_KERNING_DEFAULT - - - /*************************************************************************/ - /* */ - /* */ - /* ft_kerning_unfitted */ - /* */ - /* */ - /* This constant is deprecated. Please use @FT_KERNING_UNFITTED */ - /* instead. */ - /* */ #define ft_kerning_unfitted FT_KERNING_UNFITTED - - - /*************************************************************************/ - /* */ - /* */ - /* ft_kerning_unscaled */ - /* */ - /* */ - /* This constant is deprecated. Please use @FT_KERNING_UNSCALED */ - /* instead. */ - /* */ #define ft_kerning_unscaled FT_KERNING_UNSCALED @@ -3065,9 +3049,8 @@ FT_BEGIN_HEADER /* glyph index~0 always corresponds to the `missing glyph' (called */ /* `.notdef'). */ /* */ - /* This function is not compiled within the library if the config */ - /* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */ - /* `ftoptions.h'. */ + /* This function always returns an error if the config macro */ + /* `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is not defined in `ftoptions.h'. */ /* */ FT_EXPORT( FT_Error ) FT_Get_Glyph_Name( FT_Face face, @@ -3515,8 +3498,8 @@ FT_BEGIN_HEADER /* */ /* http://www.unicode.org/reports/tr37/ */ /* */ - /* To date (November 2012), the character with the most variants is */ - /* U+9089, having 31 such IVS. */ + /* To date (November 2014), the character with the most variants is */ + /* U+9089, having 32 such IVS. */ /* */ /* Adobe and MS decided to support IVS with a new cmap subtable */ /* (format~14). It is an odd subtable because it is not a mapping of */ @@ -3767,12 +3750,6 @@ FT_BEGIN_HEADER FT_Long c ); - /* */ - - /* The following #if 0 ... #endif is for the documentation formatter, */ - /* hiding the internal `FT_MULFIX_INLINED' macro. */ - -#if 0 /*************************************************************************/ /* */ /* */ @@ -3806,17 +3783,6 @@ FT_BEGIN_HEADER FT_MulFix( FT_Long a, FT_Long b ); - /* */ -#endif - -#ifdef FT_MULFIX_INLINED -#define FT_MulFix( a, b ) FT_MULFIX_INLINED( a, b ) -#else - FT_EXPORT( FT_Long ) - FT_MulFix( FT_Long a, - FT_Long b ); -#endif - /*************************************************************************/ /* */ @@ -3829,18 +3795,12 @@ FT_BEGIN_HEADER /* used to divide a given value by a 16.16 fixed-point factor. */ /* */ /* */ - /* a :: The first multiplier. */ - /* b :: The second multiplier. Use a 16.16 factor here whenever */ - /* possible (see note below). */ + /* a :: The numerator. */ + /* b :: The denominator. Use a 16.16 factor here. */ /* */ /* */ /* The result of `(a*0x10000)/b'. */ /* */ - /* */ - /* The optimization for FT_DivFix() is simple: If (a~<<~16) fits in */ - /* 32~bits, then the division is computed directly. Otherwise, we */ - /* use a specialized version of @FT_MulDiv. */ - /* */ FT_EXPORT( FT_Long ) FT_DivFix( FT_Long a, FT_Long b ); @@ -3940,6 +3900,18 @@ FT_BEGIN_HEADER /* even a new release of FreeType with only documentation changes */ /* increases the version number. */ /* */ + /* */ + /* FT_Library_Version */ + /* */ + /* FREETYPE_MAJOR */ + /* FREETYPE_MINOR */ + /* FREETYPE_PATCH */ + /* */ + /* FT_Face_CheckTrueTypePatents */ + /* FT_Face_SetUnpatentedHinting */ + /* */ + /* FREETYPE_XXX */ + /* */ /*************************************************************************/ @@ -3965,7 +3937,7 @@ FT_BEGIN_HEADER */ #define FREETYPE_MAJOR 2 #define FREETYPE_MINOR 5 -#define FREETYPE_PATCH 3 +#define FREETYPE_PATCH 5 /*************************************************************************/ diff --git a/libs/freetype/include/freetype2/ftadvanc.h b/libs/freetype/include/freetype2/ftadvanc.h index 8f7e2fce5ed..955f93fa16c 100644 --- a/libs/freetype/include/freetype2/ftadvanc.h +++ b/libs/freetype/include/freetype2/ftadvanc.h @@ -4,7 +4,7 @@ /* */ /* Quick computation of advance widths (specification only). */ /* */ -/* Copyright 2008, 2013 by */ +/* Copyright 2008, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -48,6 +48,11 @@ FT_BEGIN_HEADER * @description: * This section contains functions to quickly extract advance values * without handling glyph outlines, if possible. + * + * @order: + * FT_Get_Advance + * FT_Get_Advances + * */ @@ -171,7 +176,7 @@ FT_BEGIN_HEADER FT_Int32 load_flags, FT_Fixed *padvances ); -/* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftautoh.h b/libs/freetype/include/freetype2/ftautoh.h index 936791e7263..59191abbfe4 100644 --- a/libs/freetype/include/freetype2/ftautoh.h +++ b/libs/freetype/include/freetype2/ftautoh.h @@ -245,12 +245,12 @@ FT_BEGIN_HEADER * The data exchange structure for the @glyph-to-script-map property. * */ - typedef struct FT_Prop_GlyphToScriptMap_ - { - FT_Face face; - FT_Byte* map; + typedef struct FT_Prop_GlyphToScriptMap_ + { + FT_Face face; + FT_Byte* map; - } FT_Prop_GlyphToScriptMap; + } FT_Prop_GlyphToScriptMap; /************************************************************************** @@ -384,15 +384,15 @@ FT_BEGIN_HEADER * The data exchange structure for the @increase-x-height property. * */ - typedef struct FT_Prop_IncreaseXHeight_ - { - FT_Face face; - FT_UInt limit; + typedef struct FT_Prop_IncreaseXHeight_ + { + FT_Face face; + FT_UInt limit; - } FT_Prop_IncreaseXHeight; + } FT_Prop_IncreaseXHeight; + /* */ - /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftbbox.h b/libs/freetype/include/freetype2/ftbbox.h index 8938841a622..d6800e240fc 100644 --- a/libs/freetype/include/freetype2/ftbbox.h +++ b/libs/freetype/include/freetype2/ftbbox.h @@ -85,7 +85,6 @@ FT_BEGIN_HEADER FT_Outline_Get_BBox( FT_Outline* outline, FT_BBox *abbox ); - /* */ diff --git a/libs/freetype/include/freetype2/ftbdf.h b/libs/freetype/include/freetype2/ftbdf.h index 8b3c41115cb..6d262e4141a 100644 --- a/libs/freetype/include/freetype2/ftbdf.h +++ b/libs/freetype/include/freetype2/ftbdf.h @@ -53,7 +53,7 @@ FT_BEGIN_HEADER /********************************************************************** * * @enum: - * FT_PropertyType + * BDF_PropertyType * * @description: * A list of BDF property types. @@ -200,7 +200,7 @@ FT_BEGIN_HEADER const char* prop_name, BDF_PropertyRec *aproperty ); - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftbitmap.h b/libs/freetype/include/freetype2/ftbitmap.h index 7dbf5ba3fe6..eae716904b4 100644 --- a/libs/freetype/include/freetype2/ftbitmap.h +++ b/libs/freetype/include/freetype2/ftbitmap.h @@ -4,7 +4,7 @@ /* */ /* FreeType utility functions for bitmaps (specification). */ /* */ -/* Copyright 2004-2006, 2008, 2013 by */ +/* Copyright 2004-2006, 2008, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -45,7 +45,9 @@ FT_BEGIN_HEADER /* Handling FT_Bitmap objects. */ /* */ /* */ - /* This section contains functions for converting FT_Bitmap objects. */ + /* This section contains functions for handling @FT_Bitmap objects. */ + /* Note that none of the functions changes the bitmap's `flow' (as */ + /* indicated by the sign of the `pitch' field in `FT_Bitmap'). */ /* */ /*************************************************************************/ @@ -122,6 +124,9 @@ FT_BEGIN_HEADER /* If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, */ /* you should call @FT_GlyphSlot_Own_Bitmap on the slot first. */ /* */ + /* Bitmaps in @FT_PIXEL_MODE_GRAY2 and @FT_PIXEL_MODE_GRAY@ format */ + /* are converted to @FT_PIXEL_MODE_GRAY format (i.e., 8bpp). */ + /* */ FT_EXPORT( FT_Error ) FT_Bitmap_Embolden( FT_Library library, FT_Bitmap* bitmap, diff --git a/libs/freetype/include/freetype2/ftbzip2.h b/libs/freetype/include/freetype2/ftbzip2.h index 1bf81b15e89..4dce161fd69 100644 --- a/libs/freetype/include/freetype2/ftbzip2.h +++ b/libs/freetype/include/freetype2/ftbzip2.h @@ -91,7 +91,7 @@ FT_BEGIN_HEADER FT_Stream_OpenBzip2( FT_Stream stream, FT_Stream source ); - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftcache.h b/libs/freetype/include/freetype2/ftcache.h index a5d7100a3fb..a30e925cc56 100644 --- a/libs/freetype/include/freetype2/ftcache.h +++ b/libs/freetype/include/freetype2/ftcache.h @@ -4,7 +4,7 @@ /* */ /* FreeType Cache subsystem (specification). */ /* */ -/* Copyright 1996-2008, 2010, 2013 by */ +/* Copyright 1996-2008, 2010, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -209,10 +209,10 @@ FT_BEGIN_HEADER typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id, FT_Library library, - FT_Pointer request_data, + FT_Pointer req_data, FT_Face* aface ); - /* */ + /* */ /*************************************************************************/ @@ -1046,8 +1046,8 @@ FT_BEGIN_HEADER FTC_SBit *sbit, FTC_Node *anode ); + /* */ - /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftcffdrv.h b/libs/freetype/include/freetype2/ftcffdrv.h index e4d039d0214..f7031bc8832 100644 --- a/libs/freetype/include/freetype2/ftcffdrv.h +++ b/libs/freetype/include/freetype2/ftcffdrv.h @@ -4,7 +4,7 @@ /* */ /* FreeType API for controlling the CFF driver (specification only). */ /* */ -/* Copyright 2013 by */ +/* Copyright 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -108,6 +108,12 @@ FT_BEGIN_HEADER * in one of four ways, top edge up or down, bottom edge up or down. * Unless there are conflicting hstems, the smallest movement is taken * to minimize distortion. + * + * @order: + * hinting-engine + * no-stem-darkening + * darkening-parameters + * */ @@ -212,9 +218,11 @@ FT_BEGIN_HEADER * stem width >= 2.333px: darkening amount = 0px * } * - * and piecewise linear in-between. Using the `darkening-parameters' - * property, these four control points can be changed, as the following - * example demonstrates. + * and piecewise linear in-between. At configuration time, these four + * control points can be set with the macro + * `CFF_CONFIG_OPTION_DARKENING_PARAMETERS'. At runtime, the control + * points can be changed using the `darkening-parameters' property, as + * the following example demonstrates. * * { * FT_Library library; @@ -242,8 +250,8 @@ FT_BEGIN_HEADER * */ + /* */ - /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftcid.h b/libs/freetype/include/freetype2/ftcid.h index 203a30caf85..17550d87b5c 100644 --- a/libs/freetype/include/freetype2/ftcid.h +++ b/libs/freetype/include/freetype2/ftcid.h @@ -156,7 +156,8 @@ FT_BEGIN_HEADER FT_UInt glyph_index, FT_UInt *cid ); - /* */ + /* */ + FT_END_HEADER diff --git a/libs/freetype/include/freetype2/fterrdef.h b/libs/freetype/include/freetype2/fterrdef.h index 76c7b9e36fc..99b2fadec6d 100644 --- a/libs/freetype/include/freetype2/fterrdef.h +++ b/libs/freetype/include/freetype2/fterrdef.h @@ -31,218 +31,218 @@ /* generic errors */ - FT_NOERRORDEF_( Ok, 0x00, \ + FT_NOERRORDEF_( Ok, 0x00, "no error" ) - FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, "cannot open resource" ) - FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + FT_ERRORDEF_( Unknown_File_Format, 0x02, "unknown file format" ) - FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + FT_ERRORDEF_( Invalid_File_Format, 0x03, "broken file" ) - FT_ERRORDEF_( Invalid_Version, 0x04, \ + FT_ERRORDEF_( Invalid_Version, 0x04, "invalid FreeType version" ) - FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + FT_ERRORDEF_( Lower_Module_Version, 0x05, "module version is too low" ) - FT_ERRORDEF_( Invalid_Argument, 0x06, \ + FT_ERRORDEF_( Invalid_Argument, 0x06, "invalid argument" ) - FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + FT_ERRORDEF_( Unimplemented_Feature, 0x07, "unimplemented feature" ) - FT_ERRORDEF_( Invalid_Table, 0x08, \ + FT_ERRORDEF_( Invalid_Table, 0x08, "broken table" ) - FT_ERRORDEF_( Invalid_Offset, 0x09, \ + FT_ERRORDEF_( Invalid_Offset, 0x09, "broken offset within table" ) - FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + FT_ERRORDEF_( Array_Too_Large, 0x0A, "array allocation size too large" ) - FT_ERRORDEF_( Missing_Module, 0x0B, \ + FT_ERRORDEF_( Missing_Module, 0x0B, "missing module" ) - FT_ERRORDEF_( Missing_Property, 0x0C, \ + FT_ERRORDEF_( Missing_Property, 0x0C, "missing property" ) /* glyph/character errors */ - FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, "invalid glyph index" ) - FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + FT_ERRORDEF_( Invalid_Character_Code, 0x11, "invalid character code" ) - FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, "unsupported glyph image format" ) - FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, "cannot render this glyph format" ) - FT_ERRORDEF_( Invalid_Outline, 0x14, \ + FT_ERRORDEF_( Invalid_Outline, 0x14, "invalid outline" ) - FT_ERRORDEF_( Invalid_Composite, 0x15, \ + FT_ERRORDEF_( Invalid_Composite, 0x15, "invalid composite glyph" ) - FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + FT_ERRORDEF_( Too_Many_Hints, 0x16, "too many hints" ) - FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, "invalid pixel size" ) /* handle errors */ - FT_ERRORDEF_( Invalid_Handle, 0x20, \ + FT_ERRORDEF_( Invalid_Handle, 0x20, "invalid object handle" ) - FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, "invalid library handle" ) - FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, "invalid module handle" ) - FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, "invalid face handle" ) - FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, "invalid size handle" ) - FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, "invalid glyph slot handle" ) - FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, "invalid charmap handle" ) - FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, "invalid cache manager handle" ) - FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, "invalid stream handle" ) /* driver errors */ - FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, "too many modules" ) - FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + FT_ERRORDEF_( Too_Many_Extensions, 0x31, "too many extensions" ) /* memory errors */ - FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + FT_ERRORDEF_( Out_Of_Memory, 0x40, "out of memory" ) - FT_ERRORDEF_( Unlisted_Object, 0x41, \ + FT_ERRORDEF_( Unlisted_Object, 0x41, "unlisted object" ) /* stream errors */ - FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, "cannot open stream" ) - FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, "invalid stream seek" ) - FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, "invalid stream skip" ) - FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, "invalid stream read" ) - FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, "invalid stream operation" ) - FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, "invalid frame operation" ) - FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + FT_ERRORDEF_( Nested_Frame_Access, 0x57, "nested frame access" ) - FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, "invalid frame read" ) /* raster errors */ - FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, "raster uninitialized" ) - FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + FT_ERRORDEF_( Raster_Corrupted, 0x61, "raster corrupted" ) - FT_ERRORDEF_( Raster_Overflow, 0x62, \ + FT_ERRORDEF_( Raster_Overflow, 0x62, "raster overflow" ) - FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + FT_ERRORDEF_( Raster_Negative_Height, 0x63, "negative height while rastering" ) /* cache errors */ - FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + FT_ERRORDEF_( Too_Many_Caches, 0x70, "too many registered caches" ) /* TrueType and SFNT errors */ - FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + FT_ERRORDEF_( Invalid_Opcode, 0x80, "invalid opcode" ) - FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + FT_ERRORDEF_( Too_Few_Arguments, 0x81, "too few arguments" ) - FT_ERRORDEF_( Stack_Overflow, 0x82, \ + FT_ERRORDEF_( Stack_Overflow, 0x82, "stack overflow" ) - FT_ERRORDEF_( Code_Overflow, 0x83, \ + FT_ERRORDEF_( Code_Overflow, 0x83, "code overflow" ) - FT_ERRORDEF_( Bad_Argument, 0x84, \ + FT_ERRORDEF_( Bad_Argument, 0x84, "bad argument" ) - FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + FT_ERRORDEF_( Divide_By_Zero, 0x85, "division by zero" ) - FT_ERRORDEF_( Invalid_Reference, 0x86, \ + FT_ERRORDEF_( Invalid_Reference, 0x86, "invalid reference" ) - FT_ERRORDEF_( Debug_OpCode, 0x87, \ + FT_ERRORDEF_( Debug_OpCode, 0x87, "found debug opcode" ) - FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, "found ENDF opcode in execution stream" ) - FT_ERRORDEF_( Nested_DEFS, 0x89, \ + FT_ERRORDEF_( Nested_DEFS, 0x89, "nested DEFS" ) - FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, "invalid code range" ) - FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + FT_ERRORDEF_( Execution_Too_Long, 0x8B, "execution context too long" ) - FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, "too many function definitions" ) - FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, "too many instruction definitions" ) - FT_ERRORDEF_( Table_Missing, 0x8E, \ + FT_ERRORDEF_( Table_Missing, 0x8E, "SFNT font table missing" ) - FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, "horizontal header (hhea) table missing" ) - FT_ERRORDEF_( Locations_Missing, 0x90, \ + FT_ERRORDEF_( Locations_Missing, 0x90, "locations (loca) table missing" ) - FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + FT_ERRORDEF_( Name_Table_Missing, 0x91, "name table missing" ) - FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + FT_ERRORDEF_( CMap_Table_Missing, 0x92, "character map (cmap) table missing" ) - FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, "horizontal metrics (hmtx) table missing" ) - FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + FT_ERRORDEF_( Post_Table_Missing, 0x94, "PostScript (post) table missing" ) - FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, "invalid horizontal metrics" ) - FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, "invalid character map (cmap) format" ) - FT_ERRORDEF_( Invalid_PPem, 0x97, \ + FT_ERRORDEF_( Invalid_PPem, 0x97, "invalid ppem value" ) - FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, "invalid vertical metrics" ) - FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, "could not find context" ) - FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, "invalid PostScript (post) table format" ) - FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, "invalid PostScript (post) table" ) /* CFF, CID, and Type 1 errors */ - FT_ERRORDEF_( Syntax_Error, 0xA0, \ + FT_ERRORDEF_( Syntax_Error, 0xA0, "opcode syntax error" ) - FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + FT_ERRORDEF_( Stack_Underflow, 0xA1, "argument stack underflow" ) - FT_ERRORDEF_( Ignore, 0xA2, \ + FT_ERRORDEF_( Ignore, 0xA2, "ignore" ) - FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, "no Unicode glyph name found" ) - FT_ERRORDEF_( Glyph_Too_Big, 0xA4, \ + FT_ERRORDEF_( Glyph_Too_Big, 0xA4, "glyph to big for hinting" ) /* BDF errors */ - FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, "`STARTFONT' field missing" ) - FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + FT_ERRORDEF_( Missing_Font_Field, 0xB1, "`FONT' field missing" ) - FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + FT_ERRORDEF_( Missing_Size_Field, 0xB2, "`SIZE' field missing" ) - FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, "`FONTBOUNDINGBOX' field missing" ) - FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, "`CHARS' field missing" ) - FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, "`STARTCHAR' field missing" ) - FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, "`ENCODING' field missing" ) - FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, "`BBX' field missing" ) - FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, "`BBX' too big" ) - FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, "Font header corrupted or missing fields" ) - FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, "Font glyphs corrupted or missing fields" ) diff --git a/libs/freetype/include/freetype2/ftgasp.h b/libs/freetype/include/freetype2/ftgasp.h index 453d4fa42c9..3f3d7654678 100644 --- a/libs/freetype/include/freetype2/ftgasp.h +++ b/libs/freetype/include/freetype2/ftgasp.h @@ -120,7 +120,8 @@ FT_Get_Gasp( FT_Face face, FT_UInt ppem ); -/* */ + /* */ + #endif /* _FT_GASP_H_ */ diff --git a/libs/freetype/include/freetype2/ftglyph.h b/libs/freetype/include/freetype2/ftglyph.h index 2d30ed9de7b..15fa6a99505 100644 --- a/libs/freetype/include/freetype2/ftglyph.h +++ b/libs/freetype/include/freetype2/ftglyph.h @@ -4,7 +4,7 @@ /* */ /* FreeType convenience functions to handle glyphs (specification). */ /* */ -/* Copyright 1996-2003, 2006, 2008, 2009, 2011, 2013 by */ +/* Copyright 1996-2003, 2006, 2008, 2009, 2011, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -325,22 +325,8 @@ FT_BEGIN_HEADER } FT_Glyph_BBox_Mode; - /*************************************************************************/ - /* */ - /* */ - /* ft_glyph_bbox_xxx */ - /* */ - /* */ - /* These constants are deprecated. Use the corresponding */ - /* @FT_Glyph_BBox_Mode values instead. */ - /* */ - /* */ - /* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */ - /* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */ - /* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */ - /* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */ - /* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */ - /* */ + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_BBox_Mode' values instead */ #define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED #define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS #define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT @@ -603,7 +589,6 @@ FT_BEGIN_HEADER FT_EXPORT( FT_Error ) FT_Matrix_Invert( FT_Matrix* matrix ); - /* */ diff --git a/libs/freetype/include/freetype2/ftgxval.h b/libs/freetype/include/freetype2/ftgxval.h index 6d38e327aa1..88c3d937503 100644 --- a/libs/freetype/include/freetype2/ftgxval.h +++ b/libs/freetype/include/freetype2/ftgxval.h @@ -57,9 +57,19 @@ FT_BEGIN_HEADER /* some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, */ /* trak, prop, lcar). */ /* */ + /* */ + /* FT_TrueTypeGX_Validate */ + /* FT_TrueTypeGX_Free */ + /* */ + /* FT_ClassicKern_Validate */ + /* FT_ClassicKern_Free */ + /* */ + /* FT_VALIDATE_GX_LENGTH */ + /* FT_VALIDATE_GXXXX */ + /* FT_VALIDATE_CKERNXXX */ + /* */ /*************************************************************************/ - /*************************************************************************/ /* */ /* */ @@ -171,8 +181,6 @@ FT_BEGIN_HEADER FT_VALIDATE_lcar ) - /* */ - /********************************************************************** * * @function: @@ -221,8 +229,6 @@ FT_BEGIN_HEADER FT_UInt table_length ); - /* */ - /********************************************************************** * * @function: @@ -248,8 +254,6 @@ FT_BEGIN_HEADER FT_Bytes table ); - /* */ - /********************************************************************** * * @enum: @@ -277,8 +281,6 @@ FT_BEGIN_HEADER #define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) - /* */ - /********************************************************************** * * @function: @@ -320,8 +322,6 @@ FT_BEGIN_HEADER FT_Bytes *ckern_table ); - /* */ - /********************************************************************** * * @function: @@ -346,8 +346,7 @@ FT_BEGIN_HEADER FT_ClassicKern_Free( FT_Face face, FT_Bytes table ); - - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftgzip.h b/libs/freetype/include/freetype2/ftgzip.h index 78e726999ac..eb346c6dc78 100644 --- a/libs/freetype/include/freetype2/ftgzip.h +++ b/libs/freetype/include/freetype2/ftgzip.h @@ -137,8 +137,7 @@ FT_BEGIN_HEADER const FT_Byte* input, FT_ULong input_len ); - - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftimage.h b/libs/freetype/include/freetype2/ftimage.h index ea71a78efb6..2f7ca2aaf55 100644 --- a/libs/freetype/include/freetype2/ftimage.h +++ b/libs/freetype/include/freetype2/ftimage.h @@ -5,7 +5,7 @@ /* FreeType glyph image formats and default raster interface */ /* (specification). */ /* */ -/* Copyright 1996-2010, 2013 by */ +/* Copyright 1996-2010, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -193,67 +193,14 @@ FT_BEGIN_HEADER } FT_Pixel_Mode; - /*************************************************************************/ - /* */ - /* */ - /* ft_pixel_mode_xxx */ - /* */ - /* */ - /* A list of deprecated constants. Use the corresponding */ - /* @FT_Pixel_Mode values instead. */ - /* */ - /* */ - /* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */ - /* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */ - /* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */ - /* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */ - /* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */ - /* */ + /* these constants are deprecated; use the corresponding `FT_Pixel_Mode' */ + /* values instead. */ #define ft_pixel_mode_none FT_PIXEL_MODE_NONE #define ft_pixel_mode_mono FT_PIXEL_MODE_MONO #define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY #define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 #define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 - /* */ - -#if 0 - - /*************************************************************************/ - /* */ - /* */ - /* FT_Palette_Mode */ - /* */ - /* */ - /* THIS TYPE IS DEPRECATED. DO NOT USE IT! */ - /* */ - /* An enumeration type to describe the format of a bitmap palette, */ - /* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ - /* */ - /* */ - /* ft_palette_mode_rgb :: The palette is an array of 3-byte RGB */ - /* records. */ - /* */ - /* ft_palette_mode_rgba :: The palette is an array of 4-byte RGBA */ - /* records. */ - /* */ - /* */ - /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ - /* FreeType, these types are not handled by the library itself. */ - /* */ - typedef enum FT_Palette_Mode_ - { - ft_palette_mode_rgb = 0, - ft_palette_mode_rgba, - - ft_palette_mode_max /* do not remove */ - - } FT_Palette_Mode; - - /* */ - -#endif - /*************************************************************************/ /* */ @@ -318,13 +265,13 @@ FT_BEGIN_HEADER /* */ typedef struct FT_Bitmap_ { - int rows; - int width; + unsigned int rows; + unsigned int width; int pitch; unsigned char* buffer; - short num_grays; - char pixel_mode; - char palette_mode; + unsigned short num_grays; + unsigned char pixel_mode; + unsigned char palette_mode; void* palette; } FT_Bitmap; @@ -381,7 +328,7 @@ FT_BEGIN_HEADER /* */ /* flags :: A set of bit flags used to characterize the outline */ /* and give hints to the scan-converter and hinter on */ - /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ + /* how to convert/grid-fit it. See @FT_OUTLINE_XXX. */ /* */ /* */ /* The B/W rasterizer only checks bit~2 in the `tags' array for the */ @@ -402,6 +349,8 @@ FT_BEGIN_HEADER } FT_Outline; + /* */ + /* Following limits must be consistent with */ /* FT_Outline.{n_contours,n_points} */ #define FT_OUTLINE_CONTOURS_MAX SHRT_MAX @@ -411,7 +360,7 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ /* */ - /* FT_OUTLINE_FLAGS */ + /* FT_OUTLINE_XXX */ /* */ /* */ /* A list of bit-field constants use for the flags in an outline's */ @@ -492,24 +441,8 @@ FT_BEGIN_HEADER #define FT_OUTLINE_SINGLE_PASS 0x200 - /************************************************************************* - * - * @enum: - * ft_outline_flags - * - * @description: - * These constants are deprecated. Please use the corresponding - * @FT_OUTLINE_FLAGS values. - * - * @values: - * ft_outline_none :: See @FT_OUTLINE_NONE. - * ft_outline_owner :: See @FT_OUTLINE_OWNER. - * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL. - * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL. - * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS. - * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION. - * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS. - */ + /* these constants are deprecated; use the corresponding */ + /* `FT_OUTLINE_XXX' values instead */ #define ft_outline_none FT_OUTLINE_NONE #define ft_outline_owner FT_OUTLINE_OWNER #define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL @@ -796,22 +729,8 @@ FT_BEGIN_HEADER } FT_Glyph_Format; - /*************************************************************************/ - /* */ - /* */ - /* ft_glyph_format_xxx */ - /* */ - /* */ - /* A list of deprecated constants. Use the corresponding */ - /* @FT_Glyph_Format values instead. */ - /* */ - /* */ - /* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */ - /* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */ - /* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */ - /* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */ - /* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */ - /* */ + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_Format' values instead. */ #define ft_glyph_format_none FT_GLYPH_FORMAT_NONE #define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE #define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP @@ -856,6 +775,21 @@ FT_BEGIN_HEADER /* */ /* This section contains technical definitions. */ /* */ + /* */ + /* FT_Raster */ + /* FT_Span */ + /* FT_SpanFunc */ + /* */ + /* FT_Raster_Params */ + /* FT_RASTER_FLAG_XXX */ + /* */ + /* FT_Raster_NewFunc */ + /* FT_Raster_DoneFunc */ + /* FT_Raster_ResetFunc */ + /* FT_Raster_SetModeFunc */ + /* FT_Raster_RenderFunc */ + /* FT_Raster_Funcs */ + /* */ /*************************************************************************/ @@ -865,8 +799,8 @@ FT_BEGIN_HEADER /* FT_Raster */ /* */ /* */ - /* A handle (pointer) to a raster object. Each object can be used */ - /* independently to convert an outline into a bitmap or pixmap. */ + /* An opaque handle (pointer) to a raster object. Each object can be */ + /* used independently to convert an outline into a bitmap or pixmap. */ /* */ typedef struct FT_RasterRec_* FT_Raster; @@ -877,8 +811,8 @@ FT_BEGIN_HEADER /* FT_Span */ /* */ /* */ - /* A structure used to model a single span of gray (or black) pixels */ - /* when rendering a monochrome or anti-aliased bitmap. */ + /* A structure used to model a single span of gray pixels when */ + /* rendering an anti-aliased bitmap. */ /* */ /* */ /* x :: The span's horizontal start position. */ @@ -886,8 +820,7 @@ FT_BEGIN_HEADER /* len :: The span's length in pixels. */ /* */ /* coverage :: The span color/coverage, ranging from 0 (background) */ - /* to 255 (foreground). Only used for anti-aliased */ - /* rendering. */ + /* to 255 (foreground). */ /* */ /* */ /* This structure is used by the span drawing callback type named */ @@ -957,22 +890,7 @@ FT_BEGIN_HEADER /* FT_Raster_BitTest_Func */ /* */ /* */ - /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ - /* */ - /* A function used as a call-back by the monochrome scan-converter */ - /* to test whether a given target pixel is already set to the drawing */ - /* `color'. These tests are crucial to implement drop-out control */ - /* per-se the TrueType spec. */ - /* */ - /* */ - /* y :: The pixel's y~coordinate. */ - /* */ - /* x :: The pixel's x~coordinate. */ - /* */ - /* user :: User-supplied data that is passed to the callback. */ - /* */ - /* */ - /* 1~if the pixel is `set', 0~otherwise. */ + /* Deprecated, unimplemented. */ /* */ typedef int (*FT_Raster_BitTest_Func)( int y, @@ -986,21 +904,7 @@ FT_BEGIN_HEADER /* FT_Raster_BitSet_Func */ /* */ /* */ - /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ - /* */ - /* A function used as a call-back by the monochrome scan-converter */ - /* to set an individual target pixel. This is crucial to implement */ - /* drop-out control according to the TrueType specification. */ - /* */ - /* */ - /* y :: The pixel's y~coordinate. */ - /* */ - /* x :: The pixel's x~coordinate. */ - /* */ - /* user :: User-supplied data that is passed to the callback. */ - /* */ - /* */ - /* 1~if the pixel is `set', 0~otherwise. */ + /* Deprecated, unimplemented. */ /* */ typedef void (*FT_Raster_BitSet_Func)( int y, @@ -1034,8 +938,8 @@ FT_BEGIN_HEADER /* pixmap's buffer _must_ be zeroed before */ /* rendering. */ /* */ - /* Note that for now, direct rendering is */ - /* only possible with anti-aliased glyphs. */ + /* Direct rendering is only possible with */ + /* anti-aliased glyphs. */ /* */ /* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ /* rendering mode. If set, the output will */ @@ -1053,7 +957,8 @@ FT_BEGIN_HEADER #define FT_RASTER_FLAG_DIRECT 0x2 #define FT_RASTER_FLAG_CLIP 0x4 - /* deprecated */ + /* these constants are deprecated; use the corresponding */ + /* `FT_RASTER_FLAG_XXX' values instead */ #define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT #define ft_raster_flag_aa FT_RASTER_FLAG_AA #define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT @@ -1079,11 +984,11 @@ FT_BEGIN_HEADER /* */ /* gray_spans :: The gray span drawing callback. */ /* */ - /* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ + /* black_spans :: Unused. */ /* */ - /* bit_test :: The bit test callback. UNIMPLEMENTED! */ + /* bit_test :: Unused. */ /* */ - /* bit_set :: The bit set callback. UNIMPLEMENTED! */ + /* bit_set :: Unused. */ /* */ /* user :: User-supplied data that is passed to each drawing */ /* callback. */ @@ -1100,15 +1005,9 @@ FT_BEGIN_HEADER /* */ /* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ /* raster will call the `gray_spans' callback to draw gray pixel */ - /* spans, in the case of an aa glyph bitmap, it will call */ - /* `black_spans', and `bit_test' and `bit_set' in the case of a */ - /* monochrome bitmap. This allows direct composition over a */ - /* pre-existing bitmap through user-provided callbacks to perform the */ - /* span drawing/composition. */ - /* */ - /* Note that the `bit_test' and `bit_set' callbacks are required when */ - /* rendering a monochrome bitmap, as they are crucial to implement */ - /* correct drop-out control as defined in the TrueType specification. */ + /* spans. This allows direct composition over a pre-existing bitmap */ + /* through user-provided callbacks to perform the span drawing and */ + /* composition. Not supported by the monochrome rasterizer. */ /* */ typedef struct FT_Raster_Params_ { @@ -1116,9 +1015,9 @@ FT_BEGIN_HEADER const void* source; int flags; FT_SpanFunc gray_spans; - FT_SpanFunc black_spans; /* doesn't work! */ - FT_Raster_BitTest_Func bit_test; /* doesn't work! */ - FT_Raster_BitSet_Func bit_set; /* doesn't work! */ + FT_SpanFunc black_spans; /* unused */ + FT_Raster_BitTest_Func bit_test; /* unused */ + FT_Raster_BitSet_Func bit_set; /* unused */ void* user; FT_BBox clip_box; @@ -1305,7 +1204,6 @@ FT_BEGIN_HEADER } FT_Raster_Funcs; - /* */ diff --git a/libs/freetype/include/freetype2/ftincrem.h b/libs/freetype/include/freetype2/ftincrem.h index aaf689ff16c..4c0246c5df4 100644 --- a/libs/freetype/include/freetype2/ftincrem.h +++ b/libs/freetype/include/freetype2/ftincrem.h @@ -4,7 +4,7 @@ /* */ /* FreeType incremental loading (specification). */ /* */ -/* Copyright 2002, 2003, 2006, 2007, 2008, 2010 by */ +/* Copyright 2002, 2003, 2006-2008, 2010, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -45,7 +45,7 @@ FT_BEGIN_HEADER * @description: * This section contains various functions used to perform so-called * `incremental' glyph loading. This is a mode where all glyphs loaded - * from a given @FT_Face are provided by the client application, + * from a given @FT_Face are provided by the client application. * * Apart from that, all other tables are loaded normally from the font * file. This mode is useful when FreeType is used within another @@ -345,6 +345,7 @@ FT_BEGIN_HEADER /* */ + FT_END_HEADER #endif /* __FTINCREM_H__ */ diff --git a/libs/freetype/include/freetype2/ftlcdfil.h b/libs/freetype/include/freetype2/ftlcdfil.h index 39206f01927..e8679c1a3ff 100644 --- a/libs/freetype/include/freetype2/ftlcdfil.h +++ b/libs/freetype/include/freetype2/ftlcdfil.h @@ -5,7 +5,7 @@ /* FreeType API for color filtering of subpixel bitmap glyphs */ /* (specification). */ /* */ -/* Copyright 2006-2008, 2010, 2013 by */ +/* Copyright 2006-2008, 2010, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -56,7 +56,7 @@ FT_BEGIN_HEADER * * FreeType generates alpha coverage maps, which are linear by nature. * For instance, the value 0x80 in bitmap representation means that - * (within numerical precision) 0x80/0xff fraction of that pixel is + * (within numerical precision) 0x80/0xFF fraction of that pixel is * covered by the glyph's outline. The blending function for placing * text over a background is * diff --git a/libs/freetype/include/freetype2/ftlist.h b/libs/freetype/include/freetype2/ftlist.h index 241e21e555c..9950a279971 100644 --- a/libs/freetype/include/freetype2/ftlist.h +++ b/libs/freetype/include/freetype2/ftlist.h @@ -4,7 +4,7 @@ /* */ /* Generic list support for FreeType (specification). */ /* */ -/* Copyright 1996-2001, 2003, 2007, 2010, 2013 by */ +/* Copyright 1996-2001, 2003, 2007, 2010, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -248,7 +248,7 @@ FT_BEGIN_HEADER /* list :: A handle to the list. */ /* */ /* destroy :: A list destructor that will be applied to each element */ - /* of the list. */ + /* of the list. Set this to NULL if not needed. */ /* */ /* memory :: The current memory object that handles deallocation. */ /* */ @@ -265,7 +265,6 @@ FT_BEGIN_HEADER FT_Memory memory, void* user ); - /* */ diff --git a/libs/freetype/include/freetype2/ftlzw.h b/libs/freetype/include/freetype2/ftlzw.h index 00d40169a75..857c0c52bbc 100644 --- a/libs/freetype/include/freetype2/ftlzw.h +++ b/libs/freetype/include/freetype2/ftlzw.h @@ -88,7 +88,7 @@ FT_BEGIN_HEADER FT_Stream_OpenLZW( FT_Stream stream, FT_Stream source ); - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftmm.h b/libs/freetype/include/freetype2/ftmm.h index 837975a0b5c..2dcfd678df1 100644 --- a/libs/freetype/include/freetype2/ftmm.h +++ b/libs/freetype/include/freetype2/ftmm.h @@ -218,9 +218,6 @@ FT_BEGIN_HEADER } FT_MM_Var; - /* */ - - /*************************************************************************/ /* */ /* */ @@ -365,7 +362,6 @@ FT_BEGIN_HEADER FT_UInt num_coords, FT_Fixed* coords ); - /* */ diff --git a/libs/freetype/include/freetype2/ftmodapi.h b/libs/freetype/include/freetype2/ftmodapi.h index 22878f8c6d7..980f15d3de0 100644 --- a/libs/freetype/include/freetype2/ftmodapi.h +++ b/libs/freetype/include/freetype2/ftmodapi.h @@ -75,6 +75,33 @@ FT_BEGIN_HEADER /* */ /* Note that the FreeType Cache sub-system is not a FreeType module. */ /* */ + /* */ + /* FT_Module */ + /* FT_Module_Constructor */ + /* FT_Module_Destructor */ + /* FT_Module_Requester */ + /* FT_Module_Class */ + /* */ + /* FT_Add_Module */ + /* FT_Get_Module */ + /* FT_Remove_Module */ + /* FT_Add_Default_Modules */ + /* */ + /* FT_Property_Set */ + /* FT_Property_Get */ + /* */ + /* FT_New_Library */ + /* FT_Done_Library */ + /* FT_Reference_Library */ + /* */ + /* FT_Renderer */ + /* FT_Renderer_Class */ + /* */ + /* FT_Get_Renderer */ + /* FT_Set_Renderer */ + /* */ + /* FT_Set_Debug_Hook */ + /* */ /*************************************************************************/ @@ -491,7 +518,7 @@ FT_BEGIN_HEADER FT_EXPORT( FT_Error ) FT_Done_Library( FT_Library library ); -/* */ + /* */ typedef void (*FT_DebugHook_Func)( void* arg ); @@ -629,7 +656,6 @@ FT_BEGIN_HEADER FT_EXPORT( FT_TrueTypeEngineType ) FT_Get_TrueType_Engine_Type( FT_Library library ); - /* */ diff --git a/libs/freetype/include/freetype2/ftotval.h b/libs/freetype/include/freetype2/ftotval.h index bb52dc4a0d2..75ba03ee8e7 100644 --- a/libs/freetype/include/freetype2/ftotval.h +++ b/libs/freetype/include/freetype2/ftotval.h @@ -4,7 +4,7 @@ /* */ /* FreeType API for validating OpenType tables (specification). */ /* */ -/* Copyright 2004-2007, 2013 by */ +/* Copyright 2004-2007, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -58,6 +58,12 @@ FT_BEGIN_HEADER /* This section contains the declaration of functions to validate */ /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). */ /* */ + /* */ + /* FT_OpenType_Validate */ + /* FT_OpenType_Free */ + /* */ + /* FT_VALIDATE_OTXXX */ + /* */ /*************************************************************************/ @@ -107,8 +113,6 @@ FT_BEGIN_HEADER FT_VALIDATE_JSTF | \ FT_VALIDATE_MATH - /* */ - /********************************************************************** * * @function: @@ -165,8 +169,6 @@ FT_BEGIN_HEADER FT_Bytes *GSUB_table, FT_Bytes *JSTF_table ); - /* */ - /********************************************************************** * * @function: @@ -191,8 +193,7 @@ FT_BEGIN_HEADER FT_OpenType_Free( FT_Face face, FT_Bytes table ); - - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftoutln.h b/libs/freetype/include/freetype2/ftoutln.h index 6c6d3f94be6..d3b8fbd2658 100644 --- a/libs/freetype/include/freetype2/ftoutln.h +++ b/libs/freetype/include/freetype2/ftoutln.h @@ -52,7 +52,6 @@ FT_BEGIN_HEADER /* */ /* */ /* FT_Outline */ - /* FT_OUTLINE_FLAGS */ /* FT_Outline_New */ /* FT_Outline_Done */ /* FT_Outline_Copy */ @@ -68,13 +67,17 @@ FT_BEGIN_HEADER /* */ /* FT_Outline_Get_Bitmap */ /* FT_Outline_Render */ - /* */ /* FT_Outline_Decompose */ /* FT_Outline_Funcs */ - /* FT_Outline_MoveTo_Func */ - /* FT_Outline_LineTo_Func */ - /* FT_Outline_ConicTo_Func */ - /* FT_Outline_CubicTo_Func */ + /* FT_Outline_MoveToFunc */ + /* FT_Outline_LineToFunc */ + /* FT_Outline_ConicToFunc */ + /* FT_Outline_CubicToFunc */ + /* */ + /* FT_Orientation */ + /* FT_Outline_Get_Orientation */ + /* */ + /* FT_OUTLINE_XXX */ /* */ /*************************************************************************/ @@ -535,7 +538,7 @@ FT_BEGIN_HEADER * * @description: * This function analyzes a glyph outline and tries to compute its - * fill orientation (see @FT_Orientation). This is done by integrating + * fill orientation (see @FT_Orientation). This is done by integrating * the total area covered by the outline. The positive integral * corresponds to the clockwise orientation and @FT_ORIENTATION_POSTSCRIPT * is returned. The negative integral corresponds to the counter-clockwise @@ -555,7 +558,6 @@ FT_BEGIN_HEADER FT_EXPORT( FT_Orientation ) FT_Outline_Get_Orientation( FT_Outline* outline ); - /* */ diff --git a/libs/freetype/include/freetype2/ftpfr.h b/libs/freetype/include/freetype2/ftpfr.h index 0b7b7d427c9..7d5035396b7 100644 --- a/libs/freetype/include/freetype2/ftpfr.h +++ b/libs/freetype/include/freetype2/ftpfr.h @@ -161,7 +161,7 @@ FT_BEGIN_HEADER FT_UInt gindex, FT_Pos *aadvance ); - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftrender.h b/libs/freetype/include/freetype2/ftrender.h index dd0229b815e..e8d36363ca6 100644 --- a/libs/freetype/include/freetype2/ftrender.h +++ b/libs/freetype/include/freetype2/ftrender.h @@ -226,7 +226,6 @@ FT_BEGIN_HEADER FT_UInt num_params, FT_Parameter* parameters ); - /* */ diff --git a/libs/freetype/include/freetype2/ftstroke.h b/libs/freetype/include/freetype2/ftstroke.h index a498e4a883b..bd311709f34 100644 --- a/libs/freetype/include/freetype2/ftstroke.h +++ b/libs/freetype/include/freetype2/ftstroke.h @@ -4,7 +4,7 @@ /* */ /* FreeType path stroker (specification). */ /* */ -/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */ +/* Copyright 2002-2006, 2008, 2009, 2011-2012, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -46,6 +46,38 @@ FT_BEGIN_HEADER * This can be useful to generate `bordered' glyph, i.e., glyphs * displayed with a coloured (and anti-aliased) border around their * shape. + * + * @order: + * FT_Stroker + * + * FT_Stroker_LineJoin + * FT_Stroker_LineCap + * FT_StrokerBorder + * + * FT_Outline_GetInsideBorder + * FT_Outline_GetOutsideBorder + * + * FT_Glyph_Stroke + * FT_Glyph_StrokeBorder + * + * FT_Stroker_New + * FT_Stroker_Set + * FT_Stroker_Rewind + * FT_Stroker_ParseOutline + * FT_Stroker_Done + * + * FT_Stroker_BeginSubPath + * FT_Stroker_EndSubPath + * + * FT_Stroker_LineTo + * FT_Stroker_ConicTo + * FT_Stroker_CubicTo + * + * FT_Stroker_GetBorderCounts + * FT_Stroker_ExportBorder + * FT_Stroker_GetCounts + * FT_Stroker_Export + * */ @@ -55,7 +87,7 @@ FT_BEGIN_HEADER * FT_Stroker * * @description: - * Opaque handler to a path stroker object. + * Opaque handle to a path stroker object. */ typedef struct FT_StrokerRec_* FT_Stroker; @@ -276,6 +308,8 @@ FT_BEGIN_HEADER * @note: * The radius is expressed in the same units as the outline * coordinates. + * + * This function calls @FT_Stroker_Rewind automatically. */ FT_EXPORT( void ) FT_Stroker_Set( FT_Stroker stroker, @@ -570,10 +604,10 @@ FT_BEGIN_HEADER * receive all new data. * * When an outline, or a sub-path, is `closed', the stroker generates - * two independent `border' outlines, named `left' and `right' + * two independent `border' outlines, named `left' and `right'. * * When the outline, or a sub-path, is `opened', the stroker merges - * the `border' outlines with caps. The `left' border receives all + * the `border' outlines with caps. The `left' border receives all * points, while the `right' border becomes empty. * * Use the function @FT_Stroker_Export instead if you want to @@ -736,7 +770,7 @@ FT_BEGIN_HEADER FT_Bool inside, FT_Bool destroy ); - /* */ + /* */ FT_END_HEADER diff --git a/libs/freetype/include/freetype2/ftsynth.h b/libs/freetype/include/freetype2/ftsynth.h index 839ab5e4002..d0ea730874f 100644 --- a/libs/freetype/include/freetype2/ftsynth.h +++ b/libs/freetype/include/freetype2/ftsynth.h @@ -73,6 +73,7 @@ FT_BEGIN_HEADER /* */ + FT_END_HEADER #endif /* __FTSYNTH_H__ */ diff --git a/libs/freetype/include/freetype2/ftsystem.h b/libs/freetype/include/freetype2/ftsystem.h index e07460c55d4..7436ed2678a 100644 --- a/libs/freetype/include/freetype2/ftsystem.h +++ b/libs/freetype/include/freetype2/ftsystem.h @@ -4,7 +4,7 @@ /* */ /* FreeType low-level system interface definition (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2005, 2010 by */ +/* Copyright 1996-2001, 2002, 2005, 2010, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -192,6 +192,10 @@ FT_BEGIN_HEADER * @description: * A handle to an input stream. * + * @also: + * See @FT_StreamRec for the publicly accessible fields of a given + * stream object. + * */ typedef struct FT_StreamRec_* FT_Stream; @@ -285,6 +289,11 @@ FT_BEGIN_HEADER * size :: * The stream size in bytes. * + * In case of compressed streams where the size is unknown before + * actually doing the decompression, the value is set to 0x7FFFFFFF. + * (Note that this size value can occur for normal streams also; it is + * thus just a hint.) + * * pos :: * The current position within the stream. * @@ -335,7 +344,6 @@ FT_BEGIN_HEADER } FT_StreamRec; - /* */ diff --git a/libs/freetype/include/freetype2/fttrigon.h b/libs/freetype/include/freetype2/fttrigon.h index 65143cb8c85..9c7b54324e4 100644 --- a/libs/freetype/include/freetype2/fttrigon.h +++ b/libs/freetype/include/freetype2/fttrigon.h @@ -237,7 +237,7 @@ FT_BEGIN_HEADER * * @input: * angle :: - * The address of angle. + * The input angle. * */ FT_EXPORT( void ) @@ -259,7 +259,7 @@ FT_BEGIN_HEADER * * @input: * angle :: - * The address of angle. + * The input angle. * */ FT_EXPORT( void ) diff --git a/libs/freetype/include/freetype2/ftttdrv.h b/libs/freetype/include/freetype2/ftttdrv.h index 70ad3d583b3..358841397ca 100644 --- a/libs/freetype/include/freetype2/ftttdrv.h +++ b/libs/freetype/include/freetype2/ftttdrv.h @@ -158,9 +158,9 @@ FT_BEGIN_HEADER #define TT_INTERPRETER_VERSION_35 35 #define TT_INTERPRETER_VERSION_38 38 - /* */ + FT_END_HEADER diff --git a/libs/freetype/include/freetype2/fttypes.h b/libs/freetype/include/freetype2/fttypes.h index bd944a4935f..2c01e8737ca 100644 --- a/libs/freetype/include/freetype2/fttypes.h +++ b/libs/freetype/include/freetype2/fttypes.h @@ -4,7 +4,7 @@ /* */ /* FreeType simple types definitions (specification only). */ /* */ -/* Copyright 1996-2002, 2004, 2006-2009, 2012, 2013 by */ +/* Copyright 1996-2002, 2004, 2006-2009, 2012-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -57,6 +57,8 @@ FT_BEGIN_HEADER /* FT_UInt16 */ /* FT_Int32 */ /* FT_UInt32 */ + /* FT_Int64 */ + /* FT_UInt64 */ /* FT_Short */ /* FT_UShort */ /* FT_Long */ @@ -78,7 +80,9 @@ FT_BEGIN_HEADER /* FT_F2Dot14 */ /* FT_UnitVector */ /* FT_F26Dot6 */ + /* FT_Data */ /* */ + /* FT_MAKE_TAG */ /* */ /* FT_Generic */ /* FT_Generic_Finalizer */ @@ -567,9 +571,9 @@ FT_BEGIN_HEADER } FT_ListRec; - /* */ + #define FT_IS_EMPTY( list ) ( (list).head == 0 ) #define FT_BOOL( x ) ( (FT_Bool)( x ) ) diff --git a/libs/freetype/include/freetype2/ftwinfnt.h b/libs/freetype/include/freetype2/ftwinfnt.h index 0b673517914..50261581a21 100644 --- a/libs/freetype/include/freetype2/ftwinfnt.h +++ b/libs/freetype/include/freetype2/ftwinfnt.h @@ -259,9 +259,9 @@ FT_BEGIN_HEADER FT_Get_WinFNT_Header( FT_Face face, FT_WinFNT_HeaderRec *aheader ); - /* */ + FT_END_HEADER #endif /* __FTWINFNT_H__ */ diff --git a/libs/freetype/include/freetype2/ftxf86.h b/libs/freetype/include/freetype2/ftxf86.h index 493cccdd0a5..89d1993e1ea 100644 --- a/libs/freetype/include/freetype2/ftxf86.h +++ b/libs/freetype/include/freetype2/ftxf86.h @@ -76,7 +76,8 @@ FT_BEGIN_HEADER FT_EXPORT( const char* ) FT_Get_X11_Font_Format( FT_Face face ); - /* */ + /* */ + FT_END_HEADER diff --git a/libs/freetype/include/freetype2/internal/ftcalc.h b/libs/freetype/include/freetype2/internal/ftcalc.h index 03bd68eb108..14ec37b9cd1 100644 --- a/libs/freetype/include/freetype2/internal/ftcalc.h +++ b/libs/freetype/include/freetype2/internal/ftcalc.h @@ -4,7 +4,7 @@ /* */ /* Arithmetic computations (specification). */ /* */ -/* Copyright 1996-2006, 2008, 2009, 2012-2013 by */ +/* Copyright 1996-2006, 2008, 2009, 2012-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -27,36 +27,223 @@ FT_BEGIN_HEADER -#if 0 - /*************************************************************************/ /* */ - /* */ - /* FT_SqrtFixed */ - /* */ - /* */ - /* Computes the square root of a 16.16 fixed-point value. */ - /* */ - /* */ - /* x :: The value to compute the root for. */ - /* */ - /* */ - /* The result of `sqrt(x)'. */ - /* */ - /* */ - /* This function is not very fast. */ + /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ /* */ - FT_BASE( FT_Int32 ) - FT_SqrtFixed( FT_Int32 x ); + /*************************************************************************/ -#endif /* 0 */ +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + /* Provide assembler fragments for performance-critical functions. */ + /* These must be defined `static __inline__' with GCC. */ +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ - /*************************************************************************/ - /* */ - /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ - /* */ - /*************************************************************************/ +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x8000 /* a += 0x8000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #16 /* a = t2 >> 16 */ + orr a, a, t, lsl #16 /* a |= t << 16 */ + } + return a; + } + +#endif /* __CC_ARM || __ARMCC__ */ + + +#ifdef __GNUC__ + +#if defined( __arm__ ) && \ + ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ + !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + + + __asm__ __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ +#if defined( __clang__ ) && defined( __thumb2__ ) + "add.w %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#else + "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#endif + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ + "orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + return a; + } + +#endif /* __arm__ && */ + /* ( __thumb2__ || !__thumb__ ) && */ + /* !( __CC_ARM || __ARMCC__ ) */ + + +#if defined( __i386__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 result; + + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); + return result; + } + +#endif /* i386 */ + +#endif /* __GNUC__ */ + + +#ifdef _MSC_VER /* Visual C++ */ + +#ifdef _M_IX86 + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 result; + + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 8000h + add eax, ecx + adc edx, 0 + shr eax, 16 + shl edx, 16 + add eax, edx + mov result, eax + } + return result; + } + +#endif /* _M_IX86 */ + +#endif /* _MSC_VER */ + + +#if defined( __GNUC__ ) && defined( __x86_64__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 + + static __inline__ FT_Int32 + FT_MulFix_x86_64( FT_Int32 a, + FT_Int32 b ) + { + /* Temporarily disable the warning that C90 doesn't support */ + /* `long long'. */ +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlong-long" +#endif + +#if 1 + /* Technically not an assembly fragment, but GCC does a really good */ + /* job at inlining it and generating good machine code for it. */ + long long ret, tmp; + + + ret = (long long)a * b; + tmp = ret >> 63; + ret += 0x8000 + tmp; + + return (FT_Int32)( ret >> 16 ); +#else + + /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ + /* code from the lines below. The main issue is that `wide_a' is not */ + /* properly initialized by sign-extending `a'. Instead, the generated */ + /* machine code assumes that the register that contains `a' on input */ + /* can be used directly as a 64-bit value, which is wrong most of the */ + /* time. */ + long long wide_a = (long long)a; + long long wide_b = (long long)b; + long long result; + + + __asm__ __volatile__ ( + "imul %2, %1\n" + "mov %1, %0\n" + "sar $63, %0\n" + "lea 0x8000(%1, %0), %0\n" + "sar $16, %0\n" + : "=&r"(result), "=&r"(wide_a) + : "r"(wide_b) + : "cc" ); + + return (FT_Int32)result; +#endif + +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic pop +#endif + } + +#endif /* __GNUC__ && __x86_64__ */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX +#ifdef FT_MULFIX_ASSEMBLER +#define FT_MulFix( a, b ) FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) ) +#endif +#endif /*************************************************************************/ @@ -124,10 +311,11 @@ FT_BEGIN_HEADER FT_Pos out_x, FT_Pos out_y ); + /* * Return TRUE if a corner is flat or nearly flat. This is equivalent to - * saying that the angle difference between the `in' and `out' vectors is - * very small. + * saying that the corner point is close to its neighbors, or inside an + * ellipse defined by the neighbor focal points to be more precise. */ FT_BASE( FT_Int ) ft_corner_is_flat( FT_Pos in_x, @@ -139,9 +327,31 @@ FT_BEGIN_HEADER /* * Return the most significant bit index. */ + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER +#if defined( __GNUC__ ) && \ + ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) + +#if FT_SIZEOF_INT == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clz( x ) ) + +#elif FT_SIZEOF_LONG == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clzl( x ) ) + +#endif + +#endif /* __GNUC__ */ +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + +#ifndef FT_MSB + FT_BASE( FT_Int ) FT_MSB( FT_UInt32 z ); +#endif + /* * Return sqrt(x*x+y*y), which is the same as `FT_Vector_Length' but uses @@ -152,6 +362,31 @@ FT_BEGIN_HEADER FT_Fixed y ); +#if 0 + + /*************************************************************************/ + /* */ + /* */ + /* FT_SqrtFixed */ + /* */ + /* */ + /* Computes the square root of a 16.16 fixed-point value. */ + /* */ + /* */ + /* x :: The value to compute the root for. */ + /* */ + /* */ + /* The result of `sqrt(x)'. */ + /* */ + /* */ + /* This function is not very fast. */ + /* */ + FT_BASE( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ); + +#endif /* 0 */ + + #define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) #define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) #define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) diff --git a/libs/freetype/include/freetype2/internal/ftgloadr.h b/libs/freetype/include/freetype2/internal/ftgloadr.h index ce4dc6c9cc6..f70774f74eb 100644 --- a/libs/freetype/include/freetype2/internal/ftgloadr.h +++ b/libs/freetype/include/freetype2/internal/ftgloadr.h @@ -121,20 +121,22 @@ FT_BEGIN_HEADER FT_UInt n_contours ); -#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ - ( (_count) == 0 || ((_loader)->base.outline.n_points + \ - (_loader)->current.outline.n_points + \ - (unsigned long)(_count)) <= (_loader)->max_points ) - -#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ - ( (_count) == 0 || ((_loader)->base.outline.n_contours + \ - (_loader)->current.outline.n_contours + \ - (unsigned long)(_count)) <= (_loader)->max_contours ) - -#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points,_contours ) \ - ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ - FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ - ? 0 \ +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || \ + ( (_loader)->base.outline.n_points + \ + (_loader)->current.outline.n_points + \ + (unsigned long)(_count) ) <= (_loader)->max_points ) + +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || \ + ( (_loader)->base.outline.n_contours + \ + (_loader)->current.outline.n_contours + \ + (unsigned long)(_count)) <= (_loader)->max_contours ) + +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points, _contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ : FT_GlyphLoader_CheckPoints( (_loader), (_points), (_contours) ) ) diff --git a/libs/freetype/include/freetype2/internal/ftobjs.h b/libs/freetype/include/freetype2/internal/ftobjs.h index 701c850eb70..b45a5ed814f 100644 --- a/libs/freetype/include/freetype2/internal/ftobjs.h +++ b/libs/freetype/include/freetype2/internal/ftobjs.h @@ -72,6 +72,16 @@ FT_BEGIN_HEADER #define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + /* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +#define FT_HYPOT( x, y ) \ + ( x = FT_ABS( x ), \ + y = FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) #define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) #define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) @@ -82,14 +92,6 @@ FT_BEGIN_HEADER #define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) - /* - * Return the highest power of 2 that is <= value; this correspond to - * the highest bit in a given 32-bit value. - */ - FT_BASE( FT_UInt32 ) - ft_highpow2( FT_UInt32 value ); - - /* * character classification functions -- since these are used to parse * font files, we must not use those in which are diff --git a/libs/freetype/include/freetype2/internal/ftvalid.h b/libs/freetype/include/freetype2/internal/ftvalid.h index 12ad03685ad..c281b1424a5 100644 --- a/libs/freetype/include/freetype2/internal/ftvalid.h +++ b/libs/freetype/include/freetype2/internal/ftvalid.h @@ -4,7 +4,7 @@ /* */ /* FreeType validation support (specification). */ /* */ -/* Copyright 2004, 2013 by */ +/* Copyright 2004, 2013, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -87,13 +87,13 @@ FT_BEGIN_HEADER /* validator structure */ typedef struct FT_ValidatorRec_ { + ft_jmp_buf jump_buffer; /* used for exception handling */ + const FT_Byte* base; /* address of table in memory */ const FT_Byte* limit; /* `base' + sizeof(table) in memory */ FT_ValidationLevel level; /* validation level */ FT_Error error; /* error returned. 0 means success */ - ft_jmp_buf jump_buffer; /* used for exception handling */ - } FT_ValidatorRec; #if defined( _MSC_VER ) @@ -126,31 +126,29 @@ FT_BEGIN_HEADER /* Calls ft_validate_error. Assumes that the `valid' local variable */ /* holds a pointer to the current validator object. */ /* */ - /* Use preprocessor prescan to pass FT_ERR_PREFIX. */ - /* */ -#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) -#define FT_INVALID_( _prefix, _error ) \ - ft_validator_error( valid, _prefix ## _error ) +#define FT_INVALID( _error ) FT_INVALID_( _error ) +#define FT_INVALID_( _error ) \ + ft_validator_error( valid, FT_THROW( _error ) ) /* called when a broken table is detected */ #define FT_INVALID_TOO_SHORT \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + FT_INVALID( Invalid_Table ) /* called when an invalid offset is detected */ #define FT_INVALID_OFFSET \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) + FT_INVALID( Invalid_Offset ) /* called when an invalid format/value is detected */ #define FT_INVALID_FORMAT \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + FT_INVALID( Invalid_Table ) /* called when an invalid glyph index is detected */ #define FT_INVALID_GLYPH_ID \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) + FT_INVALID( Invalid_Glyph_Index ) /* called when an invalid field value is detected */ #define FT_INVALID_DATA \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + FT_INVALID( Invalid_Table ) FT_END_HEADER diff --git a/libs/freetype/include/freetype2/internal/pshints.h b/libs/freetype/include/freetype2/internal/pshints.h index 3fb18dc2d59..f05ea6863a9 100644 --- a/libs/freetype/include/freetype2/internal/pshints.h +++ b/libs/freetype/include/freetype2/internal/pshints.h @@ -6,7 +6,7 @@ /* recorders (specification only). These are used to support native */ /* T1/T2 hints in the `type1', `cid', and `cff' font drivers. */ /* */ -/* Copyright 2001-2003, 2005-2007, 2009, 2012 by */ +/* Copyright 2001-2003, 2005-2007, 2009, 2012, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -45,7 +45,7 @@ FT_BEGIN_HEADER T1_Private* private_dict, PSH_Globals* aglobals ); - typedef FT_Error + typedef void (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, FT_Fixed x_scale, FT_Fixed y_scale, diff --git a/libs/freetype/include/freetype2/internal/sfnt.h b/libs/freetype/include/freetype2/internal/sfnt.h index 6b5e41f1adf..d558e869bda 100644 --- a/libs/freetype/include/freetype2/internal/sfnt.h +++ b/libs/freetype/include/freetype2/internal/sfnt.h @@ -4,7 +4,7 @@ /* */ /* High-level `sfnt' driver interface (specification). */ /* */ -/* Copyright 1996-2006, 2009, 2012-2013 by */ +/* Copyright 1996-2006, 2009, 2012-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -405,14 +405,18 @@ FT_BEGIN_HEADER /* */ /* face :: A handle to the target face object. */ /* */ - /* stream :: The input stream. */ - /* */ /* vertical :: A boolean flag. If set, load vertical metrics. */ /* */ - /* */ - /* FreeType error code. 0 means success. */ + /* gindex :: The glyph index. */ /* */ - typedef FT_Error + /* */ + /* abearing :: The horizontal (or vertical) bearing. Set to zero in */ + /* case of error. */ + /* */ + /* aadvance :: The horizontal (or vertical) advance. Set to zero in */ + /* case of error. */ + /* */ + typedef void (*TT_Get_Metrics_Func)( TT_Face face, FT_Bool vertical, FT_UInt gindex, diff --git a/libs/freetype/include/freetype2/t1tables.h b/libs/freetype/include/freetype2/t1tables.h index a14255e5f58..61aefdd5413 100644 --- a/libs/freetype/include/freetype2/t1tables.h +++ b/libs/freetype/include/freetype2/t1tables.h @@ -5,7 +5,7 @@ /* Basic Type 1/Type 2 tables definitions and interface (specification */ /* only). */ /* */ -/* Copyright 1996-2004, 2006, 2008, 2009, 2011 by */ +/* Copyright 1996-2004, 2006, 2008, 2009, 2011, 2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -49,6 +49,26 @@ FT_BEGIN_HEADER /* This section contains the definition of Type 1-specific tables, */ /* including structures related to other PostScript font formats. */ /* */ + /* */ + /* PS_FontInfoRec */ + /* PS_FontInfo */ + /* PS_PrivateRec */ + /* PS_Private */ + /* */ + /* CID_FaceDictRec */ + /* CID_FaceDict */ + /* CID_FaceInfoRec */ + /* CID_FaceInfo */ + /* */ + /* FT_Has_PS_Glyph_Names */ + /* FT_Get_PS_Font_Info */ + /* FT_Get_PS_Font_Private */ + /* FT_Get_PS_Font_Value */ + /* */ + /* T1_Blend_Flags */ + /* T1_EncodingType */ + /* PS_Dict_Keys */ + /* */ /*************************************************************************/ @@ -190,14 +210,30 @@ FT_BEGIN_HEADER /* given blend dictionary (font info or private). Used to support */ /* Multiple Masters fonts. */ /* */ + /* */ + /* T1_BLEND_UNDERLINE_POSITION :: */ + /* T1_BLEND_UNDERLINE_THICKNESS :: */ + /* T1_BLEND_ITALIC_ANGLE :: */ + /* T1_BLEND_BLUE_VALUES :: */ + /* T1_BLEND_OTHER_BLUES :: */ + /* T1_BLEND_STANDARD_WIDTH :: */ + /* T1_BLEND_STANDARD_HEIGHT :: */ + /* T1_BLEND_STEM_SNAP_WIDTHS :: */ + /* T1_BLEND_STEM_SNAP_HEIGHTS :: */ + /* T1_BLEND_BLUE_SCALE :: */ + /* T1_BLEND_BLUE_SHIFT :: */ + /* T1_BLEND_FAMILY_BLUES :: */ + /* T1_BLEND_FAMILY_OTHER_BLUES :: */ + /* T1_BLEND_FORCE_BOLD :: */ + /* */ typedef enum T1_Blend_Flags_ { - /*# required fields in a FontInfo blend dictionary */ + /* required fields in a FontInfo blend dictionary */ T1_BLEND_UNDERLINE_POSITION = 0, T1_BLEND_UNDERLINE_THICKNESS, T1_BLEND_ITALIC_ANGLE, - /*# required fields in a Private blend dictionary */ + /* required fields in a Private blend dictionary */ T1_BLEND_BLUE_VALUES, T1_BLEND_OTHER_BLUES, T1_BLEND_STANDARD_WIDTH, @@ -210,15 +246,13 @@ FT_BEGIN_HEADER T1_BLEND_FAMILY_OTHER_BLUES, T1_BLEND_FORCE_BOLD, - /*# never remove */ - T1_BLEND_MAX + T1_BLEND_MAX /* do not remove */ } T1_Blend_Flags; - /* */ - - /*# backwards compatible definitions */ + /* these constants are deprecated; use the corresponding */ + /* `T1_Blend_Flags' values instead */ #define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION #define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS #define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE @@ -235,6 +269,8 @@ FT_BEGIN_HEADER #define t1_blend_force_bold T1_BLEND_FORCE_BOLD #define t1_blend_max T1_BLEND_MAX + /* */ + /* maximum number of Multiple Masters designs, as defined in the spec */ #define T1_MAX_MM_DESIGNS 16 @@ -333,10 +369,17 @@ FT_BEGIN_HEADER /* */ typedef struct CID_FaceDictRec_* CID_FaceDict; - /* */ - - /* backwards-compatible definition */ + /*************************************************************************/ + /* */ + /* */ + /* CID_FontDict */ + /* */ + /* */ + /* This type is equivalent to @CID_FaceDictRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ typedef CID_FaceDictRec CID_FontDict; @@ -503,6 +546,13 @@ FT_BEGIN_HEADER /* An enumeration describing the `Encoding' entry in a Type 1 */ /* dictionary. */ /* */ + /* */ + /* T1_ENCODING_TYPE_NONE :: */ + /* T1_ENCODING_TYPE_ARRAY :: */ + /* T1_ENCODING_TYPE_STANDARD :: */ + /* T1_ENCODING_TYPE_ISOLATIN1 :: */ + /* T1_ENCODING_TYPE_EXPERT :: */ + /* */ typedef enum T1_EncodingType_ { T1_ENCODING_TYPE_NONE = 0, @@ -523,6 +573,54 @@ FT_BEGIN_HEADER /* An enumeration used in calls to @FT_Get_PS_Font_Value to identify */ /* the Type~1 dictionary entry to retrieve. */ /* */ + /* */ + /* PS_DICT_FONT_TYPE :: */ + /* PS_DICT_FONT_MATRIX :: */ + /* PS_DICT_FONT_BBOX :: */ + /* PS_DICT_PAINT_TYPE :: */ + /* PS_DICT_FONT_NAME :: */ + /* PS_DICT_UNIQUE_ID :: */ + /* PS_DICT_NUM_CHAR_STRINGS :: */ + /* PS_DICT_CHAR_STRING_KEY :: */ + /* PS_DICT_CHAR_STRING :: */ + /* PS_DICT_ENCODING_TYPE :: */ + /* PS_DICT_ENCODING_ENTRY :: */ + /* PS_DICT_NUM_SUBRS :: */ + /* PS_DICT_SUBR :: */ + /* PS_DICT_STD_HW :: */ + /* PS_DICT_STD_VW :: */ + /* PS_DICT_NUM_BLUE_VALUES :: */ + /* PS_DICT_BLUE_VALUE :: */ + /* PS_DICT_BLUE_FUZZ :: */ + /* PS_DICT_NUM_OTHER_BLUES :: */ + /* PS_DICT_OTHER_BLUE :: */ + /* PS_DICT_NUM_FAMILY_BLUES :: */ + /* PS_DICT_FAMILY_BLUE :: */ + /* PS_DICT_NUM_FAMILY_OTHER_BLUES :: */ + /* PS_DICT_FAMILY_OTHER_BLUE :: */ + /* PS_DICT_BLUE_SCALE :: */ + /* PS_DICT_BLUE_SHIFT :: */ + /* PS_DICT_NUM_STEM_SNAP_H :: */ + /* PS_DICT_STEM_SNAP_H :: */ + /* PS_DICT_NUM_STEM_SNAP_V :: */ + /* PS_DICT_STEM_SNAP_V :: */ + /* PS_DICT_FORCE_BOLD :: */ + /* PS_DICT_RND_STEM_UP :: */ + /* PS_DICT_MIN_FEATURE :: */ + /* PS_DICT_LEN_IV :: */ + /* PS_DICT_PASSWORD :: */ + /* PS_DICT_LANGUAGE_GROUP :: */ + /* PS_DICT_VERSION :: */ + /* PS_DICT_NOTICE :: */ + /* PS_DICT_FULL_NAME :: */ + /* PS_DICT_FAMILY_NAME :: */ + /* PS_DICT_WEIGHT :: */ + /* PS_DICT_IS_FIXED_PITCH :: */ + /* PS_DICT_UNDERLINE_POSITION :: */ + /* PS_DICT_UNDERLINE_THICKNESS :: */ + /* PS_DICT_FS_TYPE :: */ + /* PS_DICT_ITALIC_ANGLE :: */ + /* */ typedef enum PS_Dict_Keys_ { /* conventionally in the font dictionary */ diff --git a/libs/freetype/include/freetype2/ttnameid.h b/libs/freetype/include/freetype2/ttnameid.h index 9711d1d9475..e65b5581274 100644 --- a/libs/freetype/include/freetype2/ttnameid.h +++ b/libs/freetype/include/freetype2/ttnameid.h @@ -4,7 +4,7 @@ /* */ /* TrueType name ID definitions (specification only). */ /* */ -/* Copyright 1996-2004, 2006-2008, 2012, 2013 by */ +/* Copyright 1996-2004, 2006-2008, 2012-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -470,26 +470,26 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_ARABIC_GENERAL 0x0001 #define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 #define TT_MS_LANGID_ARABIC_IRAQ 0x0801 -#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0C01 #define TT_MS_LANGID_ARABIC_LIBYA 0x1001 #define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 #define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 -#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1C01 #define TT_MS_LANGID_ARABIC_OMAN 0x2001 #define TT_MS_LANGID_ARABIC_YEMEN 0x2401 #define TT_MS_LANGID_ARABIC_SYRIA 0x2801 -#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2C01 #define TT_MS_LANGID_ARABIC_LEBANON 0x3001 #define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 #define TT_MS_LANGID_ARABIC_UAE 0x3801 -#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3C01 #define TT_MS_LANGID_ARABIC_QATAR 0x4001 #define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 #define TT_MS_LANGID_CATALAN_SPAIN 0x0403 #define TT_MS_LANGID_CHINESE_GENERAL 0x0004 #define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 #define TT_MS_LANGID_CHINESE_PRC 0x0804 -#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0C04 #define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 #if 1 /* this looks like the correct value */ @@ -507,7 +507,7 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_DANISH_DENMARK 0x0406 #define TT_MS_LANGID_GERMAN_GERMANY 0x0407 #define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 -#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0C07 #define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 #define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 #define TT_MS_LANGID_GREEK_GREECE 0x0408 @@ -520,69 +520,69 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 #define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 -#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0C09 #define TT_MS_LANGID_ENGLISH_CANADA 0x1009 #define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 #define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 -#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1C09 #define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 #define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 #define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 -#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2C09 #define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 #define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 #define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 -#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3C09 #define TT_MS_LANGID_ENGLISH_INDIA 0x4009 #define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 #define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 -#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a -#define TT_MS_LANGID_SPANISH_MEXICO 0x080a -#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a -#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a -#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a -#define TT_MS_LANGID_SPANISH_PANAMA 0x180a -#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a -#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a -#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a -#define TT_MS_LANGID_SPANISH_PERU 0x280a -#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a -#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a -#define TT_MS_LANGID_SPANISH_CHILE 0x340a -#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a -#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a -#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a -#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a -#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a -#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a -#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a -#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540a +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040A +#define TT_MS_LANGID_SPANISH_MEXICO 0x080A +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0C0A +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100A +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140A +#define TT_MS_LANGID_SPANISH_PANAMA 0x180A +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1C0A +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200A +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240A +#define TT_MS_LANGID_SPANISH_PERU 0x280A +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2C0A +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300A +#define TT_MS_LANGID_SPANISH_CHILE 0x340A +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380A +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3C0A +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400A +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440A +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480A +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4C0A +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500A +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540A /* The following ID blatantly violate MS specs by using a */ /* sublanguage > 0x1F. */ -#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40aU -#define TT_MS_LANGID_FINNISH_FINLAND 0x040b -#define TT_MS_LANGID_FRENCH_FRANCE 0x040c -#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c -#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c -#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c -#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c -#define TT_MS_LANGID_FRENCH_MONACO 0x180c -#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c -#define TT_MS_LANGID_FRENCH_REUNION 0x200c -#define TT_MS_LANGID_FRENCH_CONGO 0x240c +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40AU +#define TT_MS_LANGID_FINNISH_FINLAND 0x040B +#define TT_MS_LANGID_FRENCH_FRANCE 0x040C +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080C +#define TT_MS_LANGID_FRENCH_CANADA 0x0C0C +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100C +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140C +#define TT_MS_LANGID_FRENCH_MONACO 0x180C +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1C0C +#define TT_MS_LANGID_FRENCH_REUNION 0x200C +#define TT_MS_LANGID_FRENCH_CONGO 0x240C /* which was formerly: */ #define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO -#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c -#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c -#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c -#define TT_MS_LANGID_FRENCH_MALI 0x340c -#define TT_MS_LANGID_FRENCH_MOROCCO 0x380c -#define TT_MS_LANGID_FRENCH_HAITI 0x3c0c - /* and another violation of the spec (see 0xE40aU) */ -#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40cU -#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d -#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e -#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280C +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2C0C +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300C +#define TT_MS_LANGID_FRENCH_MALI 0x340C +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380C +#define TT_MS_LANGID_FRENCH_HAITI 0x3C0C + /* and another violation of the spec (see 0xE40AU) */ +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40CU +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040D +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040E +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040F #define TT_MS_LANGID_ITALIAN_ITALY 0x0410 #define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 #define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 @@ -600,27 +600,27 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 #define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 #define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 -#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a -#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a -#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041A +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081A +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0C1A #if 0 /* this used to be this value, but it looks like we were wrong */ -#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101A #else /* current sources say */ -#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101a -#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141a +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101A +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141A /* and XPsp2 Platform SDK added (2004-07-26) */ /* Names are shortened to be significant within 40 chars. */ -#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181a -#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181a +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181A +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181A #endif -#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b -#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c -#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d -#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d -#define TT_MS_LANGID_THAI_THAILAND 0x041e -#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041B +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041C +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041D +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081D +#define TT_MS_LANGID_THAI_THAILAND 0x041E +#define TT_MS_LANGID_TURKISH_TURKEY 0x041F #define TT_MS_LANGID_URDU_PAKISTAN 0x0420 #define TT_MS_LANGID_URDU_INDIA 0x0820 #define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 @@ -633,13 +633,13 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 #define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 #define TT_MS_LANGID_FARSI_IRAN 0x0429 -#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a -#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b -#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c -#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c -#define TT_MS_LANGID_BASQUE_SPAIN 0x042d -#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e -#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042A +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042B +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042C +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082C +#define TT_MS_LANGID_BASQUE_SPAIN 0x042D +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042E +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042F #define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 #define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 #define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 @@ -650,32 +650,32 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 #define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 #define TT_MS_LANGID_HINDI_INDIA 0x0439 -#define TT_MS_LANGID_MALTESE_MALTA 0x043a +#define TT_MS_LANGID_MALTESE_MALTA 0x043A /* Added by XPsp2 Platform SDK (2004-07-26) */ -#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043b -#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083b -#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3b -#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103b -#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143b -#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183b -#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3b -#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203b -#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243b +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043B +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083B +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3B +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103B +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143B +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183B +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3B +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203B +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243B /* ... and we also keep our old identifier... */ -#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043B #if 0 /* this seems to be a previous inversion */ -#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c -#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043C +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083C #else -#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c -#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083C +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043C #endif -#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d -#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e -#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e -#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043D +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043E +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083E +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043F #define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN /* Cyrillic*/ 0x0440 /* alias declared in Windows 2000 */ #define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ @@ -693,12 +693,12 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_GUJARATI_INDIA 0x0447 #define TT_MS_LANGID_ORIYA_INDIA 0x0448 #define TT_MS_LANGID_TAMIL_INDIA 0x0449 -#define TT_MS_LANGID_TELUGU_INDIA 0x044a -#define TT_MS_LANGID_KANNADA_INDIA 0x044b -#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c -#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d -#define TT_MS_LANGID_MARATHI_INDIA 0x044e -#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +#define TT_MS_LANGID_TELUGU_INDIA 0x044A +#define TT_MS_LANGID_KANNADA_INDIA 0x044B +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044C +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044D +#define TT_MS_LANGID_MARATHI_INDIA 0x044E +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044F #define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 #define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN 0x0850 #define TT_MS_LANGID_TIBETAN_CHINA 0x0451 @@ -732,13 +732,13 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 #define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 /* Missing a LCID for Sindhi in Devanagari script */ -#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a -#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b -#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c -#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d -#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e -#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045f -#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045A +#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045B +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045C +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045D +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045E +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045F +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085F /* Missing a LCID for Tifinagh script */ #define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 /* Spelled this way by XPsp2 Platform SDK (2004-07-26) */ @@ -758,15 +758,15 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 #define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 #define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 -#define TT_MS_LANGID_YORUBA_NIGERIA 0x046a -#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046b -#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086b -#define TT_MS_LANGID_QUECHUA_PERU 0x0c6b -#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046c +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046A +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046B +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086B +#define TT_MS_LANGID_QUECHUA_PERU 0x0C6B +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046C /* Also spelled by XPsp2 Platform SDK (2004-07-26) */ #define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ TT_MS_LANGID_SEPEDI_SOUTH_AFRICA - /* language codes 0x046d, 0x046e and 0x046f are (still) unknown. */ + /* language codes 0x046D, 0x046E and 0x046F are (still) unknown. */ #define TT_MS_LANGID_IGBO_NIGERIA 0x0470 #define TT_MS_LANGID_KANURI_NIGERIA 0x0471 #define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 @@ -783,12 +783,12 @@ FT_BEGIN_HEADER /* studying). */ #define TT_MS_LANGID_YI_CHINA 0x0478 #define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 - /* language codes from 0x047a to 0x047f are (still) unknown. */ + /* language codes from 0x047A to 0x047F are (still) unknown. */ #define TT_MS_LANGID_UIGHUR_CHINA 0x0480 #define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 #if 0 /* not deemed useful for fonts */ -#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04ff +#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04FF #endif diff --git a/libs/freetype/include/freetype2/tttables.h b/libs/freetype/include/freetype2/tttables.h index bb49dc0dafd..e1d8b05e79c 100644 --- a/libs/freetype/include/freetype2/tttables.h +++ b/libs/freetype/include/freetype2/tttables.h @@ -5,7 +5,7 @@ /* Basic SFNT/TrueType tables definitions and interface */ /* (specification only). */ /* */ -/* Copyright 1996-2005, 2008-2013 by */ +/* Copyright 1996-2005, 2008-2014 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -48,6 +48,25 @@ FT_BEGIN_HEADER /* This section contains the definition of TrueType-specific tables */ /* as well as some routines used to access and process them. */ /* */ + /* */ + /* TT_Header */ + /* TT_HoriHeader */ + /* TT_VertHeader */ + /* TT_OS2 */ + /* TT_Postscript */ + /* TT_PCLT */ + /* TT_MaxProfile */ + /* */ + /* FT_Sfnt_Tag */ + /* FT_Get_Sfnt_Table */ + /* FT_Load_Sfnt_Table */ + /* FT_Sfnt_Table_Info */ + /* */ + /* FT_Get_CMap_Language_ID */ + /* FT_Get_CMap_Format */ + /* */ + /* FT_PARAM_TAG_UNPATENTED_HINTING */ + /* */ /*************************************************************************/ @@ -559,21 +578,44 @@ FT_BEGIN_HEADER /* An enumeration used to specify the index of an SFNT table. */ /* Used in the @FT_Get_Sfnt_Table API function. */ /* */ + /* */ + /* FT_SFNT_HEAD :: To access the font's @TT_Header structure. */ + /* */ + /* FT_SFNT_MAXP :: To access the font's @TT_MaxProfile structure. */ + /* */ + /* FT_SFNT_OS2 :: To access the font's @TT_OS2 structure. */ + /* */ + /* FT_SFNT_HHEA :: To access the font's @TT_HoriHeader structure. */ + /* */ + /* FT_SFNT_VHEA :: To access the font's @TT_VertHeader struture. */ + /* */ + /* FT_SFNT_POST :: To access the font's @TT_Postscript structure. */ + /* */ + /* FT_SFNT_PCLT :: To access the font's @TT_PCLT structure. */ + /* */ typedef enum FT_Sfnt_Tag_ { - ft_sfnt_head = 0, /* TT_Header */ - ft_sfnt_maxp = 1, /* TT_MaxProfile */ - ft_sfnt_os2 = 2, /* TT_OS2 */ - ft_sfnt_hhea = 3, /* TT_HoriHeader */ - ft_sfnt_vhea = 4, /* TT_VertHeader */ - ft_sfnt_post = 5, /* TT_Postscript */ - ft_sfnt_pclt = 6, /* TT_PCLT */ + FT_SFNT_HEAD, + FT_SFNT_MAXP, + FT_SFNT_OS2, + FT_SFNT_HHEA, + FT_SFNT_VHEA, + FT_SFNT_POST, + FT_SFNT_PCLT, - sfnt_max /* internal end mark */ + FT_SFNT_MAX } FT_Sfnt_Tag; - /* */ + /* these constants are deprecated; use the corresponding `FT_Sfnt_Tag' */ + /* values instead */ +#define ft_sfnt_head FT_SFNT_HEAD +#define ft_sfnt_maxp FT_SFNT_MAXP +#define ft_sfnt_os2 FT_SFNT_OS2 +#define ft_sfnt_hhea FT_SFNT_HHEA +#define ft_sfnt_vhea FT_SFNT_VHEA +#define ft_sfnt_post FT_SFNT_POST +#define ft_sfnt_pclt FT_SFNT_PCLT /*************************************************************************/ @@ -611,7 +653,7 @@ FT_BEGIN_HEADER /* */ /* */ /* vert_header = */ - /* (TT_VertHeader*)FT_Get_Sfnt_Table( face, ft_sfnt_vhea ); */ + /* (TT_VertHeader*)FT_Get_Sfnt_Table( face, FT_SFNT_VHEA ); */ /* } */ /* */ FT_EXPORT( void* ) diff --git a/libs/freetype/include/freetype2/ttunpat.h b/libs/freetype/include/freetype2/ttunpat.h index a0162759b78..bf53ddd528f 100644 --- a/libs/freetype/include/freetype2/ttunpat.h +++ b/libs/freetype/include/freetype2/ttunpat.h @@ -48,7 +48,8 @@ FT_BEGIN_HEADER */ #define FT_PARAM_TAG_UNPATENTED_HINTING FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) - /* */ + /* */ + FT_END_HEADER diff --git a/libs/freetype/lib/android/armeabi-v7a/libfreetype.a b/libs/freetype/lib/android/armeabi-v7a/libfreetype.a index 2028c92b0ab..97a45de1a83 100644 Binary files a/libs/freetype/lib/android/armeabi-v7a/libfreetype.a and b/libs/freetype/lib/android/armeabi-v7a/libfreetype.a differ diff --git a/libs/freetype/lib/android/x86/libfreetype.a b/libs/freetype/lib/android/x86/libfreetype.a index f7c764a9009..851f9117781 100644 Binary files a/libs/freetype/lib/android/x86/libfreetype.a and b/libs/freetype/lib/android/x86/libfreetype.a differ diff --git a/libs/freetype/lib/emscripten/libfreetype.bc b/libs/freetype/lib/emscripten/libfreetype.bc index 8f2b301577b..682dbf9b472 100644 Binary files a/libs/freetype/lib/emscripten/libfreetype.bc and b/libs/freetype/lib/emscripten/libfreetype.bc differ diff --git a/libs/freetype/lib/osx/freetype.a b/libs/freetype/lib/osx/freetype.a index 8f9c48b6aea..a94cad3e7a7 100644 Binary files a/libs/freetype/lib/osx/freetype.a and b/libs/freetype/lib/osx/freetype.a differ diff --git a/libs/freetype/lib/win_cb/libfreetype.a b/libs/freetype/lib/win_cb/libfreetype.a deleted file mode 100644 index ba90fe1e78d..00000000000 Binary files a/libs/freetype/lib/win_cb/libfreetype.a and /dev/null differ diff --git a/libs/glew/lib/win_cb/glew32s.lib b/libs/glew/lib/win_cb/glew32s.lib deleted file mode 100644 index 26283a4f995..00000000000 Binary files a/libs/glew/lib/win_cb/glew32s.lib and /dev/null differ diff --git a/libs/glew/lib/win_cb/libglew32.a b/libs/glew/lib/win_cb/libglew32.a deleted file mode 100644 index ffaf6c2dbc9..00000000000 Binary files a/libs/glew/lib/win_cb/libglew32.a and /dev/null differ diff --git a/libs/glfw/lib/msys2/libglfw3.a b/libs/glfw/lib/msys2/libglfw3.a new file mode 100644 index 00000000000..4621a6b863b Binary files /dev/null and b/libs/glfw/lib/msys2/libglfw3.a differ diff --git a/libs/glfw/lib/win_cb/libglfw3.a b/libs/glfw/lib/win_cb/libglfw3.a deleted file mode 100644 index 662a60b2223..00000000000 Binary files a/libs/glfw/lib/win_cb/libglfw3.a and /dev/null differ diff --git a/libs/glu/lib/win_cb/glu32.dll b/libs/glu/lib/win_cb/glu32.dll deleted file mode 100644 index a27605870f0..00000000000 Binary files a/libs/glu/lib/win_cb/glu32.dll and /dev/null differ diff --git a/libs/glu/lib/win_cb/glu32.lib b/libs/glu/lib/win_cb/glu32.lib deleted file mode 100644 index 0fcdfb6b3f1..00000000000 Binary files a/libs/glu/lib/win_cb/glu32.lib and /dev/null differ diff --git a/libs/glut/lib/win_cb/glut32.def b/libs/glut/lib/win_cb/glut32.def deleted file mode 100644 index 48a2c8fc50c..00000000000 --- a/libs/glut/lib/win_cb/glut32.def +++ /dev/null @@ -1,115 +0,0 @@ -EXPORTS -glutAddMenuEntry@8 -glutAddSubMenu@8 -glutAttachMenu@4 -glutBitmapCharacter@8 -glutBitmapLength@8 -glutBitmapWidth@8 -glutButtonBoxFunc@4 -glutChangeToMenuEntry@12 -glutChangeToSubMenu@12 -glutCopyColormap@4 -glutCreateMenu@4 -glutCreateSubWindow@20 -glutCreateWindow@4 -glutDestroyMenu@4 -glutDestroyWindow@4 -glutDetachMenu@4 -glutDeviceGet@4 -glutDialsFunc@4 -glutDisplayFunc@4 -glutEnterGameMode@0 -glutEntryFunc@4 -glutEstablishOverlay@0 -glutExtensionSupported@4 -glutForceJoystickFunc@0 -glutFullScreen@0 -glutGameModeGet@4 -glutGameModeString@4 -glutGet@4 -glutGetColor@8 -glutGetMenu@0 -glutGetModifiers@0 -glutGetWindow@0 -glutHideOverlay@0 -glutHideWindow@0 -glutIconifyWindow@0 -glutIdleFunc@4 -glutIgnoreKeyRepeat@4 -glutInit@8 -glutInitDisplayMode@4 -glutInitDisplayString@4 -glutInitWindowPosition@8 -glutInitWindowSize@8 -glutJoystickFunc@8 -glutKeyboardFunc@4 -glutKeyboardUpFunc@4 -glutLayerGet@4 -glutLeaveGameMode@0 -glutMainLoop@0 -glutMenuStateFunc@4 -glutMenuStatusFunc@4 -glutMotionFunc@4 -glutMouseFunc@4 -glutOverlayDisplayFunc@4 -glutPassiveMotionFunc@4 -glutPopWindow@0 -glutPositionWindow@8 -glutPostOverlayRedisplay@0 -glutPostRedisplay@0 -glutPostWindowOverlayRedisplay@4 -glutPostWindowRedisplay@4 -glutPushWindow@0 -glutRemoveMenuItem@4 -glutRemoveOverlay@0 -glutReportErrors@0 -glutReshapeFunc@4 -glutReshapeWindow@8 -glutSetColor@16 -glutSetCursor@4 -glutSetIconTitle@4 -glutSetKeyRepeat@4 -glutSetMenu@4 -glutSetWindow@4 -glutSetWindowTitle@4 -glutSetupVideoResizing@0 -glutShowOverlay@0 -glutShowWindow@0 -glutSolidCone@24 -glutSolidCube@8 -glutSolidDodecahedron@0 -glutSolidIcosahedron@0 -glutSolidOctahedron@0 -glutSolidSphere@16 -glutSolidTeapot@8 -glutSolidTetrahedron@0 -glutSolidTorus@24 -glutSpaceballButtonFunc@4 -glutSpaceballMotionFunc@4 -glutSpaceballRotateFunc@4 -glutSpecialFunc@4 -glutSpecialUpFunc@4 -glutStopVideoResizing@0 -glutStrokeCharacter@8 -glutStrokeLength@8 -glutStrokeWidth@8 -glutSwapBuffers@0 -glutTabletButtonFunc@4 -glutTabletMotionFunc@4 -glutTimerFunc@12 -glutUseLayer@4 -glutVideoPan@16 -glutVideoResize@16 -glutVideoResizeGet@4 -glutVisibilityFunc@4 -glutWarpPointer@8 -glutWindowStatusFunc@4 -glutWireCone@24 -glutWireCube@8 -glutWireDodecahedron@0 -glutWireIcosahedron@0 -glutWireOctahedron@0 -glutWireSphere@16 -glutWireTeapot@8 -glutWireTetrahedron@0 -glutWireTorus@24 diff --git a/libs/glut/lib/win_cb/libglut.a b/libs/glut/lib/win_cb/libglut.a deleted file mode 100644 index 12679e7c92b..00000000000 Binary files a/libs/glut/lib/win_cb/libglut.a and /dev/null differ diff --git a/libs/json/include/json.hpp b/libs/json/include/json.hpp new file mode 100644 index 00000000000..39ef1fe88de --- /dev/null +++ b/libs/json/include/json.hpp @@ -0,0 +1,8638 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 2.0.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Copyright (c) 2013-2016 Niels Lohmann . +Licensed under the MIT License . +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// enable ssize_t on MinGW +#ifdef __GNUC__ + #ifdef __MINGW32__ + #include + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// enable ssize_t for MSVC +#ifdef _MSC_VER + #include + using ssize_t = SSIZE_T; +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + + +/*! +@brief unnamed namespace with internal helper functions +@since version 1.0.0 +*/ +namespace +{ +/*! +@brief Helper to determine whether there's a key_type for T. +@sa http://stackoverflow.com/a/7728728/266378 +*/ +template +struct has_mapped_type +{ + private: + template static char test(typename C::mapped_type*); + template static char (&test(...))[2]; + public: + static constexpr bool value = sizeof(test(0)) == 1; +}; + +} + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the class + has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +template < + template class ObjectType = std::map, + template class ArrayType = std::vector, + class StringType = std::string, + class BooleanType = bool, + class NumberIntegerType = int64_t, + class NumberUnsignedType = uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator + > +class basic_json +{ + private: + /// workaround type for MSVC + using basic_json_t = basic_json; + + public: + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + // forward declaration + template class json_reverse_iterator; + + /// an iterator for a basic_json container + class iterator; + /// a const iterator for a basic_json container + class const_iterator; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// @{ + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). The + comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default value + for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on the + name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. For + instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and + serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the @ref + max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* preserved + by the library. Therefore, iterating an object may return name/value pairs + in a different order than they were originally stored. In fact, keys will + be traversed in alphabetical order as `std::map` with `std::less` is used + by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType, + AllocatorType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the @ref + max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into byte-sized + characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a constructor. + During deserialization, too large or small integer numbers will be + automatically be stored as @ref number_unsigned_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the template + parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the default + value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], this + class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, the + value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations that + > expect no more precision or range than these provide, in the sense that + > implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + + /////////////////////////// + // JSON type enumeration // + /////////////////////////// + + /*! + @brief the JSON type enumeration + + This enumeration collects the different JSON types. It is internally used + to distinguish the stored values, and the functions @ref is_null(), @ref + is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref + is_number(), and @ref is_discarded() rely on it. + + @since version 1.0.0 + */ + enum class value_t : uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function + }; + + + private: + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + auto deleter = [&](T * object) + { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() noexcept = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + default: + { + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + }; + + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief JSON callback events + + This enumeration lists the parser events that can trigger calling a + callback function of type @ref parser_callback_t during parsing. + + @since version 1.0.0 + */ + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t), it is called on certain + events (passed as @ref parse_event_t via parameter @a event) with a set + recursion depth @a depth and context JSON value @a parsed. The return value + of the callback function is a boolean indicating whether the element that + emitted the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced with + `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t) for examples + + @since version 1.0.0 + */ + using parser_callback_t = std::function; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] value_type the type of the value to create + + @complexity Constant. + + @throw std::bad_alloc if allocation for object, array, or string value + fails + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + @sa @ref basic_json(boolean_t value) -- create a boolean value + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const object_t&) -- create a object value + @sa @ref basic_json(const array_t&) -- create a array value + @sa @ref basic_json(const number_float_t) -- create a number + (floating-point) value + @sa @ref basic_json(const number_integer_t) -- create a number (integer) + value + @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) + value + + @since version 1.0.0 + */ + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) + {} + + /*! + @brief create a null object (implicitly) + + Create a `null` JSON value. This is the implicit version of the `null` + value constructor as it takes no parameters. + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - As postcondition, it holds: `basic_json().empty() == true`. + + @liveexample{The following code shows the constructor for a `null` JSON + value.,basic_json} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + + @since version 1.0.0 + */ + basic_json() noexcept = default; + + /*! + @brief create a null object (explicitly) + + Create a `null` JSON value. This is the explicitly version of the `null` + value constructor as it takes a null pointer as parameter. It allows to + create `null` values by explicitly assigning a `nullptr` to a JSON value. + The passed null pointer itself is not read -- it is only used to choose the + right constructor. + + @complexity Constant. + + @liveexample{The following code shows the constructor with null pointer + parameter.,basic_json__nullptr_t} + + @sa @ref basic_json() -- default constructor (implicitly creating a `null` + value) + + @since version 1.0.0 + */ + basic_json(std::nullptr_t) noexcept + : basic_json(value_t::null) + {} + + /*! + @brief create an object (explicit) + + Create an object JSON value with a given content. + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with an @ref object_t + parameter.,basic_json__object_t} + + @sa @ref basic_json(const CompatibleObjectType&) -- create an object value + from a compatible STL container + + @since version 1.0.0 + */ + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) + {} + + /*! + @brief create an object (implicit) + + Create an object JSON value with a given content. This constructor allows + any type that can be used to construct values of type @ref object_t. + Examples include the types `std::map` and `std::unordered_map`. + + @tparam CompatibleObjectType an object type whose `key_type` and + `value_type` is compatible to @ref object_t + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with several + compatible object type parameters.,basic_json__CompatibleObjectType} + + @sa @ref basic_json(const object_t&) -- create an object value + + @since version 1.0.0 + */ + template ::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleObjectType& val) + : m_type(value_t::object) + { + using std::begin; + using std::end; + m_value.object = create(begin(val), end(val)); + } + + /*! + @brief create an array (explicit) + + Create an array JSON value with a given content. + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with an @ref array_t + parameter.,basic_json__array_t} + + @sa @ref basic_json(const CompatibleArrayType&) -- create an array value + from a compatible STL containers + + @since version 1.0.0 + */ + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) + {} + + /*! + @brief create an array (implicit) + + Create an array JSON value with a given content. This constructor allows + any type that can be used to construct values of type @ref array_t. + Examples include the types `std::vector`, `std::list`, and `std::set`. + + @tparam CompatibleArrayType an object type whose `value_type` is compatible + to @ref array_t + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with several + compatible array type parameters.,basic_json__CompatibleArrayType} + + @sa @ref basic_json(const array_t&) -- create an array value + + @since version 1.0.0 + */ + template ::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleArrayType& val) + : m_type(value_t::array) + { + using std::begin; + using std::end; + m_value.array = create(begin(val), end(val)); + } + + /*! + @brief create a string (explicit) + + Create an string JSON value with a given content. + + @param[in] val a value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with an @ref string_t + parameter.,basic_json__string_t} + + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) + {} + + /*! + @brief create a string (explicit) + + Create a string JSON value with a given content. + + @param[in] val a literal value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with string literal + parameter.,basic_json__string_t_value_type} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a string (implicit) + + Create a string JSON value with a given content. + + @param[in] val a value for the string + + @tparam CompatibleStringType an string type which is compatible to @ref + string_t + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the construction of a string value + from a compatible type.,basic_json__CompatibleStringType} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + + @since version 1.0.0 + */ + template ::value, int>::type + = 0> + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a boolean (explicit) + + Creates a JSON boolean type from a given value. + + @param[in] val a boolean value to store + + @complexity Constant. + + @liveexample{The example below demonstrates boolean + values.,basic_json__boolean_t} + + @since version 1.0.0 + */ + basic_json(boolean_t val) + : m_type(value_t::boolean), m_value(val) + {} + + /*! + @brief create an integer number (explicit) + + Create an integer number JSON value with a given content. + + @tparam T helper type to compare number_integer_t and int (not visible in) + the interface. + + @param[in] val an integer to create a JSON number from + + @note This constructor would have the same signature as @ref + basic_json(const int value), so we need to switch this one off in case + number_integer_t is the same as int. This is done via the helper type @a T. + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value.,basic_json__number_integer_t} + + @sa @ref basic_json(const int) -- create a number value (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_integer_t val) + : m_type(value_t::number_integer), m_value(val) + {} + + /*! + @brief create an integer number from an enum type (explicit) + + Create an integer number JSON value with a given content. + + @param[in] val an integer to create a JSON number from + + @note This constructor allows to pass enums directly to a constructor. As + C++ has no way of specifying the type of an anonymous enum explicitly, we + can only rely on the fact that such values implicitly convert to int. As + int may already be the same type of number_integer_t, we may need to switch + off the constructor @ref basic_json(const number_integer_t). + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value from an anonymous enum.,basic_json__const_int} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const int val) + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an integer number (implicit) + + Create an integer number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_integer_t. Examples may include the types `int`, `int32_t`, or + `short`. + + @tparam CompatibleNumberIntegerType an integer type which is compatible to + @ref number_integer_t. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @liveexample{The example below shows the construction of several integer + number values from compatible + types.,basic_json__CompatibleIntegerNumberType} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const int) -- create a number value (integer) + + @since version 1.0.0 + */ + template::value and + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type + = 0> + basic_json(const CompatibleNumberIntegerType val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an unsigned integer number (explicit) + + Create an unsigned integer number JSON value with a given content. + + @tparam T helper type to compare number_unsigned_t and unsigned int + (not visible in) the interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number + value (unsigned integer) from a compatible number type + + @since version 2.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_unsigned_t val) + : m_type(value_t::number_unsigned), m_value(val) + {} + + /*! + @brief create an unsigned number (implicit) + + Create an unsigned number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_unsigned_t. Examples may include the types `unsigned int`, + `uint32_t`, or `unsigned short`. + + @tparam CompatibleNumberUnsignedType an integer type which is compatible to + @ref number_unsigned_t. + + @param[in] val an unsigned integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const number_unsigned_t) -- create a number value + (unsigned) + + @since version 2.0.0 + */ + template < typename CompatibleNumberUnsignedType, typename + std::enable_if < + std::is_constructible::value and + std::numeric_limits::is_integer and + !std::numeric_limits::is_signed, + CompatibleNumberUnsignedType >::type + = 0 > + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + {} + + /*! + @brief create a floating-point number (explicit) + + Create a floating-point number JSON value with a given content. + + @param[in] val a floating-point value to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such + > as Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The following example creates several floating-point + values.,basic_json__number_float_t} + + @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number + value (floating-point) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const number_float_t val) + : m_type(value_t::number_float), m_value(val) + { + // replace infinity and NAN by null + if (not std::isfinite(val)) + { + m_type = value_t::null; + m_value = json_value(); + } + } + + /*! + @brief create an floating-point number (implicit) + + Create an floating-point number JSON value with a given content. This + constructor allows any type that can be used to construct values of type + @ref number_float_t. Examples may include the types `float`. + + @tparam CompatibleNumberFloatType a floating-point type which is compatible + to @ref number_float_t. + + @param[in] val a floating-point to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such + > as Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The example below shows the construction of several + floating-point number values from compatible + types.,basic_json__CompatibleNumberFloatType} + + @sa @ref basic_json(const number_float_t) -- create a number value + (floating-point) + + @since version 1.0.0 + */ + template::value and + std::is_floating_point::value>::type + > + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) + {} + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are treated + as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has now way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them as + an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(std::initializer_list) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(std::initializer_list) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(std::initializer_list) and + @ref object(std::initializer_list). + + @param[in] manual_type internal parameter; when @a type_deduction is set to + `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw std::domain_error if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string; example: `"cannot create object from + initializer list"` + + @complexity Linear in the size of the initializer list @a init. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(std::initializer_list init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // the initializer list could describe an object + bool is_an_object = true; + + // check if each element is an array with two elements whose first + // element is a string + for (const auto& element : init) + { + if (not element.is_array() or element.size() != 2 + or not element[0].is_string()) + { + // we found an element that makes it impossible to use the + // initializer list as object + is_an_object = false; + break; + } + } + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + throw std::domain_error("cannot create object from initializer list"); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + assert(m_value.object != nullptr); + + for (auto& element : init) + { + m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1])); + } + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(std::move(init)); + } + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot be + realized with the initializer list constructor (@ref + basic_json(std::initializer_list, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor + @ref basic_json(std::initializer_list, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw std::domain_error if @a init is not a pair whose first elements are + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed + value. In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @complexity Linear in @a cnt. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of primitive types (number, boolean, or string), @a first must + be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, std::out_of_range is thrown. + - In case of structured types (array, object), the constructor behaves + as similar versions for `std::vector`. + - In case of a null type, std::domain_error is thrown. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @throw std::domain_error if iterators are not compatible; that is, do not + belong to the same JSON value; example: `"iterators are not compatible"` + @throw std::out_of_range if iterators are for a primitive type (number, + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` + @throw std::bad_alloc if allocation for object, array, or string fails + @throw std::domain_error if called with a null value; example: `"cannot use + construct with iterators from null"` + + @complexity Linear in distance between @a first and @a last. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type) + { + // make sure iterator fits the current value + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators are not compatible"); + } + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + break; + } + + default: + { + break; + } + } + + switch (m_type) + { + case value_t::number_integer: + { + assert(first.m_object != nullptr); + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + assert(first.m_object != nullptr); + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + assert(first.m_object != nullptr); + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + assert(first.m_object != nullptr); + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + assert(first.m_object != nullptr); + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } + + default: + { + assert(first.m_object != nullptr); + throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + } + } + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @complexity Linear in the size of @a other. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @throw std::bad_alloc if allocation for object, array, or string fails. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + switch (m_type) + { + case value_t::object: + { + assert(other.m_value.object != nullptr); + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + assert(other.m_value.array != nullptr); + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + assert(other.m_value.string != nullptr); + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + { + break; + } + } + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post @a other is a JSON null value + + @complexity Constant. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, and + the swap() member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + switch (m_type) + { + case value_t::object: + { + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } + + default: + { + // all other types need no specific destructor + break; + } + } + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's @p json.dumps() function, and currently supports its @p indent + parameter. + + @param[in] indent if indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of 0 + will only insert newlines. -1 (the default) selects the most compact + representation + + @return string containing the serialization of the JSON value + + @complexity Linear. + + @liveexample{The following example shows the effect of different @a indent + parameters to the result of the serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0 + */ + string_t dump(const int indent = -1) const + { + std::stringstream ss; + + if (indent >= 0) + { + dump(ss, true, static_cast(indent)); + } + else + { + dump(ss, false, 0); + } + + return ss.str(); + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @since version 1.0.0 + */ + value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true iff the JSON type is primitive (string, number, + boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true iff the JSON type is structured (array or + object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true iff the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true iff the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true iff the JSON value is a number. This includes + both integer and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true iff the JSON value is an integer or unsigned + integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true iff the JSON value is an unsigned integer + number. This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true iff the JSON value is a floating-point number. + This excludes integer and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true iff the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true iff the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true iff the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is discarded + + This function returns true iff the JSON value was discarded during parsing + with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @since version 1.0.0 + */ + operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get an object (explicit) + template ::value and + std::is_convertible::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an object (explicit) + object_t get_impl(object_t*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value and + not std::is_arithmetic::value and + not std::is_convertible::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + T to_vector; + assert(m_value.array != nullptr); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value + , int>::type = 0> + std::vector get_impl(std::vector*) const + { + if (is_array()) + { + std::vector to_vector; + assert(m_value.array != nullptr); + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + array_t get_impl(array_t*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get a string (explicit) + template ::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_string()) + { + assert(m_value.string != nullptr); + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); + } + } + + /// get a number (explicit) + template::value + , int>::type = 0> + T get_impl(T*) const + { + switch (m_type) + { + case value_t::number_integer: + { + return static_cast(m_value.number_integer); + } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } + + case value_t::number_float: + { + return static_cast(m_value.number_float); + } + + default: + { + throw std::domain_error("type must be number, but is " + type_name()); + } + } + } + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t*) const + { + if (is_boolean()) + { + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); + } + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t*) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + const object_t* get_impl_ptr(const object_t*) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t*) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + const array_t* get_impl_ptr(const array_t*) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t*) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + const string_t* get_impl_ptr(const string_t*) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t*) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + const boolean_t* get_impl_ptr(const boolean_t*) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t*) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t*) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + const number_float_t* get_impl_ptr(const number_float_t*) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + using PointerType = typename std::add_pointer::type; + auto ptr = obj.template get_ptr(); + + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } + } + + public: + + /// @name value access + /// @{ + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON; example: `"type must be object, but is null"` + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @internal + The idea of using a casted null pointer to choose the correct + implementation is from . + @endinternal + + @sa @ref operator ValueType() const for implicit conversion + @sa @ref get() for pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + ValueType get() const + { + return get_impl(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value + , int>::type = 0> + const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get_ptr() noexcept + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + const PointerType get_ptr() const noexcept + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implict reference access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise + + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value + , int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. The + call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t as + well as an initializer list of this type is excluded to avoid ambiguities + as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON, thrown by @ref get() const + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename + std::enable_if < + not std::is_pointer::value + and not std::is_same::value +#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 + and not std::is_same>::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read and + written using `at()`.,at__size_type} + + @since version 1.0.0 + */ + reference at(size_type idx) + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + `at()`.,at__size_type_const} + + @since version 1.0.0 + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using `at()`.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + `at()`.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array or null; example: `"cannot + use operator[] with null"` + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + } + + // [] only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + for (size_t i = m_value.array->size(); i <= idx; ++i) + { + m_value.array->push_back(basic_json()); + } + + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // at only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + } + + // [] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + reference operator[](T * (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + const_reference operator[](T * (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key or + a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template ::value + , int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } + } + else + { + throw std::domain_error("cannot use value() with " + type_name()); + } + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value() + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) or + an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to `{ auto tmp = + c.end(); --tmp; return *tmp; }`. + + @return In case of a structured type (array or object), a reference to the + last element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) or + an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on null value. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. Invalidates iterators and + references at or after the point of the erase, including the end() + iterator. The iterator @a pos must be valid and dereferenceable. Thus the + end() iterator (which is valid, but is not dereferenceable) cannot be used + as a value for @a pos. + + If called on a primitive type other than null, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a pos + refers to the last element, the end() iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` + @throw std::domain_error if called on an iterator which does not belong to + the current JSON value; example: `"iterator does not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterator (i.e., any iterator which is not end()); example: `"iterator out + of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType pos) + { + // make sure iterator fits the current value + if (this != pos.m_object) + { + throw std::domain_error("iterator does not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not pos.m_it.primitive_iterator.is_begin()) + { + throw std::out_of_range("iterator out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. Invalidates + iterators and references at or after the point of the erase, including the + end() iterator. The iterator @a first does not need to be dereferenceable + if `first == last`: erasing an empty range is a no-op. + + If called on a primitive type other than null, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the end() iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` + @throw std::domain_error if called on iterators which does not belong to + the current JSON value; example: `"iterators do not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType first, InteratorType last) + { + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + throw std::domain_error("iterators do not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If ObjectType is the default `std::map` + type, the return value will always be `0` (@a key was not found) or `1` (@a + key was found). + + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"index out of + range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (is_array()) + { + if (idx >= size()) + { + throw std::out_of_range("index out of range"); + } + + assert(m_value.array != nullptr); + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is returned. + + @param[in] key key value of the element to search for + + @return Iterator to an element with key equivalent to @a key. If no such + element is found, past-the-end (see end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + iterator find(typename object_t::key_type key) + { + auto result = end(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + const_iterator find(typename object_t::key_type key) const + { + auto result = cend(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + assert(not is_object() or m_value.object != nullptr); + return is_object() ? m_value.object->count(key) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty + + Checks if a JSON value has no elements. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their `empty()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->empty(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their size() functions have constant complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their `max_size()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->max_size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @note Floating-point numbers are set to `0.0` which will be serialized to + `0`. The vale type remains @ref number_float_t. + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + m_value.string->clear(); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + m_value.array->clear(); + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + m_value.object->clear(); + break; + } + + default: + { + break; + } + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array (move semantics) + assert(m_value.array != nullptr); + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array + assert(m_value.array != nullptr); + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting @a + val. + + @param[in] val the value to add to the JSON object + + @throw std::domain_error when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // add element to array + assert(m_value.object != nullptr); + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return operator[](val.first); + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between pos and end of the + container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + @throw std::domain_error if @a first and @a last do not belong to the same + JSON value; example: `"iterators do not fit"` + @throw std::domain_error if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators do not fit"); + } + + if (first.m_object == this or last.m_object == this) + { + throw std::domain_error("passed iterators may not belong to container"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between @a + pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, std::initializer_list ilist) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw std::domain_error when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + std::swap(*(m_value.array), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + std::swap(*(m_value.object), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (is_string()) + { + assert(m_value.string != nullptr); + std::swap(*(m_value.string), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /// @} + + + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + private: + /*! + @brief comparison operator for JSON types + + Returns an ordering that is similar to Python: + - order: null < boolean < number < object < array < string + - furthermore, each type is not smaller than itself + + @since version 1.0.0 + */ + friend bool operator<(const value_t lhs, const value_t rhs) + { + static constexpr std::array order = {{ + 0, // null + 3, // object + 4, // array + 5, // string + 1, // boolean + 2, // integer + 2, // unsigned + 2, // float + } + }; + + // discarded values are not comparable + if (lhs == value_t::discarded or rhs == value_t::discarded) + { + return false; + } + + return order[static_cast(lhs)] < order[static_cast(rhs)]; + } + + public: + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same. + - Integer and floating-point numbers are automatically converted before + comparison. Floating-point numbers are compared indirectly: two + floating-point numbers `f1` and `f2` are considered equal if neither + `f1 > f2` nor `f2 > f1` holds. + - Two JSON null values are equal. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__equal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator==(const_reference v, std::nullptr_t) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, std::nullptr_t) + */ + friend bool operator==(std::nullptr_t, const_reference v) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `not v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is not null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__notequal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference v, std::nullptr_t) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, std::nullptr_t) + */ + friend bool operator!=(std::nullptr_t, const_reference v) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /// @} + + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. The + indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + j.dump(o, pretty_print, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @copydoc operator<<(std::ostream&, const basic_json&) + */ + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from string + + @param[in] s string to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with and + without callback function.,parse__string__parser_callback_t} + + @sa @ref parse(std::istream&, parser_callback_t) for a version that reads + from an input stream + + @since version 1.0.0 + */ + static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) + { + return parser(s, cb).parse(); + } + + /*! + @brief deserialize from stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with and + without callback function.,parse__istream__parser_callback_t} + + @sa @ref parse(const string_t&, parser_callback_t) for a version that reads + from a string + + @since version 1.0.0 + */ + static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @copydoc parse(std::istream&, parser_callback_t) + */ + static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw std::invalid_argument in case of parse errors + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, parser_callback_t) for a variant with a parser + callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + + /*! + @brief deserialize from stream + @copydoc operator<<(basic_json&, std::istream&) + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + j = parser(i).parse(); + return i; + } + + /// @} + + + private: + /////////////////////////// + // convenience functions // + /////////////////////////// + + /// return the type as string + string_t type_name() const + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s) noexcept + { + std::size_t result = 0; + + for (const auto& c : s) + { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + result += 5; + } + break; + } + } + } + + return result; + } + + /*! + @brief escape a string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. + + @param[in] s the string to escape + @return the escaped string + + @complexity Linear in the length of string @a s. + */ + static string_t escape_string(const string_t& s) noexcept + { + const auto space = extra_space(s); + if (space == 0) + { + return s; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto& c : s) + { + switch (c) + { + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } + + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // convert a number 0..15 to its hex representation + // (0..f) + auto hexify = [](const char v) -> char + { + return (v < 10) ? ('0' + v) : ('a' + v - 10); + }; + + // print character c as \uxxxx + for (const char m : + { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + }) + { + result[++pos] = m; + } + + ++pos; + } + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; + } + } + } + + return result; + } + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is called + recursively. Note that + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[out] o stream to write to + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) const + { + // variable to hold indentation for recursive calls + unsigned int new_indent = current_indent; + + switch (m_type) + { + case value_t::object: + { + assert(m_value.object != nullptr); + + if (m_value.object->empty()) + { + o << "{}"; + return; + } + + o << "{"; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + { + if (i != m_value.object->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' ') << "\"" + << escape_string(i->first) << "\":" + << (pretty_print ? " " : ""); + i->second.dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') + "}"; + return; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + + if (m_value.array->empty()) + { + o << "[]"; + return; + } + + o << "["; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + { + if (i != m_value.array->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' '); + i->dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') << "]"; + return; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + o << string_t("\"") << escape_string(*m_value.string) << "\""; + return; + } + + case value_t::boolean: + { + o << (m_value.boolean ? "true" : "false"); + return; + } + + case value_t::number_integer: + { + o << m_value.number_integer; + return; + } + + case value_t::number_unsigned: + { + o << m_value.number_unsigned; + return; + } + + case value_t::number_float: + { + // If the number is an integer then output as a fixed with with + // precision 1 to output "0.0", "1.0" etc as expected for some + // round trip tests otherwise 15 digits of precision allows + // round-trip IEEE 754 string->double->string; to be safe, we + // read this value from + // std::numeric_limits::digits10 + if (std::fmod(m_value.number_float, 1) == 0) + { + o << std::fixed << std::setprecision(1); + } + else + { + // std::defaultfloat not supported in gcc version < 5 + o.unsetf(std::ios_base::floatfield); + o << std::setprecision(std::numeric_limits::digits10); + } + o << m_value.number_float; + return; + } + + case value_t::discarded: + { + o << ""; + return; + } + + case value_t::null: + { + o << "null"; + return; + } + } + } + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + + private: + /////////////// + // iterators // + /////////////// + + /*! + @brief an iterator for primitive JSON types + + This class models an iterator for primitive JSON types (boolean, number, + string). It's only purpose is to allow the iterator/const_iterator classes + to "iterate" over primitive values. Internally, the iterator is modeled by + a `difference_type` variable. Value begin_value (`0`) models the begin, + end_value (`1`) models past the end. + */ + class primitive_iterator_t + { + public: + /// set iterator to a defined beginning + void set_begin() + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + bool is_begin() const + { + return (m_it == begin_value); + } + + /// return whether the iterator is at end + bool is_end() const + { + return (m_it == end_value); + } + + /// return reference to the value to change and compare + operator difference_type& () + { + return m_it; + } + + /// return value to compare + operator difference_type () const + { + return m_it; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; + + /*! + @brief an iterator value + + @note This structure could easily be a union, but MSVC currently does not + allow unions members with complex constructors, see + https://github.com/nlohmann/json/pull/105. + */ + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; + + /// create an uninitialized internal_iterator + internal_iterator() + : object_iterator(), array_iterator(), primitive_iterator() + {} + }; + + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + iteration_proxy_internal(IteratorType it) + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() + { + return iteration_proxy_internal(container.end()); + } + }; + + public: + /*! + @brief a const random access iterator for the @ref basic_json class + + This class implements a const iterator for the @ref basic_json class. From + this class, the @ref iterator class is derived. + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + + @since version 1.0.0 + */ + class const_iterator : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; + + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename basic_json::const_pointer; + /// defines a reference to the type iterated over (value_type) + using reference = typename basic_json::const_reference; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// default constructor + const_iterator() = default; + + /// constructor for a given JSON instance + const_iterator(pointer object) : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /// copy constructor given a nonconst iterator + const_iterator(const iterator& other) : m_object(other.m_object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = other.m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = other.m_it.array_iterator; + break; + } + + default: + { + m_it.primitive_iterator = other.m_it.primitive_iterator; + break; + } + } + } + + /// copy constructor + const_iterator(const const_iterator& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /// copy assignment + const_iterator& operator=(const_iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; + } + + private: + /// set the iterator to the first value + void set_begin() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /// set the iterator past the last value + void set_end() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /// return a reference to the value pointed to by the iterator + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// dereference the iterator + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// post-increment (it++) + const_iterator operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /// pre-increment (++it) + const_iterator& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + ++m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + ++m_it.array_iterator; + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// post-decrement (it--) + const_iterator operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /// pre-decrement (--it) + const_iterator& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + --m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + --m_it.array_iterator; + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// comparison: equal + bool operator==(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + } + + /// comparison: not equal + bool operator!=(const const_iterator& other) const + { + return not operator==(other); + } + + /// comparison: smaller + bool operator<(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot compare order of object iterators"); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + } + + /// comparison: less than or equal + bool operator<=(const const_iterator& other) const + { + return not other.operator < (*this); + } + + /// comparison: greater than + bool operator>(const const_iterator& other) const + { + return not operator<=(other); + } + + /// comparison: greater than or equal + bool operator>=(const const_iterator& other) const + { + return not operator<(other); + } + + /// add to iterator + const_iterator& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + m_it.array_iterator += i; + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /// subtract from iterator + const_iterator& operator-=(difference_type i) + { + return operator+=(-i); + } + + /// add to iterator + const_iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + const_iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const const_iterator& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + } + + /// access to successor + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use operator[] for object iterators"); + } + + case basic_json::value_t::array: + { + return *(m_it.array_iterator + n); + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } + } + + /// return the value of an iterator + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; + + /*! + @brief a mutable random access iterator for the @ref basic_json class + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element. + + @since version 1.0.0 + */ + class iterator : public const_iterator + { + public: + using base_iterator = const_iterator; + using pointer = typename basic_json::pointer; + using reference = typename basic_json::reference; + + /// default constructor + iterator() = default; + + /// constructor for a given JSON instance + iterator(pointer object) noexcept + : base_iterator(object) + {} + + /// copy constructor + iterator(const iterator& other) noexcept + : base_iterator(other) + {} + + /// copy assignment + iterator& operator=(iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + base_iterator::operator=(other); + return *this; + } + + /// return a reference to the value pointed to by the iterator + reference operator*() + { + return const_cast(base_iterator::operator*()); + } + + /// dereference the iterator + pointer operator->() + { + return const_cast(base_iterator::operator->()); + } + + /// post-increment (it++) + iterator operator++(int) + { + iterator result = *this; + base_iterator::operator++(); + return result; + } + + /// pre-increment (++it) + iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + iterator operator--(int) + { + iterator result = *this; + base_iterator::operator--(); + return result; + } + + /// pre-decrement (--it) + iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// subtract from iterator + iterator& operator-=(difference_type i) + { + base_iterator::operator-=(i); + return *this; + } + + /// add to iterator + iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const iterator& other) const + { + return base_iterator::operator-(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return const_cast(base_iterator::operator[](n)); + } + + /// return the value of an iterator + reference value() const + { + return const_cast(base_iterator::value()); + } + }; + + /*! + @brief a template for a reverse iterator class + + @tparam Base the base iterator type to reverse. Valid types are @ref + iterator (to create @ref reverse_iterator) and @ref const_iterator (to + create @ref const_reverse_iterator). + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + + @since version 1.0.0 + */ + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) + : base_iterator(it) + {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) + : base_iterator(it) + {} + + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return this->base() - other.base(); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } + }; + + + private: + ////////////////////// + // lexer and parser // + ////////////////////// + + /*! + @brief lexical analysis + + This class organizes the lexical analysis during JSON deserialization. The + core of it is a scanner generated by [re2c](http://re2c.org) that processes + a buffer and recognizes tokens according to RFC 7159. + */ + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the "true" literal + literal_false, ///< the "false" literal + literal_null, ///< the "null" literal + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value + begin_array, ///< the character for array begin "[" + begin_object, ///< the character for object begin "{" + end_array, ///< the character for array end "]" + end_object, ///< the character for object end "}" + name_separator, ///< the name separator ":" + value_separator, ///< the value separator "," + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; + + /// the char type to use in the lexer + using lexer_char_t = unsigned char; + + /// constructor with a given buffer + explicit lexer(const string_t& s) noexcept + : m_stream(nullptr), m_buffer(s) + { + m_content = reinterpret_cast(s.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + s.size(); + } + + /// constructor with a given stream + explicit lexer(std::istream* s) noexcept + : m_stream(s), m_buffer() + { + assert(m_stream != nullptr); + getline(*m_stream, m_buffer); + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + m_buffer.size(); + } + + /// default constructor + lexer() = default; + + // switch off unwanted functions + lexer(const lexer&) = delete; + lexer operator=(const lexer&) = delete; + + /*! + @brief create a string from a Unicode code point + + @param[in] codepoint1 the code point (can be high surrogate) + @param[in] codepoint2 the code point (can be low surrogate or 0) + + @return string representation of the code point + + @throw std::out_of_range if code point is >0x10ffff; example: `"code + points above 0x10FFFF are invalid"` + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` + + @see + */ + static string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) + { + // calculate the codepoint from the given code points + std::size_t codepoint = codepoint1; + + // check if codepoint1 is a high surrogate + if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) + { + // check if codepoint2 is a low surrogate + if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + { + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + throw std::invalid_argument("missing or wrong low surrogate"); + } + } + + string_t result; + + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + result.append(1, static_cast(codepoint)); + } + else if (codepoint <= 0x7ff) + { + // 2-byte characters: 110xxxxx 10xxxxxx + result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0xffff) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0x10ffff) + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); + result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + throw std::out_of_range("code points above 0x10FFFF are invalid"); + } + + return result; + } + + /// return name of values of type token_type (only used for errors) + static std::string token_type_name(token_type t) + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_number: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + } + + /*! + This function implements a scanner for JSON. It is specified using + regular expressions that try to follow RFC 7159 as close as possible. + These regular expressions are then translated into a minimized + deterministic finite automaton (DFA) by the tool + [re2c](http://re2c.org). As a result, the translated code for this + function consists of a large block of code with `goto` jumps. + + @return the class of the next token read from the buffer + */ + token_type scan() noexcept + { + // pointer for backtracking information + m_marker = nullptr; + + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); + + + { + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 160, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + if ((m_limit - m_cursor) < 5) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + if (yych <= '\\') + { + if (yych <= '-') + { + if (yych <= '"') + { + if (yych <= 0x00) + { + goto basic_json_parser_2; + } + if (yych <= '!') + { + goto basic_json_parser_4; + } + goto basic_json_parser_9; + } + else + { + if (yych <= '+') + { + goto basic_json_parser_4; + } + if (yych <= ',') + { + goto basic_json_parser_10; + } + goto basic_json_parser_12; + } + } + else + { + if (yych <= '9') + { + if (yych <= '/') + { + goto basic_json_parser_4; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + goto basic_json_parser_15; + } + else + { + if (yych <= ':') + { + goto basic_json_parser_17; + } + if (yych == '[') + { + goto basic_json_parser_19; + } + goto basic_json_parser_4; + } + } + } + else + { + if (yych <= 't') + { + if (yych <= 'f') + { + if (yych <= ']') + { + goto basic_json_parser_21; + } + if (yych <= 'e') + { + goto basic_json_parser_4; + } + goto basic_json_parser_23; + } + else + { + if (yych == 'n') + { + goto basic_json_parser_24; + } + if (yych <= 's') + { + goto basic_json_parser_4; + } + goto basic_json_parser_25; + } + } + else + { + if (yych <= '|') + { + if (yych == '{') + { + goto basic_json_parser_26; + } + goto basic_json_parser_4; + } + else + { + if (yych <= '}') + { + goto basic_json_parser_28; + } + if (yych == 0xEF) + { + goto basic_json_parser_30; + } + goto basic_json_parser_4; + } + } + } +basic_json_parser_2: + ++m_cursor; + { + return token_type::end_of_input; + } +basic_json_parser_4: + ++m_cursor; +basic_json_parser_5: + { + return token_type::parse_error; + } +basic_json_parser_6: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + { + return scan(); + } +basic_json_parser_9: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x0F) + { + goto basic_json_parser_5; + } + goto basic_json_parser_32; +basic_json_parser_10: + ++m_cursor; + { + return token_type::value_separator; + } +basic_json_parser_12: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_5; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + if (yych <= '9') + { + goto basic_json_parser_15; + } + goto basic_json_parser_5; +basic_json_parser_13: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_37; + } + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + } +basic_json_parser_14: + { + return token_type::value_number; + } +basic_json_parser_15: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 64) + { + goto basic_json_parser_15; + } + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_37; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_17: + ++m_cursor; + { + return token_type::name_separator; + } +basic_json_parser_19: + ++m_cursor; + { + return token_type::begin_array; + } +basic_json_parser_21: + ++m_cursor; + { + return token_type::end_array; + } +basic_json_parser_23: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') + { + goto basic_json_parser_39; + } + goto basic_json_parser_5; +basic_json_parser_24: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_40; + } + goto basic_json_parser_5; +basic_json_parser_25: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') + { + goto basic_json_parser_41; + } + goto basic_json_parser_5; +basic_json_parser_26: + ++m_cursor; + { + return token_type::begin_object; + } +basic_json_parser_28: + ++m_cursor; + { + return token_type::end_object; + } +basic_json_parser_30: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 0xBB) + { + goto basic_json_parser_42; + } + goto basic_json_parser_5; +basic_json_parser_31: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; +basic_json_parser_32: + if (yybm[0 + yych] & 128) + { + goto basic_json_parser_31; + } + if (yych <= 0x0F) + { + goto basic_json_parser_33; + } + if (yych <= '"') + { + goto basic_json_parser_34; + } + goto basic_json_parser_36; +basic_json_parser_33: + m_cursor = m_marker; + if (yyaccept == 0) + { + goto basic_json_parser_5; + } + else + { + goto basic_json_parser_14; + } +basic_json_parser_34: + ++m_cursor; + { + return token_type::value_string; + } +basic_json_parser_36: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'e') + { + if (yych <= '/') + { + if (yych == '"') + { + goto basic_json_parser_31; + } + if (yych <= '.') + { + goto basic_json_parser_33; + } + goto basic_json_parser_31; + } + else + { + if (yych <= '\\') + { + if (yych <= '[') + { + goto basic_json_parser_33; + } + goto basic_json_parser_31; + } + else + { + if (yych == 'b') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + } + } + else + { + if (yych <= 'q') + { + if (yych <= 'f') + { + goto basic_json_parser_31; + } + if (yych == 'n') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 's') + { + if (yych <= 'r') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 't') + { + goto basic_json_parser_31; + } + if (yych <= 'u') + { + goto basic_json_parser_43; + } + goto basic_json_parser_33; + } + } + } +basic_json_parser_37: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } + goto basic_json_parser_33; +basic_json_parser_38: + yych = *++m_cursor; + if (yych <= ',') + { + if (yych == '+') + { + goto basic_json_parser_46; + } + goto basic_json_parser_33; + } + else + { + if (yych <= '-') + { + goto basic_json_parser_46; + } + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_47; + } + goto basic_json_parser_33; + } +basic_json_parser_39: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_49; + } + goto basic_json_parser_33; +basic_json_parser_40: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_50; + } + goto basic_json_parser_33; +basic_json_parser_41: + yych = *++m_cursor; + if (yych == 'u') + { + goto basic_json_parser_51; + } + goto basic_json_parser_33; +basic_json_parser_42: + yych = *++m_cursor; + if (yych == 0xBF) + { + goto basic_json_parser_52; + } + goto basic_json_parser_33; +basic_json_parser_43: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_54; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } +basic_json_parser_44: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'D') + { + if (yych <= '/') + { + goto basic_json_parser_14; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_46: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych >= ':') + { + goto basic_json_parser_33; + } +basic_json_parser_47: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '/') + { + goto basic_json_parser_14; + } + if (yych <= '9') + { + goto basic_json_parser_47; + } + goto basic_json_parser_14; +basic_json_parser_49: + yych = *++m_cursor; + if (yych == 's') + { + goto basic_json_parser_55; + } + goto basic_json_parser_33; +basic_json_parser_50: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_56; + } + goto basic_json_parser_33; +basic_json_parser_51: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_58; + } + goto basic_json_parser_33; +basic_json_parser_52: + ++m_cursor; + { + return scan(); + } +basic_json_parser_54: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_60; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_60; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_60; + } + goto basic_json_parser_33; + } +basic_json_parser_55: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_61; + } + goto basic_json_parser_33; +basic_json_parser_56: + ++m_cursor; + { + return token_type::literal_null; + } +basic_json_parser_58: + ++m_cursor; + { + return token_type::literal_true; + } +basic_json_parser_60: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_63; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_63; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_63; + } + goto basic_json_parser_33; + } +basic_json_parser_61: + ++m_cursor; + { + return token_type::literal_false; + } +basic_json_parser_63: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_31; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + } + + + } + + /// append data from the stream to the internal buffer + void yyfill() noexcept + { + if (m_stream == nullptr or not * m_stream) + { + return; + } + + const ssize_t offset_start = m_start - m_content; + const ssize_t offset_marker = m_marker - m_start; + const ssize_t offset_cursor = m_cursor - m_start; + + m_buffer.erase(0, static_cast(offset_start)); + std::string line; + assert(m_stream != nullptr); + std::getline(*m_stream, line); + m_buffer += "\n" + line; // add line with newline symbol + + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_content; + m_marker = m_start + offset_marker; + m_cursor = m_start + offset_cursor; + m_limit = m_start + m_buffer.size() - 1; + } + + /// return string representation of last read token + string_t get_token() const noexcept + { + assert(m_start != nullptr); + return string_t(reinterpret_cast(m_start), + static_cast(m_cursor - m_start)); + } + + /*! + @brief return string value for string tokens + + The function iterates the characters between the opening and closing + quotes of the string value. The complete string is the range + [m_start,m_cursor). Consequently, we iterate from m_start+1 to + m_cursor-1. + + We differentiate two cases: + + 1. Escaped characters. In this case, a new character is constructed + according to the nature of the escape. Some escapes create new + characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as + is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape + `"\\uxxxx"` need special care. In this case, to_unicode takes care + of the construction of the values. + 2. Unescaped characters are copied as is. + + @return string value of current token without opening and closing quotes + @throw std::out_of_range if to_unicode fails + */ + string_t get_string() const + { + string_t result; + result.reserve(static_cast(m_cursor - m_start - 2)); + + // iterate the result between the quotes + for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) + { + // process escaped characters + if (*i == '\\') + { + // read next character + ++i; + + switch (*i) + { + // the default escapes + case 't': + { + result += "\t"; + break; + } + case 'b': + { + result += "\b"; + break; + } + case 'f': + { + result += "\f"; + break; + } + case 'n': + { + result += "\n"; + break; + } + case 'r': + { + result += "\r"; + break; + } + case '\\': + { + result += "\\"; + break; + } + case '/': + { + result += "/"; + break; + } + case '"': + { + result += "\""; + break; + } + + // unicode + case 'u': + { + // get code xxxx from uxxxx + auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), + 4).c_str(), nullptr, 16); + + // check if codepoint is a high surrogate + if (codepoint >= 0xD800 and codepoint <= 0xDBFF) + { + // make sure there is a subsequent unicode + if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + { + throw std::invalid_argument("missing low surrogate"); + } + + // get code yyyy from uxxxx\uyyyy + auto codepoint2 = std::strtoul(std::string(reinterpret_cast + (i + 7), 4).c_str(), nullptr, 16); + result += to_unicode(codepoint, codepoint2); + // skip the next 10 characters (xxxx\uyyyy) + i += 10; + } + else + { + // add unicode character(s) + result += to_unicode(codepoint); + // skip the next four characters (xxxx) + i += 4; + } + break; + } + } + } + else + { + // all other characters are just copied to the end of the + // string + result.append(1, static_cast(*i)); + } + } + + return result; + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + + @bug This function uses `std::strtof`, `std::strtod`, or `std::strtold` + which use the current C locale to determine which character is used as + decimal point character. This may yield to parse errors if the locale + does not used `.`. + */ + long double str_to_float_t(long double* /* type */, char** endptr) const + { + return std::strtold(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + double str_to_float_t(double* /* type */, char** endptr) const + { + return std::strtod(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + float str_to_float_t(float* /* type */, char** endptr) const + { + return std::strtof(reinterpret_cast(m_start), endptr); + } + + /*! + @brief static_cast between two types and indicate if it results in error + + This function performs a static_cast between @a source and @a dest. It + then checks if a static_cast back to @a dest produces an error. + + @param[in] source the value to cast from + + @param[out] dest the value to cast to + + @return @a true if the cast was performed without error, @a false otherwise + */ + template + bool attempt_cast(T_A source, T_B& dest) const + { + dest = static_cast(source); + return (source == static_cast(dest)); + } + + /*! + @brief return number value for number tokens + + This function translates the last token into the most appropriate + number type (either integer, unsigned integer or floating point), which + is passed back to the caller via the result parameter. The pointer @a + m_start points to the beginning of the parsed number. We first examine + the first character to determine the sign of the number and then pass + this pointer to either @a std::strtoull (if positive) or @a + std::strtoll (if negative), both of which set @a endptr to the first + character past the converted number. If this pointer is not the same as + @a m_cursor, then either more or less characters have been used during + the comparison. + + This can happen for inputs like "01" which will be treated like number + 0 followed by number 1. This will also occur for valid floating point + inputs like "12e3" will be incorrectly read as 12. Numbers that are too + large or too small for a signed/unsigned long long will cause a range + error (@a errno set to ERANGE). The parsed number is cast to a @ref + number_integer_t/@ref number_unsigned_t using the helper function @ref + attempt_cast, which returns @a false if the cast could not be peformed + without error. + + In any of these cases (more/less characters read, range error or a cast + error) the pointer is passed to @a std:strtod, which also sets @a + endptr to the first character past the converted number. The resulting + @ref number_float_t is then cast to a @ref number_integer_t/@ref + number_unsigned_t using @ref attempt_cast and if no error occurs is + stored in that form, otherwise it is stored as a @ref number_float_t. + + A final comparison is made of @a endptr and if still not the same as + @ref m_cursor a bad input is assumed and @a result parameter is set to + NAN. + + @param[out] result @ref basic_json object to receive the number, or NAN + if the conversion read past the current token. The latter case needs to + be treated by the caller function. + */ + void get_number(basic_json& result) const + { + typename string_t::value_type* endptr; + assert(m_start != nullptr); + errno = 0; + + // attempt to parse it as an integer - first checking for a + // negative number + if (*reinterpret_cast(m_start) != '-') + { + // positive, parse with strtoull and attempt cast to + // number_unsigned_t + if (attempt_cast(std::strtoull(reinterpret_cast(m_start), &endptr, + 10), result.m_value.number_unsigned)) + { + result.m_type = value_t::number_unsigned; + } + else + { + // cast failed due to overflow - store as float + result.m_type = value_t::number_float; + } + } + else + { + // Negative, parse with strtoll and attempt cast to + // number_integer_t + if (attempt_cast(std::strtoll(reinterpret_cast(m_start), &endptr, + 10), result.m_value.number_integer)) + { + result.m_type = value_t::number_integer; + } + else + { + // cast failed due to overflow - store as float + result.m_type = value_t::number_float; + } + } + + // check the end of the number was reached and no range error + // occurred + if (reinterpret_cast(endptr) != m_cursor || errno == ERANGE) + { + result.m_type = value_t::number_float; + } + + if (result.m_type == value_t::number_float) + { + // either the number won't fit in an integer (range error from + // strtoull/strtoll or overflow on cast) or there was something + // else after the number, which could be an exponent + + // parse with strtod + result.m_value.number_float = str_to_float_t(static_cast(nullptr), &endptr); + + // anything after the number is an error + if (reinterpret_cast(endptr) != m_cursor) + { + throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number"); + } + } + } + + private: + /// optional input stream + std::istream* m_stream = nullptr; + /// the buffer + string_t m_buffer; + /// the buffer pointer + const lexer_char_t* m_content = nullptr; + /// pointer to the beginning of the current symbol + const lexer_char_t* m_start = nullptr; + /// pointer for backtracking information + const lexer_char_t* m_marker = nullptr; + /// pointer to the current symbol + const lexer_char_t* m_cursor = nullptr; + /// pointer to the end of the buffer + const lexer_char_t* m_limit = nullptr; + }; + + /*! + @brief syntax analysis + + This class implements a recursive decent parser. + */ + class parser + { + public: + /// constructor for strings + parser(const string_t& s, parser_callback_t cb = nullptr) + : callback(cb), m_lexer(s) + { + // read first token + get_token(); + } + + /// a parser reading from an input stream + parser(std::istream& _is, parser_callback_t cb = nullptr) + : callback(cb), m_lexer(&_is) + { + // read first token + get_token(); + } + + /// public parser interface + basic_json parse() + { + basic_json result = parse_internal(true); + + expect(lexer::token_type::end_of_input); + + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : result; + } + + private: + /// the actual parser + basic_json parse_internal(bool keep) + { + auto result = basic_json(value_t::discarded); + + switch (last_token) + { + case lexer::token_type::begin_object: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = json_value(value_t::object); + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse key-value pairs + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing } + expect(lexer::token_type::end_object); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::begin_array: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = json_value(value_t::array); + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse values + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) + { + result.push_back(std::move(value)); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing ] + expect(lexer::token_type::end_array); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::literal_null: + { + get_token(); + result.m_type = value_t::null; + break; + } + + case lexer::token_type::value_string: + { + const auto s = m_lexer.get_string(); + get_token(); + result = basic_json(s); + break; + } + + case lexer::token_type::literal_true: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case lexer::token_type::literal_false: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case lexer::token_type::value_number: + { + m_lexer.get_number(result); + get_token(); + break; + } + + default: + { + // the last token was unexpected + unexpect(last_token); + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + /// get next token from lexer + typename lexer::token_type get_token() + { + last_token = m_lexer.scan(); + return last_token; + } + + void expect(typename lexer::token_type t) const + { + if (t != last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); + throw std::invalid_argument(error_msg); + } + } + + void unexpect(typename lexer::token_type t) const + { + if (t == last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + throw std::invalid_argument(error_msg); + } + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + parser_callback_t callback; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; +}; + + +///////////// +// presets // +///////////// + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which uses +the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + + +///////////////////////// +// nonmember functions // +///////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template <> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template <> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; +} + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It can +be used by adding \p "_json" to a string literal and returns a JSON object if +no parse error occurred. + +@param[in] s a string representation of a JSON object +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t) +{ + return nlohmann::json::parse(reinterpret_cast(s)); +} + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif + +#endif diff --git a/libs/json/include/json.hpp.re2c b/libs/json/include/json.hpp.re2c new file mode 100644 index 00000000000..f49096290dc --- /dev/null +++ b/libs/json/include/json.hpp.re2c @@ -0,0 +1,7948 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 2.0.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Copyright (c) 2013-2016 Niels Lohmann . +Licensed under the MIT License . +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// enable ssize_t on MinGW +#ifdef __GNUC__ + #ifdef __MINGW32__ + #include + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// enable ssize_t for MSVC +#ifdef _MSC_VER + #include + using ssize_t = SSIZE_T; +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + + +/*! +@brief unnamed namespace with internal helper functions +@since version 1.0.0 +*/ +namespace +{ +/*! +@brief Helper to determine whether there's a key_type for T. +@sa http://stackoverflow.com/a/7728728/266378 +*/ +template +struct has_mapped_type +{ + private: + template static char test(typename C::mapped_type*); + template static char (&test(...))[2]; + public: + static constexpr bool value = sizeof(test(0)) == 1; +}; + +} + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the class + has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +template < + template class ObjectType = std::map, + template class ArrayType = std::vector, + class StringType = std::string, + class BooleanType = bool, + class NumberIntegerType = int64_t, + class NumberUnsignedType = uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator + > +class basic_json +{ + private: + /// workaround type for MSVC + using basic_json_t = basic_json; + + public: + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + // forward declaration + template class json_reverse_iterator; + + /// an iterator for a basic_json container + class iterator; + /// a const iterator for a basic_json container + class const_iterator; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// @{ + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). The + comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default value + for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on the + name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. For + instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and + serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the @ref + max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* preserved + by the library. Therefore, iterating an object may return name/value pairs + in a different order than they were originally stored. In fact, keys will + be traversed in alphabetical order as `std::map` with `std::less` is used + by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType, + AllocatorType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the @ref + max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into byte-sized + characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a constructor. + During deserialization, too large or small integer numbers will be + automatically be stored as @ref number_unsigned_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the template + parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the default + value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], this + class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, the + value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations that + > expect no more precision or range than these provide, in the sense that + > implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + + /////////////////////////// + // JSON type enumeration // + /////////////////////////// + + /*! + @brief the JSON type enumeration + + This enumeration collects the different JSON types. It is internally used + to distinguish the stored values, and the functions @ref is_null(), @ref + is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref + is_number(), and @ref is_discarded() rely on it. + + @since version 1.0.0 + */ + enum class value_t : uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function + }; + + + private: + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + auto deleter = [&](T * object) + { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() noexcept = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + default: + { + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + }; + + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief JSON callback events + + This enumeration lists the parser events that can trigger calling a + callback function of type @ref parser_callback_t during parsing. + + @since version 1.0.0 + */ + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t), it is called on certain + events (passed as @ref parse_event_t via parameter @a event) with a set + recursion depth @a depth and context JSON value @a parsed. The return value + of the callback function is a boolean indicating whether the element that + emitted the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced with + `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t) for examples + + @since version 1.0.0 + */ + using parser_callback_t = std::function; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] value_type the type of the value to create + + @complexity Constant. + + @throw std::bad_alloc if allocation for object, array, or string value + fails + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + @sa @ref basic_json(boolean_t value) -- create a boolean value + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const object_t&) -- create a object value + @sa @ref basic_json(const array_t&) -- create a array value + @sa @ref basic_json(const number_float_t) -- create a number + (floating-point) value + @sa @ref basic_json(const number_integer_t) -- create a number (integer) + value + @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) + value + + @since version 1.0.0 + */ + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) + {} + + /*! + @brief create a null object (implicitly) + + Create a `null` JSON value. This is the implicit version of the `null` + value constructor as it takes no parameters. + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - As postcondition, it holds: `basic_json().empty() == true`. + + @liveexample{The following code shows the constructor for a `null` JSON + value.,basic_json} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + + @since version 1.0.0 + */ + basic_json() noexcept = default; + + /*! + @brief create a null object (explicitly) + + Create a `null` JSON value. This is the explicitly version of the `null` + value constructor as it takes a null pointer as parameter. It allows to + create `null` values by explicitly assigning a `nullptr` to a JSON value. + The passed null pointer itself is not read -- it is only used to choose the + right constructor. + + @complexity Constant. + + @liveexample{The following code shows the constructor with null pointer + parameter.,basic_json__nullptr_t} + + @sa @ref basic_json() -- default constructor (implicitly creating a `null` + value) + + @since version 1.0.0 + */ + basic_json(std::nullptr_t) noexcept + : basic_json(value_t::null) + {} + + /*! + @brief create an object (explicit) + + Create an object JSON value with a given content. + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with an @ref object_t + parameter.,basic_json__object_t} + + @sa @ref basic_json(const CompatibleObjectType&) -- create an object value + from a compatible STL container + + @since version 1.0.0 + */ + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) + {} + + /*! + @brief create an object (implicit) + + Create an object JSON value with a given content. This constructor allows + any type that can be used to construct values of type @ref object_t. + Examples include the types `std::map` and `std::unordered_map`. + + @tparam CompatibleObjectType an object type whose `key_type` and + `value_type` is compatible to @ref object_t + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with several + compatible object type parameters.,basic_json__CompatibleObjectType} + + @sa @ref basic_json(const object_t&) -- create an object value + + @since version 1.0.0 + */ + template ::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleObjectType& val) + : m_type(value_t::object) + { + using std::begin; + using std::end; + m_value.object = create(begin(val), end(val)); + } + + /*! + @brief create an array (explicit) + + Create an array JSON value with a given content. + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with an @ref array_t + parameter.,basic_json__array_t} + + @sa @ref basic_json(const CompatibleArrayType&) -- create an array value + from a compatible STL containers + + @since version 1.0.0 + */ + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) + {} + + /*! + @brief create an array (implicit) + + Create an array JSON value with a given content. This constructor allows + any type that can be used to construct values of type @ref array_t. + Examples include the types `std::vector`, `std::list`, and `std::set`. + + @tparam CompatibleArrayType an object type whose `value_type` is compatible + to @ref array_t + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with several + compatible array type parameters.,basic_json__CompatibleArrayType} + + @sa @ref basic_json(const array_t&) -- create an array value + + @since version 1.0.0 + */ + template ::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleArrayType& val) + : m_type(value_t::array) + { + using std::begin; + using std::end; + m_value.array = create(begin(val), end(val)); + } + + /*! + @brief create a string (explicit) + + Create an string JSON value with a given content. + + @param[in] val a value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with an @ref string_t + parameter.,basic_json__string_t} + + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) + {} + + /*! + @brief create a string (explicit) + + Create a string JSON value with a given content. + + @param[in] val a literal value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with string literal + parameter.,basic_json__string_t_value_type} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a string (implicit) + + Create a string JSON value with a given content. + + @param[in] val a value for the string + + @tparam CompatibleStringType an string type which is compatible to @ref + string_t + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the construction of a string value + from a compatible type.,basic_json__CompatibleStringType} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + + @since version 1.0.0 + */ + template ::value, int>::type + = 0> + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a boolean (explicit) + + Creates a JSON boolean type from a given value. + + @param[in] val a boolean value to store + + @complexity Constant. + + @liveexample{The example below demonstrates boolean + values.,basic_json__boolean_t} + + @since version 1.0.0 + */ + basic_json(boolean_t val) + : m_type(value_t::boolean), m_value(val) + {} + + /*! + @brief create an integer number (explicit) + + Create an integer number JSON value with a given content. + + @tparam T helper type to compare number_integer_t and int (not visible in) + the interface. + + @param[in] val an integer to create a JSON number from + + @note This constructor would have the same signature as @ref + basic_json(const int value), so we need to switch this one off in case + number_integer_t is the same as int. This is done via the helper type @a T. + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value.,basic_json__number_integer_t} + + @sa @ref basic_json(const int) -- create a number value (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_integer_t val) + : m_type(value_t::number_integer), m_value(val) + {} + + /*! + @brief create an integer number from an enum type (explicit) + + Create an integer number JSON value with a given content. + + @param[in] val an integer to create a JSON number from + + @note This constructor allows to pass enums directly to a constructor. As + C++ has no way of specifying the type of an anonymous enum explicitly, we + can only rely on the fact that such values implicitly convert to int. As + int may already be the same type of number_integer_t, we may need to switch + off the constructor @ref basic_json(const number_integer_t). + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value from an anonymous enum.,basic_json__const_int} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const int val) + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an integer number (implicit) + + Create an integer number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_integer_t. Examples may include the types `int`, `int32_t`, or + `short`. + + @tparam CompatibleNumberIntegerType an integer type which is compatible to + @ref number_integer_t. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @liveexample{The example below shows the construction of several integer + number values from compatible + types.,basic_json__CompatibleIntegerNumberType} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const int) -- create a number value (integer) + + @since version 1.0.0 + */ + template::value and + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type + = 0> + basic_json(const CompatibleNumberIntegerType val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an unsigned integer number (explicit) + + Create an unsigned integer number JSON value with a given content. + + @tparam T helper type to compare number_unsigned_t and unsigned int + (not visible in) the interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number + value (unsigned integer) from a compatible number type + + @since version 2.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_unsigned_t val) + : m_type(value_t::number_unsigned), m_value(val) + {} + + /*! + @brief create an unsigned number (implicit) + + Create an unsigned number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_unsigned_t. Examples may include the types `unsigned int`, + `uint32_t`, or `unsigned short`. + + @tparam CompatibleNumberUnsignedType an integer type which is compatible to + @ref number_unsigned_t. + + @param[in] val an unsigned integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const number_unsigned_t) -- create a number value + (unsigned) + + @since version 2.0.0 + */ + template < typename CompatibleNumberUnsignedType, typename + std::enable_if < + std::is_constructible::value and + std::numeric_limits::is_integer and + !std::numeric_limits::is_signed, + CompatibleNumberUnsignedType >::type + = 0 > + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + {} + + /*! + @brief create a floating-point number (explicit) + + Create a floating-point number JSON value with a given content. + + @param[in] val a floating-point value to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such + > as Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The following example creates several floating-point + values.,basic_json__number_float_t} + + @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number + value (floating-point) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const number_float_t val) + : m_type(value_t::number_float), m_value(val) + { + // replace infinity and NAN by null + if (not std::isfinite(val)) + { + m_type = value_t::null; + m_value = json_value(); + } + } + + /*! + @brief create an floating-point number (implicit) + + Create an floating-point number JSON value with a given content. This + constructor allows any type that can be used to construct values of type + @ref number_float_t. Examples may include the types `float`. + + @tparam CompatibleNumberFloatType a floating-point type which is compatible + to @ref number_float_t. + + @param[in] val a floating-point to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such + > as Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The example below shows the construction of several + floating-point number values from compatible + types.,basic_json__CompatibleNumberFloatType} + + @sa @ref basic_json(const number_float_t) -- create a number value + (floating-point) + + @since version 1.0.0 + */ + template::value and + std::is_floating_point::value>::type + > + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) + {} + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are treated + as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has now way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them as + an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(std::initializer_list) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(std::initializer_list) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(std::initializer_list) and + @ref object(std::initializer_list). + + @param[in] manual_type internal parameter; when @a type_deduction is set to + `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw std::domain_error if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string; example: `"cannot create object from + initializer list"` + + @complexity Linear in the size of the initializer list @a init. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(std::initializer_list init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // the initializer list could describe an object + bool is_an_object = true; + + // check if each element is an array with two elements whose first + // element is a string + for (const auto& element : init) + { + if (not element.is_array() or element.size() != 2 + or not element[0].is_string()) + { + // we found an element that makes it impossible to use the + // initializer list as object + is_an_object = false; + break; + } + } + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + throw std::domain_error("cannot create object from initializer list"); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + assert(m_value.object != nullptr); + + for (auto& element : init) + { + m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1])); + } + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(std::move(init)); + } + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot be + realized with the initializer list constructor (@ref + basic_json(std::initializer_list, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor + @ref basic_json(std::initializer_list, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw std::domain_error if @a init is not a pair whose first elements are + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed + value. In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @complexity Linear in @a cnt. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of primitive types (number, boolean, or string), @a first must + be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, std::out_of_range is thrown. + - In case of structured types (array, object), the constructor behaves + as similar versions for `std::vector`. + - In case of a null type, std::domain_error is thrown. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @throw std::domain_error if iterators are not compatible; that is, do not + belong to the same JSON value; example: `"iterators are not compatible"` + @throw std::out_of_range if iterators are for a primitive type (number, + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` + @throw std::bad_alloc if allocation for object, array, or string fails + @throw std::domain_error if called with a null value; example: `"cannot use + construct with iterators from null"` + + @complexity Linear in distance between @a first and @a last. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type) + { + // make sure iterator fits the current value + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators are not compatible"); + } + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + break; + } + + default: + { + break; + } + } + + switch (m_type) + { + case value_t::number_integer: + { + assert(first.m_object != nullptr); + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + assert(first.m_object != nullptr); + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + assert(first.m_object != nullptr); + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + assert(first.m_object != nullptr); + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + assert(first.m_object != nullptr); + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } + + default: + { + assert(first.m_object != nullptr); + throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + } + } + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @complexity Linear in the size of @a other. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @throw std::bad_alloc if allocation for object, array, or string fails. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + switch (m_type) + { + case value_t::object: + { + assert(other.m_value.object != nullptr); + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + assert(other.m_value.array != nullptr); + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + assert(other.m_value.string != nullptr); + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + { + break; + } + } + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post @a other is a JSON null value + + @complexity Constant. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, and + the swap() member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + switch (m_type) + { + case value_t::object: + { + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } + + default: + { + // all other types need no specific destructor + break; + } + } + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's @p json.dumps() function, and currently supports its @p indent + parameter. + + @param[in] indent if indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of 0 + will only insert newlines. -1 (the default) selects the most compact + representation + + @return string containing the serialization of the JSON value + + @complexity Linear. + + @liveexample{The following example shows the effect of different @a indent + parameters to the result of the serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0 + */ + string_t dump(const int indent = -1) const + { + std::stringstream ss; + + if (indent >= 0) + { + dump(ss, true, static_cast(indent)); + } + else + { + dump(ss, false, 0); + } + + return ss.str(); + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @since version 1.0.0 + */ + value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true iff the JSON type is primitive (string, number, + boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true iff the JSON type is structured (array or + object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true iff the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true iff the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true iff the JSON value is a number. This includes + both integer and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true iff the JSON value is an integer or unsigned + integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true iff the JSON value is an unsigned integer + number. This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true iff the JSON value is a floating-point number. + This excludes integer and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true iff the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true iff the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true iff the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is discarded + + This function returns true iff the JSON value was discarded during parsing + with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @since version 1.0.0 + */ + operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get an object (explicit) + template ::value and + std::is_convertible::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an object (explicit) + object_t get_impl(object_t*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value and + not std::is_arithmetic::value and + not std::is_convertible::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + T to_vector; + assert(m_value.array != nullptr); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value + , int>::type = 0> + std::vector get_impl(std::vector*) const + { + if (is_array()) + { + std::vector to_vector; + assert(m_value.array != nullptr); + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + array_t get_impl(array_t*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get a string (explicit) + template ::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_string()) + { + assert(m_value.string != nullptr); + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); + } + } + + /// get a number (explicit) + template::value + , int>::type = 0> + T get_impl(T*) const + { + switch (m_type) + { + case value_t::number_integer: + { + return static_cast(m_value.number_integer); + } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } + + case value_t::number_float: + { + return static_cast(m_value.number_float); + } + + default: + { + throw std::domain_error("type must be number, but is " + type_name()); + } + } + } + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t*) const + { + if (is_boolean()) + { + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); + } + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t*) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + const object_t* get_impl_ptr(const object_t*) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t*) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + const array_t* get_impl_ptr(const array_t*) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t*) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + const string_t* get_impl_ptr(const string_t*) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t*) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + const boolean_t* get_impl_ptr(const boolean_t*) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t*) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t*) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + const number_float_t* get_impl_ptr(const number_float_t*) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + using PointerType = typename std::add_pointer::type; + auto ptr = obj.template get_ptr(); + + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } + } + + public: + + /// @name value access + /// @{ + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON; example: `"type must be object, but is null"` + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @internal + The idea of using a casted null pointer to choose the correct + implementation is from . + @endinternal + + @sa @ref operator ValueType() const for implicit conversion + @sa @ref get() for pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + ValueType get() const + { + return get_impl(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value + , int>::type = 0> + const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get_ptr() noexcept + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + const PointerType get_ptr() const noexcept + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implict reference access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise + + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value + , int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. The + call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t as + well as an initializer list of this type is excluded to avoid ambiguities + as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON, thrown by @ref get() const + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename + std::enable_if < + not std::is_pointer::value + and not std::is_same::value +#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 + and not std::is_same>::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read and + written using `at()`.,at__size_type} + + @since version 1.0.0 + */ + reference at(size_type idx) + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + `at()`.,at__size_type_const} + + @since version 1.0.0 + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using `at()`.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + `at()`.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array or null; example: `"cannot + use operator[] with null"` + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + } + + // [] only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + for (size_t i = m_value.array->size(); i <= idx; ++i) + { + m_value.array->push_back(basic_json()); + } + + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // at only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + } + + // [] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + reference operator[](T * (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + const_reference operator[](T * (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key or + a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template ::value + , int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } + } + else + { + throw std::domain_error("cannot use value() with " + type_name()); + } + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value() + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) or + an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to `{ auto tmp = + c.end(); --tmp; return *tmp; }`. + + @return In case of a structured type (array or object), a reference to the + last element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) or + an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on null value. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. Invalidates iterators and + references at or after the point of the erase, including the end() + iterator. The iterator @a pos must be valid and dereferenceable. Thus the + end() iterator (which is valid, but is not dereferenceable) cannot be used + as a value for @a pos. + + If called on a primitive type other than null, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a pos + refers to the last element, the end() iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` + @throw std::domain_error if called on an iterator which does not belong to + the current JSON value; example: `"iterator does not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterator (i.e., any iterator which is not end()); example: `"iterator out + of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType pos) + { + // make sure iterator fits the current value + if (this != pos.m_object) + { + throw std::domain_error("iterator does not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not pos.m_it.primitive_iterator.is_begin()) + { + throw std::out_of_range("iterator out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. Invalidates + iterators and references at or after the point of the erase, including the + end() iterator. The iterator @a first does not need to be dereferenceable + if `first == last`: erasing an empty range is a no-op. + + If called on a primitive type other than null, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the end() iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` + @throw std::domain_error if called on iterators which does not belong to + the current JSON value; example: `"iterators do not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType first, InteratorType last) + { + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + throw std::domain_error("iterators do not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If ObjectType is the default `std::map` + type, the return value will always be `0` (@a key was not found) or `1` (@a + key was found). + + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const size_type) -- removes the element from an array at the + given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"index out of + range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (is_array()) + { + if (idx >= size()) + { + throw std::out_of_range("index out of range"); + } + + assert(m_value.array != nullptr); + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is returned. + + @param[in] key key value of the element to search for + + @return Iterator to an element with key equivalent to @a key. If no such + element is found, past-the-end (see end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + iterator find(typename object_t::key_type key) + { + auto result = end(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + const_iterator find(typename object_t::key_type key) const + { + auto result = cend(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + assert(not is_object() or m_value.object != nullptr); + return is_object() ? m_value.object->count(key) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty + + Checks if a JSON value has no elements. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their `empty()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->empty(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their size() functions have constant complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the + Container concept; that is, their `max_size()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->max_size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @note Floating-point numbers are set to `0.0` which will be serialized to + `0`. The vale type remains @ref number_float_t. + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + m_value.string->clear(); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + m_value.array->clear(); + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + m_value.object->clear(); + break; + } + + default: + { + break; + } + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array (move semantics) + assert(m_value.array != nullptr); + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array + assert(m_value.array != nullptr); + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting @a + val. + + @param[in] val the value to add to the JSON object + + @throw std::domain_error when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // add element to array + assert(m_value.object != nullptr); + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return operator[](val.first); + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between pos and end of the + container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + @throw std::domain_error if @a first and @a last do not belong to the same + JSON value; example: `"iterators do not fit"` + @throw std::domain_error if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators do not fit"); + } + + if (first.m_object == this or last.m_object == this) + { + throw std::domain_error("passed iterators may not belong to container"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between @a + pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, std::initializer_list ilist) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw std::domain_error when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + std::swap(*(m_value.array), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + std::swap(*(m_value.object), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (is_string()) + { + assert(m_value.string != nullptr); + std::swap(*(m_value.string), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /// @} + + + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + private: + /*! + @brief comparison operator for JSON types + + Returns an ordering that is similar to Python: + - order: null < boolean < number < object < array < string + - furthermore, each type is not smaller than itself + + @since version 1.0.0 + */ + friend bool operator<(const value_t lhs, const value_t rhs) + { + static constexpr std::array order = {{ + 0, // null + 3, // object + 4, // array + 5, // string + 1, // boolean + 2, // integer + 2, // unsigned + 2, // float + } + }; + + // discarded values are not comparable + if (lhs == value_t::discarded or rhs == value_t::discarded) + { + return false; + } + + return order[static_cast(lhs)] < order[static_cast(rhs)]; + } + + public: + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same. + - Integer and floating-point numbers are automatically converted before + comparison. Floating-point numbers are compared indirectly: two + floating-point numbers `f1` and `f2` are considered equal if neither + `f1 > f2` nor `f2 > f1` holds. + - Two JSON null values are equal. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__equal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator==(const_reference v, std::nullptr_t) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, std::nullptr_t) + */ + friend bool operator==(std::nullptr_t, const_reference v) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `not v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is not null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__notequal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference v, std::nullptr_t) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, std::nullptr_t) + */ + friend bool operator!=(std::nullptr_t, const_reference v) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /// @} + + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. The + indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + j.dump(o, pretty_print, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @copydoc operator<<(std::ostream&, const basic_json&) + */ + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from string + + @param[in] s string to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with and + without callback function.,parse__string__parser_callback_t} + + @sa @ref parse(std::istream&, parser_callback_t) for a version that reads + from an input stream + + @since version 1.0.0 + */ + static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) + { + return parser(s, cb).parse(); + } + + /*! + @brief deserialize from stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with and + without callback function.,parse__istream__parser_callback_t} + + @sa @ref parse(const string_t&, parser_callback_t) for a version that reads + from a string + + @since version 1.0.0 + */ + static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @copydoc parse(std::istream&, parser_callback_t) + */ + static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw std::invalid_argument in case of parse errors + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, parser_callback_t) for a variant with a parser + callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + + /*! + @brief deserialize from stream + @copydoc operator<<(basic_json&, std::istream&) + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + j = parser(i).parse(); + return i; + } + + /// @} + + + private: + /////////////////////////// + // convenience functions // + /////////////////////////// + + /// return the type as string + string_t type_name() const + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s) noexcept + { + std::size_t result = 0; + + for (const auto& c : s) + { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + result += 5; + } + break; + } + } + } + + return result; + } + + /*! + @brief escape a string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. + + @param[in] s the string to escape + @return the escaped string + + @complexity Linear in the length of string @a s. + */ + static string_t escape_string(const string_t& s) noexcept + { + const auto space = extra_space(s); + if (space == 0) + { + return s; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto& c : s) + { + switch (c) + { + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } + + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // convert a number 0..15 to its hex representation + // (0..f) + auto hexify = [](const char v) -> char + { + return (v < 10) ? ('0' + v) : ('a' + v - 10); + }; + + // print character c as \uxxxx + for (const char m : + { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + }) + { + result[++pos] = m; + } + + ++pos; + } + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; + } + } + } + + return result; + } + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is called + recursively. Note that + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[out] o stream to write to + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) const + { + // variable to hold indentation for recursive calls + unsigned int new_indent = current_indent; + + switch (m_type) + { + case value_t::object: + { + assert(m_value.object != nullptr); + + if (m_value.object->empty()) + { + o << "{}"; + return; + } + + o << "{"; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + { + if (i != m_value.object->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' ') << "\"" + << escape_string(i->first) << "\":" + << (pretty_print ? " " : ""); + i->second.dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') + "}"; + return; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + + if (m_value.array->empty()) + { + o << "[]"; + return; + } + + o << "["; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + { + if (i != m_value.array->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' '); + i->dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') << "]"; + return; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + o << string_t("\"") << escape_string(*m_value.string) << "\""; + return; + } + + case value_t::boolean: + { + o << (m_value.boolean ? "true" : "false"); + return; + } + + case value_t::number_integer: + { + o << m_value.number_integer; + return; + } + + case value_t::number_unsigned: + { + o << m_value.number_unsigned; + return; + } + + case value_t::number_float: + { + // If the number is an integer then output as a fixed with with + // precision 1 to output "0.0", "1.0" etc as expected for some + // round trip tests otherwise 15 digits of precision allows + // round-trip IEEE 754 string->double->string; to be safe, we + // read this value from + // std::numeric_limits::digits10 + if (std::fmod(m_value.number_float, 1) == 0) + { + o << std::fixed << std::setprecision(1); + } + else + { + // std::defaultfloat not supported in gcc version < 5 + o.unsetf(std::ios_base::floatfield); + o << std::setprecision(std::numeric_limits::digits10); + } + o << m_value.number_float; + return; + } + + case value_t::discarded: + { + o << ""; + return; + } + + case value_t::null: + { + o << "null"; + return; + } + } + } + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + + private: + /////////////// + // iterators // + /////////////// + + /*! + @brief an iterator for primitive JSON types + + This class models an iterator for primitive JSON types (boolean, number, + string). It's only purpose is to allow the iterator/const_iterator classes + to "iterate" over primitive values. Internally, the iterator is modeled by + a `difference_type` variable. Value begin_value (`0`) models the begin, + end_value (`1`) models past the end. + */ + class primitive_iterator_t + { + public: + /// set iterator to a defined beginning + void set_begin() + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + bool is_begin() const + { + return (m_it == begin_value); + } + + /// return whether the iterator is at end + bool is_end() const + { + return (m_it == end_value); + } + + /// return reference to the value to change and compare + operator difference_type& () + { + return m_it; + } + + /// return value to compare + operator difference_type () const + { + return m_it; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; + + /*! + @brief an iterator value + + @note This structure could easily be a union, but MSVC currently does not + allow unions members with complex constructors, see + https://github.com/nlohmann/json/pull/105. + */ + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; + + /// create an uninitialized internal_iterator + internal_iterator() + : object_iterator(), array_iterator(), primitive_iterator() + {} + }; + + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + iteration_proxy_internal(IteratorType it) + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() + { + return iteration_proxy_internal(container.end()); + } + }; + + public: + /*! + @brief a const random access iterator for the @ref basic_json class + + This class implements a const iterator for the @ref basic_json class. From + this class, the @ref iterator class is derived. + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + + @since version 1.0.0 + */ + class const_iterator : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; + + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename basic_json::const_pointer; + /// defines a reference to the type iterated over (value_type) + using reference = typename basic_json::const_reference; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// default constructor + const_iterator() = default; + + /// constructor for a given JSON instance + const_iterator(pointer object) : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /// copy constructor given a nonconst iterator + const_iterator(const iterator& other) : m_object(other.m_object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = other.m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = other.m_it.array_iterator; + break; + } + + default: + { + m_it.primitive_iterator = other.m_it.primitive_iterator; + break; + } + } + } + + /// copy constructor + const_iterator(const const_iterator& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /// copy assignment + const_iterator& operator=(const_iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; + } + + private: + /// set the iterator to the first value + void set_begin() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /// set the iterator past the last value + void set_end() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /// return a reference to the value pointed to by the iterator + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// dereference the iterator + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// post-increment (it++) + const_iterator operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /// pre-increment (++it) + const_iterator& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + ++m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + ++m_it.array_iterator; + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// post-decrement (it--) + const_iterator operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /// pre-decrement (--it) + const_iterator& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + --m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + --m_it.array_iterator; + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// comparison: equal + bool operator==(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + } + + /// comparison: not equal + bool operator!=(const const_iterator& other) const + { + return not operator==(other); + } + + /// comparison: smaller + bool operator<(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot compare order of object iterators"); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + } + + /// comparison: less than or equal + bool operator<=(const const_iterator& other) const + { + return not other.operator < (*this); + } + + /// comparison: greater than + bool operator>(const const_iterator& other) const + { + return not operator<=(other); + } + + /// comparison: greater than or equal + bool operator>=(const const_iterator& other) const + { + return not operator<(other); + } + + /// add to iterator + const_iterator& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + m_it.array_iterator += i; + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /// subtract from iterator + const_iterator& operator-=(difference_type i) + { + return operator+=(-i); + } + + /// add to iterator + const_iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + const_iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const const_iterator& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + } + + /// access to successor + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use operator[] for object iterators"); + } + + case basic_json::value_t::array: + { + return *(m_it.array_iterator + n); + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } + } + + /// return the value of an iterator + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; + + /*! + @brief a mutable random access iterator for the @ref basic_json class + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element. + + @since version 1.0.0 + */ + class iterator : public const_iterator + { + public: + using base_iterator = const_iterator; + using pointer = typename basic_json::pointer; + using reference = typename basic_json::reference; + + /// default constructor + iterator() = default; + + /// constructor for a given JSON instance + iterator(pointer object) noexcept + : base_iterator(object) + {} + + /// copy constructor + iterator(const iterator& other) noexcept + : base_iterator(other) + {} + + /// copy assignment + iterator& operator=(iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + base_iterator::operator=(other); + return *this; + } + + /// return a reference to the value pointed to by the iterator + reference operator*() + { + return const_cast(base_iterator::operator*()); + } + + /// dereference the iterator + pointer operator->() + { + return const_cast(base_iterator::operator->()); + } + + /// post-increment (it++) + iterator operator++(int) + { + iterator result = *this; + base_iterator::operator++(); + return result; + } + + /// pre-increment (++it) + iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + iterator operator--(int) + { + iterator result = *this; + base_iterator::operator--(); + return result; + } + + /// pre-decrement (--it) + iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// subtract from iterator + iterator& operator-=(difference_type i) + { + base_iterator::operator-=(i); + return *this; + } + + /// add to iterator + iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const iterator& other) const + { + return base_iterator::operator-(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return const_cast(base_iterator::operator[](n)); + } + + /// return the value of an iterator + reference value() const + { + return const_cast(base_iterator::value()); + } + }; + + /*! + @brief a template for a reverse iterator class + + @tparam Base the base iterator type to reverse. Valid types are @ref + iterator (to create @ref reverse_iterator) and @ref const_iterator (to + create @ref const_reverse_iterator). + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + + @since version 1.0.0 + */ + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) + : base_iterator(it) + {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) + : base_iterator(it) + {} + + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return this->base() - other.base(); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } + }; + + + private: + ////////////////////// + // lexer and parser // + ////////////////////// + + /*! + @brief lexical analysis + + This class organizes the lexical analysis during JSON deserialization. The + core of it is a scanner generated by [re2c](http://re2c.org) that processes + a buffer and recognizes tokens according to RFC 7159. + */ + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the "true" literal + literal_false, ///< the "false" literal + literal_null, ///< the "null" literal + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value + begin_array, ///< the character for array begin "[" + begin_object, ///< the character for object begin "{" + end_array, ///< the character for array end "]" + end_object, ///< the character for object end "}" + name_separator, ///< the name separator ":" + value_separator, ///< the value separator "," + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; + + /// the char type to use in the lexer + using lexer_char_t = unsigned char; + + /// constructor with a given buffer + explicit lexer(const string_t& s) noexcept + : m_stream(nullptr), m_buffer(s) + { + m_content = reinterpret_cast(s.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + s.size(); + } + + /// constructor with a given stream + explicit lexer(std::istream* s) noexcept + : m_stream(s), m_buffer() + { + assert(m_stream != nullptr); + getline(*m_stream, m_buffer); + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + m_buffer.size(); + } + + /// default constructor + lexer() = default; + + // switch off unwanted functions + lexer(const lexer&) = delete; + lexer operator=(const lexer&) = delete; + + /*! + @brief create a string from a Unicode code point + + @param[in] codepoint1 the code point (can be high surrogate) + @param[in] codepoint2 the code point (can be low surrogate or 0) + + @return string representation of the code point + + @throw std::out_of_range if code point is >0x10ffff; example: `"code + points above 0x10FFFF are invalid"` + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` + + @see + */ + static string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) + { + // calculate the codepoint from the given code points + std::size_t codepoint = codepoint1; + + // check if codepoint1 is a high surrogate + if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) + { + // check if codepoint2 is a low surrogate + if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + { + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + throw std::invalid_argument("missing or wrong low surrogate"); + } + } + + string_t result; + + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + result.append(1, static_cast(codepoint)); + } + else if (codepoint <= 0x7ff) + { + // 2-byte characters: 110xxxxx 10xxxxxx + result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0xffff) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0x10ffff) + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); + result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + throw std::out_of_range("code points above 0x10FFFF are invalid"); + } + + return result; + } + + /// return name of values of type token_type (only used for errors) + static std::string token_type_name(token_type t) + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_number: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + } + + /*! + This function implements a scanner for JSON. It is specified using + regular expressions that try to follow RFC 7159 as close as possible. + These regular expressions are then translated into a minimized + deterministic finite automaton (DFA) by the tool + [re2c](http://re2c.org). As a result, the translated code for this + function consists of a large block of code with `goto` jumps. + + @return the class of the next token read from the buffer + */ + token_type scan() noexcept + { + // pointer for backtracking information + m_marker = nullptr; + + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); + + /*!re2c + re2c:define:YYCTYPE = lexer_char_t; + re2c:define:YYCURSOR = m_cursor; + re2c:define:YYLIMIT = m_limit; + re2c:define:YYMARKER = m_marker; + re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; + re2c:yyfill:parameter = 0; + re2c:indent:string = " "; + re2c:indent:top = 1; + re2c:labelprefix = "basic_json_parser_"; + + // ignore whitespace + ws = [ \t\n\r]+; + ws { return scan(); } + + // ignore byte-order-mark + bom = "\xEF\xBB\xBF"; + bom { return scan(); } + + // structural characters + "[" { return token_type::begin_array; } + "]" { return token_type::end_array; } + "{" { return token_type::begin_object; } + "}" { return token_type::end_object; } + "," { return token_type::value_separator; } + ":" { return token_type::name_separator; } + + // literal names + "null" { return token_type::literal_null; } + "true" { return token_type::literal_true; } + "false" { return token_type::literal_false; } + + // number + decimal_point = [.]; + digit = [0-9]; + digit_1_9 = [1-9]; + e = [eE]; + minus = [-]; + plus = [+]; + zero = [0]; + exp = e (minus|plus)? digit+; + frac = decimal_point digit+; + int = (zero|digit_1_9 digit*); + number = minus? int frac? exp?; + number { return token_type::value_number; } + + // string + quotation_mark = [\"]; + escape = [\\]; + unescaped = [^\"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F]; + single_escaped = [\"\\/bfnrt]; + unicode_escaped = [u][0-9a-fA-F]{4}; + escaped = escape (single_escaped | unicode_escaped); + char = unescaped | escaped; + string = quotation_mark char* quotation_mark; + string { return token_type::value_string; } + + // end of file + '\000' { return token_type::end_of_input; } + + // anything else is an error + . { return token_type::parse_error; } + */ + + } + + /// append data from the stream to the internal buffer + void yyfill() noexcept + { + if (m_stream == nullptr or not * m_stream) + { + return; + } + + const ssize_t offset_start = m_start - m_content; + const ssize_t offset_marker = m_marker - m_start; + const ssize_t offset_cursor = m_cursor - m_start; + + m_buffer.erase(0, static_cast(offset_start)); + std::string line; + assert(m_stream != nullptr); + std::getline(*m_stream, line); + m_buffer += "\n" + line; // add line with newline symbol + + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_content; + m_marker = m_start + offset_marker; + m_cursor = m_start + offset_cursor; + m_limit = m_start + m_buffer.size() - 1; + } + + /// return string representation of last read token + string_t get_token() const noexcept + { + assert(m_start != nullptr); + return string_t(reinterpret_cast(m_start), + static_cast(m_cursor - m_start)); + } + + /*! + @brief return string value for string tokens + + The function iterates the characters between the opening and closing + quotes of the string value. The complete string is the range + [m_start,m_cursor). Consequently, we iterate from m_start+1 to + m_cursor-1. + + We differentiate two cases: + + 1. Escaped characters. In this case, a new character is constructed + according to the nature of the escape. Some escapes create new + characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as + is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape + `"\\uxxxx"` need special care. In this case, to_unicode takes care + of the construction of the values. + 2. Unescaped characters are copied as is. + + @return string value of current token without opening and closing quotes + @throw std::out_of_range if to_unicode fails + */ + string_t get_string() const + { + string_t result; + result.reserve(static_cast(m_cursor - m_start - 2)); + + // iterate the result between the quotes + for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) + { + // process escaped characters + if (*i == '\\') + { + // read next character + ++i; + + switch (*i) + { + // the default escapes + case 't': + { + result += "\t"; + break; + } + case 'b': + { + result += "\b"; + break; + } + case 'f': + { + result += "\f"; + break; + } + case 'n': + { + result += "\n"; + break; + } + case 'r': + { + result += "\r"; + break; + } + case '\\': + { + result += "\\"; + break; + } + case '/': + { + result += "/"; + break; + } + case '"': + { + result += "\""; + break; + } + + // unicode + case 'u': + { + // get code xxxx from uxxxx + auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), + 4).c_str(), nullptr, 16); + + // check if codepoint is a high surrogate + if (codepoint >= 0xD800 and codepoint <= 0xDBFF) + { + // make sure there is a subsequent unicode + if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + { + throw std::invalid_argument("missing low surrogate"); + } + + // get code yyyy from uxxxx\uyyyy + auto codepoint2 = std::strtoul(std::string(reinterpret_cast + (i + 7), 4).c_str(), nullptr, 16); + result += to_unicode(codepoint, codepoint2); + // skip the next 10 characters (xxxx\uyyyy) + i += 10; + } + else + { + // add unicode character(s) + result += to_unicode(codepoint); + // skip the next four characters (xxxx) + i += 4; + } + break; + } + } + } + else + { + // all other characters are just copied to the end of the + // string + result.append(1, static_cast(*i)); + } + } + + return result; + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + + @bug This function uses `std::strtof`, `std::strtod`, or `std::strtold` + which use the current C locale to determine which character is used as + decimal point character. This may yield to parse errors if the locale + does not used `.`. + */ + long double str_to_float_t(long double* /* type */, char** endptr) const + { + return std::strtold(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + double str_to_float_t(double* /* type */, char** endptr) const + { + return std::strtod(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to + @a static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + float str_to_float_t(float* /* type */, char** endptr) const + { + return std::strtof(reinterpret_cast(m_start), endptr); + } + + /*! + @brief static_cast between two types and indicate if it results in error + + This function performs a static_cast between @a source and @a dest. It + then checks if a static_cast back to @a dest produces an error. + + @param[in] source the value to cast from + + @param[out] dest the value to cast to + + @return @a true if the cast was performed without error, @a false otherwise + */ + template + bool attempt_cast(T_A source, T_B& dest) const + { + dest = static_cast(source); + return (source == static_cast(dest)); + } + + /*! + @brief return number value for number tokens + + This function translates the last token into the most appropriate + number type (either integer, unsigned integer or floating point), which + is passed back to the caller via the result parameter. The pointer @a + m_start points to the beginning of the parsed number. We first examine + the first character to determine the sign of the number and then pass + this pointer to either @a std::strtoull (if positive) or @a + std::strtoll (if negative), both of which set @a endptr to the first + character past the converted number. If this pointer is not the same as + @a m_cursor, then either more or less characters have been used during + the comparison. + + This can happen for inputs like "01" which will be treated like number + 0 followed by number 1. This will also occur for valid floating point + inputs like "12e3" will be incorrectly read as 12. Numbers that are too + large or too small for a signed/unsigned long long will cause a range + error (@a errno set to ERANGE). The parsed number is cast to a @ref + number_integer_t/@ref number_unsigned_t using the helper function @ref + attempt_cast, which returns @a false if the cast could not be peformed + without error. + + In any of these cases (more/less characters read, range error or a cast + error) the pointer is passed to @a std:strtod, which also sets @a + endptr to the first character past the converted number. The resulting + @ref number_float_t is then cast to a @ref number_integer_t/@ref + number_unsigned_t using @ref attempt_cast and if no error occurs is + stored in that form, otherwise it is stored as a @ref number_float_t. + + A final comparison is made of @a endptr and if still not the same as + @ref m_cursor a bad input is assumed and @a result parameter is set to + NAN. + + @param[out] result @ref basic_json object to receive the number, or NAN + if the conversion read past the current token. The latter case needs to + be treated by the caller function. + */ + void get_number(basic_json& result) const + { + typename string_t::value_type* endptr; + assert(m_start != nullptr); + errno = 0; + + // attempt to parse it as an integer - first checking for a + // negative number + if (*reinterpret_cast(m_start) != '-') + { + // positive, parse with strtoull and attempt cast to + // number_unsigned_t + if (attempt_cast(std::strtoull(reinterpret_cast(m_start), &endptr, + 10), result.m_value.number_unsigned)) + { + result.m_type = value_t::number_unsigned; + } + else + { + // cast failed due to overflow - store as float + result.m_type = value_t::number_float; + } + } + else + { + // Negative, parse with strtoll and attempt cast to + // number_integer_t + if (attempt_cast(std::strtoll(reinterpret_cast(m_start), &endptr, + 10), result.m_value.number_integer)) + { + result.m_type = value_t::number_integer; + } + else + { + // cast failed due to overflow - store as float + result.m_type = value_t::number_float; + } + } + + // check the end of the number was reached and no range error + // occurred + if (reinterpret_cast(endptr) != m_cursor || errno == ERANGE) + { + result.m_type = value_t::number_float; + } + + if (result.m_type == value_t::number_float) + { + // either the number won't fit in an integer (range error from + // strtoull/strtoll or overflow on cast) or there was something + // else after the number, which could be an exponent + + // parse with strtod + result.m_value.number_float = str_to_float_t(static_cast(nullptr), &endptr); + + // anything after the number is an error + if (reinterpret_cast(endptr) != m_cursor) + { + throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number"); + } + } + } + + private: + /// optional input stream + std::istream* m_stream = nullptr; + /// the buffer + string_t m_buffer; + /// the buffer pointer + const lexer_char_t* m_content = nullptr; + /// pointer to the beginning of the current symbol + const lexer_char_t* m_start = nullptr; + /// pointer for backtracking information + const lexer_char_t* m_marker = nullptr; + /// pointer to the current symbol + const lexer_char_t* m_cursor = nullptr; + /// pointer to the end of the buffer + const lexer_char_t* m_limit = nullptr; + }; + + /*! + @brief syntax analysis + + This class implements a recursive decent parser. + */ + class parser + { + public: + /// constructor for strings + parser(const string_t& s, parser_callback_t cb = nullptr) + : callback(cb), m_lexer(s) + { + // read first token + get_token(); + } + + /// a parser reading from an input stream + parser(std::istream& _is, parser_callback_t cb = nullptr) + : callback(cb), m_lexer(&_is) + { + // read first token + get_token(); + } + + /// public parser interface + basic_json parse() + { + basic_json result = parse_internal(true); + + expect(lexer::token_type::end_of_input); + + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : result; + } + + private: + /// the actual parser + basic_json parse_internal(bool keep) + { + auto result = basic_json(value_t::discarded); + + switch (last_token) + { + case lexer::token_type::begin_object: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = json_value(value_t::object); + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse key-value pairs + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing } + expect(lexer::token_type::end_object); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::begin_array: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = json_value(value_t::array); + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse values + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) + { + result.push_back(std::move(value)); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing ] + expect(lexer::token_type::end_array); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::literal_null: + { + get_token(); + result.m_type = value_t::null; + break; + } + + case lexer::token_type::value_string: + { + const auto s = m_lexer.get_string(); + get_token(); + result = basic_json(s); + break; + } + + case lexer::token_type::literal_true: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case lexer::token_type::literal_false: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case lexer::token_type::value_number: + { + m_lexer.get_number(result); + get_token(); + break; + } + + default: + { + // the last token was unexpected + unexpect(last_token); + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + /// get next token from lexer + typename lexer::token_type get_token() + { + last_token = m_lexer.scan(); + return last_token; + } + + void expect(typename lexer::token_type t) const + { + if (t != last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); + throw std::invalid_argument(error_msg); + } + } + + void unexpect(typename lexer::token_type t) const + { + if (t == last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + throw std::invalid_argument(error_msg); + } + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + parser_callback_t callback; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; +}; + + +///////////// +// presets // +///////////// + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which uses +the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + + +///////////////////////// +// nonmember functions // +///////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template <> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template <> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; +} + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It can +be used by adding \p "_json" to a string literal and returns a JSON object if +no parse error occurred. + +@param[in] s a string representation of a JSON object +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t) +{ + return nlohmann::json::parse(reinterpret_cast(s)); +} + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif + +#endif diff --git a/libs/json/license/LICENSE.MIT b/libs/json/license/LICENSE.MIT new file mode 100644 index 00000000000..e2ac4891d4a --- /dev/null +++ b/libs/json/license/LICENSE.MIT @@ -0,0 +1,22 @@ +The library is licensed under the MIT License +: + +Copyright (c) 2013-2016 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/json/license/README.md b/libs/json/license/README.md new file mode 100644 index 00000000000..42489417a02 --- /dev/null +++ b/libs/json/license/README.md @@ -0,0 +1,418 @@ +![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif) + +[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) +[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk?svg=true)](https://ci.appveyor.com/project/nlohmann/json) +[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/WSW3gHHE4UcZ9K3G) +[![Documentation Status](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) +[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) +[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) +[![Gitter](https://badges.gitter.im/nlohmann/json.svg)](https://gitter.im/nlohmann/json?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +## Design goals + +There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: + +- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you know, what I mean. + +- **Trivial integration**. Our whole code consists of a single header file `json.hpp`. That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. + +- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/json_unit.cc) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. + +Other aspects were not so important to us: + +- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. + +- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder). + +See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/CONTRIBUTING.md#please-dont) for more information. + +## Integration + +The single required source, file `json.hpp` is in the `src` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add + +```cpp +#include "json.hpp" + +// for convenience +using json = nlohmann::json; +``` + +to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). + +## Supported compilers + +Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: + +- GCC 4.9 - 6.0 (and possibly later) +- Clang 3.4 - 3.8 (and possibly later) +- Microsoft Visual C++ 14.0 RC (and possibly later) + +I would be happy to learn about other compilers/versions. + +Please note: + +- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. +- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. Please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. + +## Examples + +Here are some examples to give you an idea how to use the class. + +Assume you want to create the JSON object + +```json +{ + "pi": 3.141, + "happy": true, + "name": "Niels", + "nothing": null, + "answer": { + "everything": 42 + }, + "list": [1, 0, 2], + "object": { + "currency": "USD", + "value": 42.99 + } +} +``` + +With the JSON class, you could write: + +```cpp +// create an empty structure (null) +json j; + +// add a number that is stored as double (note the implicit conversion of j to an object) +j["pi"] = 3.141; + +// add a Boolean that is stored as bool +j["happy"] = true; + +// add a string that is stored as std::string +j["name"] = "Niels"; + +// add another null object by passing nullptr +j["nothing"] = nullptr; + +// add an object inside the object +j["answer"]["everything"] = 42; + +// add an array that is stored as std::vector (using an initializer list) +j["list"] = { 1, 0, 2 }; + +// add another object (using an initializer list of pairs) +j["object"] = { {"currency", "USD"}, {"value", 42.99} }; + +// instead, you could also write (which looks very similar to the JSON above) +json j2 = { + {"pi", 3.141}, + {"happy", true}, + {"name", "Niels"}, + {"nothing", nullptr}, + {"answer", { + {"everything", 42} + }}, + {"list", {1, 0, 2}}, + {"object", { + {"currency", "USD"}, + {"value", 42.99} + }} +}; +``` + +Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help: + +```cpp +// a way to express the empty array [] +json empty_array_explicit = json::array(); + +// ways to express the empty object {} +json empty_object_implicit = json({}); +json empty_object_explicit = json::object(); + +// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] +json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; +``` + +### Serialization / Deserialization + +You can create an object (deserialization) by appending `_json` to a string literal: + +```cpp +// create object from string literal +json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; + +// or even nicer (thanks http://isocpp.org/blog/2015/01/json-for-modern-cpp) +auto j2 = R"( + { + "happy": true, + "pi": 3.141 + } +)"_json; + +// or explicitly +auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); +``` + +You can also get a string representation (serialize): + +```cpp +// explicit conversion to string +std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} + +// serialization with pretty printing +// pass in the amount of spaces to indent +std::cout << j.dump(4) << std::endl; +// { +// "happy": true, +// "pi": 3.141 +// } +``` + +You can also use streams to serialize and deserialize: + +```cpp +// deserialize from standard input +json j; +std::cin >> j; + +// serialize to standard output +std::cout << j; + +// the setw manipulator was overloaded to set the indentation for pretty printing +std::cout << std::setw(4) << j << std::endl; +``` + +These operators work for any subclasses of `std::istream` or `std::ostream`. + +### STL-like access + +We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. + +```cpp +// create an array using push_back +json j; +j.push_back("foo"); +j.push_back(1); +j.push_back(true); + +// iterate the array +for (json::iterator it = j.begin(); it != j.end(); ++it) { + std::cout << *it << '\n'; +} + +// range-based for +for (auto element : j) { + std::cout << element << '\n'; +} + +// getter/setter +const std::string tmp = j[0]; +j[1] = 42; +bool foo = j.at(2); + +// other stuff +j.size(); // 3 entries +j.empty(); // false +j.type(); // json::value_t::array +j.clear(); // the array is empty again + +// convenience type checkers +j.is_null(); +j.is_boolean(); +j.is_number(); +j.is_object(); +j.is_array(); +j.is_string(); + +// comparison +j == "[\"foo\", 1, true]"_json; // true + +// create an object +json o; +o["foo"] = 23; +o["bar"] = false; +o["baz"] = 3.141; + +// special iterator member functions for objects +for (json::iterator it = o.begin(); it != o.end(); ++it) { + std::cout << it.key() << " : " << it.value() << "\n"; +} + +// find an entry +if (o.find("foo") != o.end()) { + // there is an entry with key "foo" +} + +// or simpler using count() +int foo_present = o.count("foo"); // 1 +int fob_present = o.count("fob"); // 0 + +// delete an entry +o.erase("foo"); +``` + +### Conversion from STL containers + +Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends how the elements are ordered in the respective STL container. + +```cpp +std::vector c_vector {1, 2, 3, 4}; +json j_vec(c_vector); +// [1, 2, 3, 4] + +std::deque c_deque {1.2, 2.3, 3.4, 5.6}; +json j_deque(c_deque); +// [1.2, 2.3, 3.4, 5.6] + +std::list c_list {true, true, false, true}; +json j_list(c_list); +// [true, true, false, true] + +std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; +json j_flist(c_flist); +// [12345678909876, 23456789098765, 34567890987654, 45678909876543] + +std::array c_array {{1, 2, 3, 4}}; +json j_array(c_array); +// [1, 2, 3, 4] + +std::set c_set {"one", "two", "three", "four", "one"}; +json j_set(c_set); // only one entry for "one" is used +// ["four", "one", "three", "two"] + +std::unordered_set c_uset {"one", "two", "three", "four", "one"}; +json j_uset(c_uset); // only one entry for "one" is used +// maybe ["two", "three", "four", "one"] + +std::multiset c_mset {"one", "two", "one", "four"}; +json j_mset(c_mset); // only one entry for "one" is used +// maybe ["one", "two", "four"] + +std::unordered_multiset c_umset {"one", "two", "one", "four"}; +json j_umset(c_umset); // both entries for "one" are used +// maybe ["one", "two", "one", "four"] +``` + +Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys are can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. + +```cpp +std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; +json j_map(c_map); +// {"one": 1, "two": 2, "three": 3} + +std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; +json j_umap(c_umap); +// {"one": 1.2, "two": 2.3, "three": 3.4} + +std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; +json j_mmap(c_mmap); // only one entry for key "three" is used +// maybe {"one": true, "two": true, "three": true} + +std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; +json j_ummap(c_ummap); // only one entry for key "three" is used +// maybe {"one": true, "two": true, "three": true} +``` + +### Implicit conversions + +The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted. + +```cpp +/// strings +std::string s1 = "Hello, world!"; +json js = s1; +std::string s2 = js; + +// Booleans +bool b1 = true; +json jb = b1; +bool b2 = jb; + +// numbers +int i = 42; +json jn = i; +double f = jn; + +// etc. +``` + +You can also explicitly ask for the value: + +```cpp +std::string vs = js.get(); +bool vb = jb.get(); +int vi = jn.get(); + +// etc. +``` + +## License + + + +The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): + +Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Thanks + +I deeply appreciate the help of the following people. + +- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. +- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. +- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. +- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang. +- Tomas Åblad found a bug in the iterator implementation. +- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization. +- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing. +- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0. +- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators. +- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. +- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. +- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. +- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. +- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. +- [dariomt](https://github.com/dariomt) fixed some typos in the examples. +- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. +- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. +- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. +- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. +- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. +- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. +- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. +- [406345](https://github.com/406345) fixed two small warnings. +- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. +- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. +- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers. +- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. + +Thanks a lot for helping out! + +## Notes + +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). +- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. + +## Execute unit tests + +To compile and run the tests, you need to execute + +```sh +$ make +$ ./json_unit "*" + +=============================================================================== +All tests passed (3344278 assertions in 29 test cases) +``` + +For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/libs/openFrameworks/.cproject b/libs/openFrameworks/.cproject index e3bdf9d3d00..2a2e9be9395 100644 --- a/libs/openFrameworks/.cproject +++ b/libs/openFrameworks/.cproject @@ -2,7 +2,7 @@ - + @@ -14,24 +14,24 @@ - + - + - - - @@ -42,10 +42,7 @@ - + @@ -73,9 +70,12 @@ - - - + + + + + + @@ -101,17 +101,17 @@ - + - - @@ -144,6 +144,9 @@ + + + @@ -159,26 +162,29 @@ - - + + - - - - - - - + + + + + + + + + + diff --git a/libs/openFrameworks/.settings/language.settings.xml b/libs/openFrameworks/.settings/language.settings.xml new file mode 100644 index 00000000000..2ac91deba19 --- /dev/null +++ b/libs/openFrameworks/.settings/language.settings.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/openFrameworks/3d/of3dPrimitives.cpp b/libs/openFrameworks/3d/of3dPrimitives.cpp index 6b0ba2b14db..840165fb8b9 100644 --- a/libs/openFrameworks/3d/of3dPrimitives.cpp +++ b/libs/openFrameworks/3d/of3dPrimitives.cpp @@ -533,38 +533,38 @@ void ofCylinderPrimitive::set(float _radius, float _height, int radiusSegments, bCapped = _bCapped; resolution.set( radiusSegments, heightSegments, capSegments ); - int resX = getResolution().x; - int resY = getResolution().y-1; - int resZ = getResolution().z-1; + int resX = std::max(getResolution().x,0.0f); + int resY = std::max(getResolution().y-1,0.0f); + int resZ = std::max(getResolution().z-1,0.0f); int indexStep = 2; if(mode == OF_PRIMITIVE_TRIANGLES) { indexStep = 6; - resX = resX-1; + resX = std::max(resX,0); } // 0 -> top cap strides[0][0] = 0; - strides[0][1] = resX * resZ * indexStep; + strides[0][1] = (resX+1) * (resZ+1) * indexStep; vertices[0][0] = 0; - vertices[0][1] = getResolution().x * getResolution().z; + vertices[0][1] = (getResolution().x+1) * (getResolution().z+1); // 1 -> cylinder // if(bCapped) { - strides[1][0] = strides[0][0] + strides[0][1]; - vertices[1][0] = vertices[0][0] + vertices[0][1]; + strides[1][0] = strides[0][0] + strides[0][1]; + vertices[1][0] = vertices[0][0] + vertices[0][1]; } else { - strides[1][0] = 0; - vertices[1][0] = 0; + strides[1][0] = 0; + vertices[1][0] = 0; } - strides[1][1] = resX * resY * indexStep; - vertices[1][1] = getResolution().x * getResolution().y; + strides[1][1] = (resX+1) * (resY+1) * indexStep; + vertices[1][1] = (getResolution().x+1) * (getResolution().y+1); // 2 -> bottom cap strides[2][0] = strides[1][0] + strides[1][1]; - strides[2][1] = resX * resZ * indexStep; + strides[2][1] = (resX+1) * (resZ+1) * indexStep; vertices[2][0] = vertices[1][0]+vertices[1][1]; - vertices[2][1] = getResolution().x * getResolution().z; + vertices[2][1] = (getResolution().x+1) * (getResolution().z+1); getMesh() = ofMesh::cylinder( getRadius(), getHeight(), getResolution().x, getResolution().y, getResolution().z, getCapped(), mode ); @@ -762,25 +762,25 @@ void ofConePrimitive::set( float _radius, float _height, int radiusSegments, int height = _height; resolution.set(radiusSegments, heightSegments, capSegments); - int resX = getResolution().x; - int resY = getResolution().y-1; - int resZ = getResolution().z-1; + int resX = std::max(getResolution().x, 0.0f); + int resY = std::max(getResolution().y-1, 0.0f); + int resZ = std::max(getResolution().z-1, 0.0f); int indexStep = 2; if(mode == OF_PRIMITIVE_TRIANGLES) { indexStep = 6; - resX = resX-1; + resX = std::max(resX-1, 0); } strides[ 0 ][0] = 0; - strides[ 0 ][1] = (resX)*(resY) * indexStep; + strides[ 0 ][1] = (resX+1)*(resY+1) * indexStep; vertices[0][0] = 0; - vertices[0][1] = getResolution().x * getResolution().y; + vertices[0][1] = (getResolution().x+1) * (getResolution().y+1); strides[ 1 ][0] = strides[ 0 ][0] + strides[ 0 ][1]; - strides[ 1 ][1] = (resX)*(resZ) * indexStep; + strides[ 1 ][1] = (resX+1)*(resZ+1) * indexStep; vertices[1][0] = vertices[0][0] + vertices[0][1]; - vertices[1][1] = getResolution().x * getResolution().z; + vertices[1][1] = (getResolution().x+1) * (getResolution().z+1); getMesh() = ofMesh::cone( getRadius(), getHeight(), getResolution().x, getResolution().y, getResolution().z, mode ); @@ -960,39 +960,39 @@ void ofBoxPrimitive::set( float width, float height, float depth, int resWidth, //FRONT, resY, resX strides[ SIDE_FRONT ][0] = 0; - strides[ SIDE_FRONT ][1] = (resY-1)*(resX-1)*6; + strides[ SIDE_FRONT ][1] = (resY)*(resX)*6; vertices[SIDE_FRONT][0] = 0; - vertices[SIDE_FRONT][1] = resX * resY; + vertices[SIDE_FRONT][1] = (resX+1) * (resY+1); //RIGHT, resY, resZ strides[ SIDE_RIGHT ][0] = strides[ SIDE_FRONT ][0] + strides[ SIDE_FRONT ][1]; - strides[ SIDE_RIGHT ][1] = (resY-1)*(resZ-1)*6; + strides[ SIDE_RIGHT ][1] = (resY)*(resZ)*6; vertices[SIDE_RIGHT][0] = vertices[SIDE_FRONT][0] + vertices[SIDE_FRONT][1]; - vertices[SIDE_RIGHT][1] = resY * resZ; + vertices[SIDE_RIGHT][1] = (resY+1) * (resZ+1); //LEFT, resY, resZ strides[ SIDE_LEFT ][0] = strides[ SIDE_RIGHT ][0] + strides[ SIDE_RIGHT ][1]; - strides[ SIDE_LEFT ][1] = (resY-1)*(resZ-1)*6; + strides[ SIDE_LEFT ][1] = (resY)*(resZ)*6; vertices[SIDE_LEFT][0] = vertices[SIDE_RIGHT][0] + vertices[SIDE_RIGHT][1]; - vertices[SIDE_LEFT][1] = resY * resZ; + vertices[SIDE_LEFT][1] = (resY+1) * (resZ+1); //BACK, resY, resX strides[ SIDE_BACK ][0] = strides[ SIDE_LEFT ][0] + strides[ SIDE_LEFT ][1]; - strides[ SIDE_BACK ][1] = (resY-1)*(resX-1)*6; + strides[ SIDE_BACK ][1] = (resY)*(resX)*6; vertices[SIDE_BACK][0] = vertices[SIDE_LEFT][0] + vertices[SIDE_LEFT][1]; - vertices[SIDE_BACK][1] = resY * resX; + vertices[SIDE_BACK][1] = (resY+1) * (resZ+1); //TOP, resZ, resX strides[ SIDE_TOP ][0] = strides[ SIDE_BACK ][0] + strides[ SIDE_BACK ][1]; - strides[ SIDE_TOP ][1] = (resZ-1)*(resX-1)*6; + strides[ SIDE_TOP ][1] = (resZ)*(resX)*6; vertices[SIDE_TOP][0] = vertices[SIDE_BACK][0] + vertices[SIDE_BACK][1]; - vertices[SIDE_TOP][1] = resZ * resX; + vertices[SIDE_TOP][1] = (resY+1) * (resZ+1); //BOTTOM, resZ, resX strides[ SIDE_BOTTOM ][0] = strides[ SIDE_TOP ][0]+strides[ SIDE_TOP ][1]; - strides[ SIDE_BOTTOM ][1] = (resZ-1)*(resX-1)*6; + strides[ SIDE_BOTTOM ][1] = (resZ)*(resX)*6; vertices[SIDE_BOTTOM][0] = vertices[SIDE_TOP][0] + vertices[SIDE_TOP][1]; - vertices[SIDE_BOTTOM][1] = resZ * resX; + vertices[SIDE_BOTTOM][1] = (resY+1) * (resZ+1); getMesh() = ofMesh::box( getWidth(), getHeight(), getDepth(), getResolution().x, getResolution().y, getResolution().z ); diff --git a/libs/openFrameworks/3d/ofCamera.cpp b/libs/openFrameworks/3d/ofCamera.cpp index f59fa145b8c..440731010bb 100644 --- a/libs/openFrameworks/3d/ofCamera.cpp +++ b/libs/openFrameworks/3d/ofCamera.cpp @@ -163,7 +163,7 @@ ofMatrix4x4 ofCamera::getProjectionMatrix(ofRectangle viewport) const { //---------------------------------------- ofMatrix4x4 ofCamera::getModelViewMatrix() const { - return ofMatrix4x4::getInverseOf(getGlobalTransformMatrix()); + return getGlobalTransformMatrix().getInverse(); } //---------------------------------------- diff --git a/libs/openFrameworks/3d/ofEasyCam.cpp b/libs/openFrameworks/3d/ofEasyCam.cpp index c8a1be52489..9c483a11396 100644 --- a/libs/openFrameworks/3d/ofEasyCam.cpp +++ b/libs/openFrameworks/3d/ofEasyCam.cpp @@ -14,9 +14,14 @@ ofEasyCam::ofEasyCam(){ lastTap = 0; lastDistance = 0; drag = 0.9f; - sensitivityRot = 1.0f;//when 1 moving the mouse from one side to the other of the arcball (min(viewport.width, viewport.height)) will rotate 180degrees. when .5, 90 degrees. - sensitivityXY = .5f; - sensitivityZ= .7f; + + sensitivityRotX = 1.0f; + sensitivityRotY = 1.0f; + sensitivityRotZ = 1.0f; + + sensitivityX = 1.0f; + sensitivityY = 1.0f; + sensitivityZ = 1.0f; bDistanceSet = false; bMouseInputEnabled = true; @@ -30,7 +35,6 @@ ofEasyCam::ofEasyCam(){ doTranslationKey = 'm'; bEventsSet = false; events = nullptr; - rotationFactor = 0.0f; reset(); } @@ -48,8 +52,6 @@ void ofEasyCam::update(ofEventArgs & args){ } if(bMouseInputEnabled){ - rotationFactor = sensitivityRot * 180 / min(viewport.width, viewport.height); - if(events->getMousePressed()) prevMouse = ofVec2f(events->getMouseX(),events->getMouseY()); if (bDoRotate) { @@ -213,6 +215,20 @@ void ofEasyCam::setEvents(ofCoreEvents & _events){ bEventsSet = true; } +//---------------------------------------- +void ofEasyCam::setRotationSensitivity(float x, float y, float z){ + sensitivityRotX = x; + sensitivityRotY = y; + sensitivityRotZ = z; +} + +//---------------------------------------- +void ofEasyCam::setTranslationSensitivity(float x, float y, float z){ + sensitivityX = x; + sensitivityY = y; + sensitivityZ = z; +} + //---------------------------------------- bool ofEasyCam::getMouseInputEnabled(){ return bMouseInputEnabled; @@ -329,7 +345,7 @@ void ofEasyCam::mouseScrolled(ofMouseEventArgs & mouse){ ofRectangle viewport = getViewport(this->viewport); prevPosition = ofCamera::getGlobalPosition(); prevAxisZ = getZAxis(); - moveZ = mouse.y * 30 * sensitivityZ * (getDistance() + FLT_EPSILON)/ viewport.height; + moveZ = mouse.scrollY * 30 * sensitivityZ * (getDistance() + FLT_EPSILON)/ viewport.height; bDoScrollZoom = true; } @@ -346,21 +362,21 @@ void ofEasyCam::updateMouse(const ofMouseEventArgs & mouse){ moveY = 0; moveZ = 0; if(mouse.button == OF_MOUSE_BUTTON_RIGHT){ - moveZ = mouseVel.y * sensitivityZ * (getDistance() + FLT_EPSILON)/ viewport.height; + moveZ = mouseVel.y * (sensitivityZ * 0.7f) * (getDistance() + FLT_EPSILON)/ viewport.height; }else{ - moveX = -mouseVel.x * sensitivityXY * (getDistance() + FLT_EPSILON)/viewport.width; - moveY = vFlip * mouseVel.y * sensitivityXY * (getDistance() + FLT_EPSILON)/viewport.height; + moveX = -mouseVel.x * (sensitivityX * 0.5f) * (getDistance() + FLT_EPSILON)/viewport.width; + moveY = vFlip * mouseVel.y * (sensitivityY* 0.5f) * (getDistance() + FLT_EPSILON)/viewport.height; } }else{ xRot = 0; yRot = 0; zRot = 0; if(bInsideArcball){ - xRot = vFlip * -mouseVel.y * rotationFactor; - yRot = -mouseVel.x * rotationFactor; + xRot = vFlip * -mouseVel.y * sensitivityRotX * 180 / min(viewport.width, viewport.height); + yRot = -mouseVel.x * sensitivityRotY * 180 / min(viewport.width, viewport.height); }else{ ofVec2f center(viewport.width/2, viewport.height/2); - zRot = -vFlip * ofVec2f(mouse.x - viewport.x - center.x, mouse.y - viewport.y - center.y).angle(lastMouse - ofVec2f(viewport.x, viewport.y) - center); + zRot = -vFlip * ofVec2f(mouse.x - viewport.x - center.x, mouse.y - viewport.y - center.y).angle(lastMouse - ofVec2f(viewport.x, viewport.y) - center) * sensitivityRotZ; } } } diff --git a/libs/openFrameworks/3d/ofEasyCam.h b/libs/openFrameworks/3d/ofEasyCam.h index f6b913d3101..435f9c0e6c8 100644 --- a/libs/openFrameworks/3d/ofEasyCam.h +++ b/libs/openFrameworks/3d/ofEasyCam.h @@ -78,7 +78,19 @@ class ofEasyCam : public ofCamera { void setAutoDistance(bool bAutoDistance); void setEvents(ofCoreEvents & events); - + + /// \brief Set the input sensitivity of the rotation. + /// X and Y axes - when the value is 1.0, moving the mouse from one side to + /// the other of the arcball (min(viewport.width, viewport.height)) will + /// rotate 180 degrees. When the value is 0.5, the rotation will be 90 + /// degrees. + /// \param value Scales the xyz axes rotation factor by these values. + void setRotationSensitivity(float x, float y, float z); + + /// \brief Set the input sensitivity of the translation. + /// \param value Scales the xyz axes translation factor by these values. + void setTranslationSensitivity(float x, float y, float z); + /// \brief Set the key used to switch between camera rotation and translation. /// /// Translation will only happen when the translation key is pressed. @@ -148,11 +160,12 @@ class ofEasyCam : public ofCamera { float moveY; float moveZ; - float sensitivityXY; + float sensitivityX; + float sensitivityY; float sensitivityZ; - float sensitivityRot; - - float rotationFactor; + float sensitivityRotX; + float sensitivityRotY; + float sensitivityRotZ; ofVec2f lastMouse, prevMouse; ofVec2f mouseVel; diff --git a/libs/openFrameworks/3d/ofMesh.cpp b/libs/openFrameworks/3d/ofMesh.cpp index 2bfb82258a0..5b500a8d6c6 100644 --- a/libs/openFrameworks/3d/ofMesh.cpp +++ b/libs/openFrameworks/3d/ofMesh.cpp @@ -4,35 +4,31 @@ //-------------------------------------------------------------- ofMesh::ofMesh(){ - mode = OF_PRIMITIVE_TRIANGLES; - bVertsChanged = false; - bColorsChanged = false; - bNormalsChanged = false; - bTexCoordsChanged = false; - bIndicesChanged = false; - bFacesDirty = false; - useColors = true; - useTextures = true; - useNormals = true; - useIndices = true; + mode = OF_PRIMITIVE_TRIANGLES; + bVertsChanged = false; + bColorsChanged = false; + bNormalsChanged = false; + bTexCoordsChanged = false; + bIndicesChanged = false; + bFacesDirty = false; + useColors = true; + useTextures = true; + useNormals = true; + useIndices = true; } //-------------------------------------------------------------- ofMesh::ofMesh(ofPrimitiveMode mode, const vector& verts){ - bColorsChanged = false; - bNormalsChanged = false; - bTexCoordsChanged = false; - useColors = true; - useTextures = true; - useNormals = true; - useIndices = true; - setMode(mode); - addVertices(verts); -} - -//-------------------------------------------------------------- -ofMesh::~ofMesh(){ + bColorsChanged = false; + bNormalsChanged = false; + bTexCoordsChanged = false; + useColors = true; + useTextures = true; + useNormals = true; + useIndices = true; + setMode(mode); + addVertices(verts); } //-------------------------------------------------------------- @@ -251,19 +247,19 @@ void ofMesh::addIndices(const ofIndexType* inds, std::size_t amt){ //-------------------------------------------------------------- void ofMesh::addTriangle(ofIndexType index1, ofIndexType index2, ofIndexType index3) { - addIndex(index1); - addIndex(index2); - addIndex(index3); + addIndex(index1); + addIndex(index2); + addIndex(index3); } //REMOVERS //-------------------------------------------------------------- void ofMesh::removeVertex(ofIndexType index){ if(index >= vertices.size()){ - ofLogError("ofMesh") << "removeVertex(): ignoring out of range index " << index << ", number of vertices is" << vertices.size(); + ofLogError("ofMesh") << "removeVertex(): ignoring out of range index " << index << ", number of vertices is" << vertices.size(); }else{ - vertices.erase(vertices.begin() + index); - bVertsChanged = true; + vertices.erase(vertices.begin() + index); + bVertsChanged = true; bFacesDirty = true; } } @@ -273,8 +269,8 @@ void ofMesh::removeNormal(ofIndexType index){ if(index >= normals.size()){ ofLogError("ofMesh") << "removeNormal(): ignoring out of range index " << index << ", number of normals is" << normals.size(); }else{ - normals.erase(normals.begin() + index); - bNormalsChanged = true; + normals.erase(normals.begin() + index); + bNormalsChanged = true; bFacesDirty = true; } } @@ -284,8 +280,8 @@ void ofMesh::removeColor(ofIndexType index){ if(index >= colors.size()){ ofLogError("ofMesh") << "removeColor(): ignoring out of range index " << index << ", number of colors is" << colors.size(); }else{ - colors.erase(colors.begin() + index); - bColorsChanged = true; + colors.erase(colors.begin() + index); + bColorsChanged = true; bFacesDirty = true; } } @@ -295,8 +291,8 @@ void ofMesh::removeTexCoord(ofIndexType index){ if(index >= texCoords.size()){ ofLogError("ofMesh") << "removeTexCoord(): ignoring out of range index " << index << ", number of tex coords is" << texCoords.size(); }else{ - texCoords.erase(texCoords.begin() + index); - bTexCoordsChanged = true; + texCoords.erase(texCoords.begin() + index); + bTexCoordsChanged = true; bFacesDirty = true; } } @@ -306,8 +302,8 @@ void ofMesh::removeIndex(ofIndexType index){ if(index >= indices.size()){ ofLogError("ofMesh") << "removeIndex(): ignoring out of range index " << index << ", number of indices is" << indices.size(); }else{ - indices.erase(indices.begin() + index); - bIndicesChanged = true; + indices.erase(indices.begin() + index); + bIndicesChanged = true; bFacesDirty = true; } } @@ -693,17 +689,17 @@ void ofMesh::draw(ofPolyRenderMode renderType) const{ //-------------------------------------------------------------- void ofMesh::enableColors(){ - useColors = true; + useColors = true; } //-------------------------------------------------------------- void ofMesh::enableTextures(){ - useTextures = true; + useTextures = true; } //-------------------------------------------------------------- void ofMesh::enableNormals(){ - useNormals = true; + useNormals = true; } //-------------------------------------------------------------- @@ -713,17 +709,17 @@ void ofMesh::enableIndices(){ //-------------------------------------------------------------- void ofMesh::disableColors(){ - useColors = false; + useColors = false; } //-------------------------------------------------------------- void ofMesh::disableTextures(){ - useTextures = false; + useTextures = false; } //-------------------------------------------------------------- void ofMesh::disableNormals(){ - useNormals = false; + useNormals = false; } //-------------------------------------------------------------- @@ -733,28 +729,28 @@ void ofMesh::disableIndices(){ //-------------------------------------------------------------- bool ofMesh::usingColors() const{ - return useColors; + return useColors; } //-------------------------------------------------------------- bool ofMesh::usingTextures() const{ - return useTextures; + return useTextures; } //-------------------------------------------------------------- bool ofMesh::usingNormals() const{ - return useNormals; + return useNormals; } //-------------------------------------------------------------- bool ofMesh::usingIndices() const{ - return useIndices; + return useIndices; } //-------------------------------------------------------------- void ofMesh::append(const ofMesh & mesh){ - ofIndexType prevNumVertices = vertices.size(); + ofIndexType prevNumVertices = static_cast(vertices.size()); if(mesh.getNumVertices()){ vertices.insert(vertices.end(),mesh.getVertices().begin(),mesh.getVertices().end()); } @@ -768,8 +764,8 @@ void ofMesh::append(const ofMesh & mesh){ normals.insert(normals.end(),mesh.getNormals().begin(),mesh.getNormals().end()); } if(mesh.getNumIndices()){ - for(ofIndexType i=0;i meshDefinition; + data.clear(); State state = Header; @@ -836,44 +840,47 @@ void ofMesh::load(string path){ if((state==Header || state==FaceDef) && lineStr.find("element vertex")==0){ state = VertexDef; orderVertices = MAX(orderIndices, 0)+1; - data.getVertices().resize(ofToInt(lineStr.substr(15))); + data.getVertices().resize(ofTo(lineStr.substr(15))); continue; } if((state==Header || state==VertexDef) && lineStr.find("element face")==0){ state = FaceDef; orderIndices = MAX(orderVertices, 0)+1; - data.getIndices().resize(ofToInt(lineStr.substr(13))*3); + data.getIndices().resize(ofTo(lineStr.substr(13))*3); continue; } if(state==VertexDef && (lineStr.find("property float x")==0 || lineStr.find("property float y")==0 || lineStr.find("property float z")==0)){ + meshDefinition.push_back(Position); vertexCoordsFound++; continue; } if(state==VertexDef && (lineStr.find("property float r")==0 || lineStr.find("property float g")==0 || lineStr.find("property float b")==0 || lineStr.find("property float a")==0)){ colorCompsFound++; + meshDefinition.push_back(Color); data.getColors().resize(data.getVertices().size()); - floatColor = true; continue; } if(state==VertexDef && (lineStr.find("property uchar red")==0 || lineStr.find("property uchar green")==0 || lineStr.find("property uchar blue")==0 || lineStr.find("property uchar alpha")==0)){ colorCompsFound++; + meshDefinition.push_back(Color); data.getColors().resize(data.getVertices().size()); - floatColor = false; continue; } - if(state==VertexDef && (lineStr.find("property float u")==0 || lineStr.find("property float v")==0)){ + if(state==VertexDef && (lineStr.find("property float u")==0 || lineStr.find("property float v")==0|| lineStr.find("property float s")==0 || lineStr.find("property float t")==0)){ texCoordsFound++; + meshDefinition.push_back(TexCoord); data.getTexCoords().resize(data.getVertices().size()); continue; } if(state==VertexDef && (lineStr.find("property float nx")==0 || lineStr.find("property float ny")==0 || lineStr.find("property float nz")==0)){ normalsCoordsFound++; + meshDefinition.push_back(Normal); if (normalsCoordsFound==3) data.getNormals().resize(data.getVertices().size()); continue; } @@ -912,39 +919,35 @@ void ofMesh::load(string path){ goto clean; } stringstream sline(lineStr); - sline >> data.getVertices()[currentVertex].x; - sline >> data.getVertices()[currentVertex].y; - if(vertexCoordsFound>2) sline >> data.getVertices()[currentVertex].z; - - if(colorCompsFound>0){ - if (floatColor){ - sline >> data.getColors()[currentVertex].r; - sline >> data.getColors()[currentVertex].g; - sline >> data.getColors()[currentVertex].b; - if(colorCompsFound>3) sline >> data.getColors()[currentVertex].a; - }else{ - ofColor c; - sline >> c.r; - sline >> c.g; - sline >> c.b; - if(colorCompsFound>3) sline >> c.a; - data.getColors()[currentVertex] = c; + + // read in a line of vertex elements + // and split it into attributes, + // based attribute order specified in file header + ofIndexType vAttr = 0; + ofIndexType nAttr = 0; + ofIndexType tAttr = 0; + ofIndexType cAttr = 0; + for(auto s:meshDefinition){ + switch (s) { + case Position: + sline >> *(&data.getVertices()[currentVertex].x + (vAttr++)%vertexCoordsFound); + break; + case Color: + sline >> *(&data.getColors()[currentVertex].r + (cAttr++)%colorCompsFound); + break; + case Normal: + sline >> *(&data.getNormals()[currentVertex].x + (nAttr++)%normalsCoordsFound); + break; + case TexCoord: + sline >> *(&data.getTexCoords()[currentVertex].x + (tAttr++)%texCoordsFound); + break; + default: + break; } } - - if(texCoordsFound>0){ - ofVec2f uv; - sline >> uv.x; - sline >> uv.y; - data.getTexCoords()[currentVertex] = uv; - } - - if (normalsCoordsFound>0){ - ofVec3f n; - sline >> n.x; - sline >> n.y; - sline >> n.z; - data.getNormals()[currentVertex] = n; + if (vAttr != vertexCoordsFound || cAttr!= colorCompsFound || nAttr!=normalsCoordsFound || tAttr!=texCoordsFound){ + error = "attribute data does not match definition in header"; + goto clean; } currentVertex++; @@ -970,7 +973,7 @@ void ofMesh::load(string path){ error = "face not a triangle"; goto clean; } - int i; + ofIndexType i; sline >> i; data.getIndices()[currentFace*3] = i; sline >> i; @@ -1107,171 +1110,175 @@ void ofMesh::save(string path, bool useBinary) const{ //---------------------------------------------------------- void ofMesh::setColorForIndices( ofIndexType startIndex, ofIndexType endIndex, ofColor color ) { - if(!hasColors()) { - // no colors for vertices, so we must set them here // - getColors().resize( getNumVertices() ); - } - - for(ofIndexType i = startIndex; i < endIndex; i++) { - setColor( getIndex(i), color); - } + if(!hasColors()) { + // no colors for vertices, so we must set them here // + getColors().resize( getNumVertices() ); + } + + for(ofIndexType i = startIndex; i < endIndex; i++) { + setColor( getIndex(i), color); + } } //---------------------------------------------------------- ofMesh ofMesh::getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex ) const { - ofIndexType startVertIndex = 0; - ofIndexType endVertIndex = 0; - - if(startIndex >= getNumIndices() ) { - startVertIndex = 0; - } else { - startVertIndex = getIndex( startIndex ); - } - - if(endIndex >= getNumIndices() ) { - // set to the total, because the vector assign does not include the last element // - endVertIndex = getNumVertices(); - } else { - endVertIndex = getIndex( endIndex ); - } - return getMeshForIndices(startIndex, endIndex, startVertIndex, endVertIndex ); + ofIndexType startVertIndex = 0; + ofIndexType endVertIndex = 0; + + if(startIndex >= getNumIndices() ) { + startVertIndex = 0; + } else { + startVertIndex = getIndex( startIndex ); + } + + if(endIndex >= getNumIndices() ) { + // set to the total, because the vector assign does not include the last element // + endVertIndex = getNumVertices(); + } else { + endVertIndex = getIndex( endIndex ); + } + return getMeshForIndices(startIndex, endIndex, startVertIndex, endVertIndex ); } //---------------------------------------------------------- ofMesh ofMesh::getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex, ofIndexType startVertIndex, ofIndexType endVertIndex ) const{ - - ofMesh mesh; - mesh.setMode( getMode() ); - - mesh.getVertices().assign( getVertices().begin()+startVertIndex, getVertices().begin()+endVertIndex ); - - if( hasColors() ) { - vector colors; - mesh.getColors().assign( getColors().begin()+startVertIndex, getColors().begin()+endVertIndex ); - if( usingColors()) mesh.enableColors(); - else mesh.disableColors(); - } - - if( hasTexCoords() ) { - mesh.getTexCoords().assign( getTexCoords().begin()+startVertIndex, getTexCoords().begin()+endVertIndex ); - if( usingTextures() ) mesh.enableTextures(); - else mesh.disableTextures(); - } - - if( hasNormals() ) { - mesh.getNormals().assign( getNormals().begin()+startVertIndex, getNormals().begin()+endVertIndex ); - if( usingNormals() ) mesh.enableNormals(); - else mesh.disableNormals(); - } - - int offsetIndex = getIndex(startIndex); - bool bFoundLessThanZero = false; - for(ofIndexType i = startIndex; i < endIndex; i++) { - ofIndexType index = getIndex(i) - offsetIndex; - index = 0; - bFoundLessThanZero = true; - mesh.addIndex( index ); - } - - if(bFoundLessThanZero) { - ofLogWarning( "ofMesh :: getMeshForIndices : found some indices less than 0, setting them to 0" ); - } - - return mesh; + + ofMesh mesh; + mesh.setMode( getMode() ); + + mesh.getVertices().assign( getVertices().begin()+startVertIndex, getVertices().begin()+endVertIndex ); + + if( hasColors() ) { + vector colors; + mesh.getColors().assign( getColors().begin()+startVertIndex, getColors().begin()+endVertIndex ); + if( usingColors()) mesh.enableColors(); + else mesh.disableColors(); + } + + if( hasTexCoords() ) { + mesh.getTexCoords().assign( getTexCoords().begin()+startVertIndex, getTexCoords().begin()+endVertIndex ); + if( usingTextures() ) mesh.enableTextures(); + else mesh.disableTextures(); + } + + if( hasNormals() ) { + mesh.getNormals().assign( getNormals().begin()+startVertIndex, getNormals().begin()+endVertIndex ); + if( usingNormals() ) mesh.enableNormals(); + else mesh.disableNormals(); + } + + ofIndexType offsetIndex = getIndex(startIndex); + bool bFoundLessThanZero = false; + for(ofIndexType i = startIndex; i < endIndex; i++) { + ofIndexType index; + if(getIndex(i) verts = getVertices(); - vector indices = getIndices(); - - //get indexes to share single point - TODO: try j < i - for(ofIndexType i = 0; i < indices.size(); i++) { - for(ofIndexType j = 0; j < indices.size(); j++ ) { - if(i==j) continue; - - ofIndexType i1 = indices[i]; - ofIndexType i2 = indices[j]; - ofVec3f v1 = verts[ i1 ]; - ofVec3f v2 = verts[ i2 ]; - - if( v1 == v2 && i1 != i2) { - indices[j] = i1; - break; - } - } - } - - //indices array now has list of unique points we need - //but we need to delete the old points we're not using and that means the index values will change - //so we are going to create a new list of points and new indexes - we will use a map to map old index values to the new ones - vector newPoints; - vector newIndexes; - map ptCreated; - map oldIndexNewIndex; - - vector newColors; - vector& colors = getColors(); - vector newTCoords; - vector& tcoords = getTexCoords(); - vector newNormals; - vector& normals = getNormals(); - - for(ofIndexType i = 0; i < indices.size(); i++){ - ptCreated[i] = false; - } - - for(ofIndexType i = 0; i < indices.size(); i++){ - ofIndexType index = indices[i]; - ofPoint p = verts[ index ]; - - if( ptCreated[index] == false ){ - oldIndexNewIndex[index] = newPoints.size(); - newPoints.push_back( p ); - if(hasColors()) { - newColors.push_back(colors[index]); - } - if(hasTexCoords()) { - newTCoords.push_back(tcoords[index]); - } - if(hasNormals()) { - newNormals.push_back(normals[index]); - } - - ptCreated[index] = true; - } - - //ofLogNotice("ofMesh") << "[" << i << "]: old " << index << " --> " << oldIndexNewIndex[index]; - newIndexes.push_back( oldIndexNewIndex[index] ); - } - - verts.clear(); - verts = newPoints; - - indices.clear(); - indices = newIndexes; - - clearIndices(); - addIndices(indices); - clearVertices(); - addVertices( verts ); - - if(hasColors()) { - clearColors(); - addColors( newColors ); - } - - if(hasTexCoords()) { - clearTexCoords(); - addTexCoords( newTCoords ); - } - - if(hasNormals()) { - clearNormals(); - addNormals( newNormals ); - } - + + vector verts = getVertices(); + vector indices = getIndices(); + + //get indexes to share single point - TODO: try j < i + for(ofIndexType i = 0; i < indices.size(); i++) { + for(ofIndexType j = 0; j < indices.size(); j++ ) { + if(i==j) continue; + + ofIndexType i1 = indices[i]; + ofIndexType i2 = indices[j]; + ofVec3f v1 = verts[ i1 ]; + ofVec3f v2 = verts[ i2 ]; + + if( v1 == v2 && i1 != i2) { + indices[j] = i1; + break; + } + } + } + + //indices array now has list of unique points we need + //but we need to delete the old points we're not using and that means the index values will change + //so we are going to create a new list of points and new indexes - we will use a map to map old index values to the new ones + vector newPoints; + vector newIndexes; + map ptCreated; + map oldIndexNewIndex; + + vector newColors; + vector& colors = getColors(); + vector newTCoords; + vector& tcoords = getTexCoords(); + vector newNormals; + vector& normals = getNormals(); + + for(ofIndexType i = 0; i < indices.size(); i++){ + ptCreated[i] = false; + } + + for(ofIndexType i = 0; i < indices.size(); i++){ + ofIndexType index = indices[i]; + ofPoint p = verts[ index ]; + + if( ptCreated[index] == false ){ + oldIndexNewIndex[index] = newPoints.size(); + newPoints.push_back( p ); + if(hasColors()) { + newColors.push_back(colors[index]); + } + if(hasTexCoords()) { + newTCoords.push_back(tcoords[index]); + } + if(hasNormals()) { + newNormals.push_back(normals[index]); + } + + ptCreated[index] = true; + } + + //ofLogNotice("ofMesh") << "[" << i << "]: old " << index << " --> " << oldIndexNewIndex[index]; + newIndexes.push_back( oldIndexNewIndex[index] ); + } + + verts.clear(); + verts = newPoints; + + indices.clear(); + indices = newIndexes; + + clearIndices(); + addIndices(indices); + clearVertices(); + addVertices( verts ); + + if(hasColors()) { + clearColors(); + addColors( newColors ); + } + + if(hasTexCoords()) { + clearTexCoords(); + addTexCoords( newTCoords ); + } + + if(hasNormals()) { + clearNormals(); + addNormals( newNormals ); + } + } //---------------------------------------------------------- @@ -1287,16 +1294,16 @@ ofMeshFace ofMesh::getFace(ofIndexType faceId) const{ //---------------------------------------------------------- const vector & ofMesh::getUniqueFaces() const{ - if(bFacesDirty){ + if(bFacesDirty){ // if we are doing triangles, we have to use a vert and normal for each triangle // that way we can calculate face normals and use getFaceNormal(); faces.resize( indices.size()/3 ); - int index = 0; - int triindex = 0; + int index = 0; + int triindex = 0; - bool bHasColors = hasColors(); - bool bHasNormals = hasNormals(); + bool bHasColors = hasColors(); + bool bHasNormals = hasNormals(); bool bHasTexcoords = hasTexCoords(); if( getMode() == OF_PRIMITIVE_TRIANGLES) { @@ -1320,359 +1327,357 @@ const vector & ofMesh::getUniqueFaces() const{ } bFacesDirty = false; - } - - return faces; - + } + + return faces; + } //---------------------------------------------------------- vector ofMesh::getFaceNormals( bool perVertex ) const{ - // default for ofPrimitiveBase is vertex normals // - vector faceNormals; - - if( hasVertices() ) { - if(vertices.size() > 3 && indices.size() > 3) { - if(perVertex){ - faceNormals.resize(indices.size()*3); - }else{ - faceNormals.resize(indices.size()); - } - ofMeshFace face; - ofVec3f n; - for(ofIndexType i = 0; i < indices.size(); i+=3) { - face.setVertex( 0, vertices[indices[i+0]] ); - face.setVertex( 1, vertices[indices[i+1]] ); - face.setVertex( 2, vertices[indices[i+2]] ); - - n = face.getFaceNormal(); - - faceNormals[i]=n; - if(perVertex) { - faceNormals[i+1]=n; - faceNormals[i+2]=n; - } - } - } - - } - - return faceNormals; + // default for ofPrimitiveBase is vertex normals // + vector faceNormals; + + if( hasVertices() ) { + if(vertices.size() > 3 && indices.size() > 3) { + if(perVertex){ + faceNormals.resize(indices.size()*3); + }else{ + faceNormals.resize(indices.size()); + } + ofMeshFace face; + ofVec3f n; + for(ofIndexType i = 0; i < indices.size(); i+=3) { + face.setVertex( 0, vertices[indices[i+0]] ); + face.setVertex( 1, vertices[indices[i+1]] ); + face.setVertex( 2, vertices[indices[i+2]] ); + + n = face.getFaceNormal(); + + faceNormals[i]=n; + if(perVertex) { + faceNormals[i+1]=n; + faceNormals[i+2]=n; + } + } + } + } + + return faceNormals; } //---------------------------------------------------------- void ofMesh::setFromTriangles( const vector& tris, bool bUseFaceNormal ) { - if(tris.empty()) { - ofLogWarning("ofMesh") << "setFromTriangles(): ignoring empty tris vector"; - return; - } - - vector::const_iterator it; - - vertices.resize(tris.size()*3 ); - it = tris.begin(); - // if the first tri has data, assume the rest do as well // - if(it->hasNormals()){ - normals.resize(tris.size()*3); - }else{ - normals.clear(); - } - if(it->hasColors()){ - colors.resize(tris.size()*3); - }else{ - colors.clear(); - } - if(it->hasTexcoords()){ - texCoords.resize(tris.size()*3); - }else{ - texCoords.clear(); - } - - int i = 0; - for(it = tris.begin(); it != tris.end(); it++) { - for(std::size_t k = 0; k < 3; k++) { - vertices[i] = it->getVertex(k); - if(it->hasTexcoords()) - texCoords[i] = it->getTexCoord(k); - if(it->hasColors()) - colors[i] = it->getColor(k); + if(tris.empty()) { + ofLogWarning("ofMesh") << "setFromTriangles(): ignoring empty tris vector"; + return; + } + + vector::const_iterator it; + + vertices.resize(tris.size()*3 ); + it = tris.begin(); + // if the first tri has data, assume the rest do as well // + if(it->hasNormals()){ + normals.resize(tris.size()*3); + }else{ + normals.clear(); + } + if(it->hasColors()){ + colors.resize(tris.size()*3); + }else{ + colors.clear(); + } + if(it->hasTexcoords()){ + texCoords.resize(tris.size()*3); + }else{ + texCoords.clear(); + } + + int i = 0; + for(it = tris.begin(); it != tris.end(); it++) { + for(std::size_t k = 0; k < 3; k++) { + vertices[i] = it->getVertex(k); + if(it->hasTexcoords()) + texCoords[i] = it->getTexCoord(k); + if(it->hasColors()) + colors[i] = it->getColor(k); if(bUseFaceNormal) normals[i] = it->getFaceNormal(); else if(it->hasNormals()) normals[i] = it->getNormal(k); - i++; - } - } - - setupIndicesAuto(); - bVertsChanged = true; - bIndicesChanged = true; - bNormalsChanged = true; - bColorsChanged = true; - bTexCoordsChanged = true; + i++; + } + } + + setupIndicesAuto(); + bVertsChanged = true; + bIndicesChanged = true; + bNormalsChanged = true; + bColorsChanged = true; + bTexCoordsChanged = true; - bFacesDirty = false; - faces = tris; + bFacesDirty = false; + faces = tris; } //---------------------------------------------------------- void ofMesh::smoothNormals( float angle ) { - - if( getMode() == OF_PRIMITIVE_TRIANGLES) { - vector triangles = getUniqueFaces(); - vector verts; - for(ofIndexType i = 0; i < triangles.size(); i++) { - for(ofIndexType j = 0; j < 3; j++) { - verts.push_back( triangles[i].getVertex(j) ); - } - } - - map removeIds; - - float epsilon = .01f; - for(ofIndexType i = 0; i < verts.size()-1; i++) { - for(ofIndexType j = i+1; j < verts.size(); j++) { - if(i != j) { - ofVec3f& v1 = verts[i]; - ofVec3f& v2 = verts[j]; - if( v1.distance(v2) <= epsilon ) { - // average the location // - verts[i] = (v1+v2)/2.f; - verts[j] = verts[i]; - removeIds[j] = 1; - } - } - } - } - - // string of vertex in 3d space to triangle index // - map > vertHash; - + + if( getMode() == OF_PRIMITIVE_TRIANGLES) { + vector triangles = getUniqueFaces(); + vector verts; + for(ofIndexType i = 0; i < triangles.size(); i++) { + for(ofIndexType j = 0; j < 3; j++) { + verts.push_back( triangles[i].getVertex(j) ); + } + } + + map removeIds; + + float epsilon = .01f; + for(ofIndexType i = 0; i < verts.size()-1; i++) { + for(ofIndexType j = i+1; j < verts.size(); j++) { + if(i != j) { + ofVec3f& v1 = verts[i]; + ofVec3f& v2 = verts[j]; + if( v1.distance(v2) <= epsilon ) { + // average the location // + verts[i] = (v1+v2)/2.f; + verts[j] = verts[i]; + removeIds[j] = 1; + } + } + } + } + + // string of vertex in 3d space to triangle index // + map > vertHash; + //ofLogNotice("ofMesh") << "smoothNormals(): num verts = " << verts.size() << " tris size = " << triangles.size(); - - string xStr, yStr, zStr; - - for(ofIndexType i = 0; i < verts.size(); i++ ) { - xStr = "x"+ofToString(verts[i].x==-0?0:verts[i].x); - yStr = "y"+ofToString(verts[i].y==-0?0:verts[i].y); - zStr = "z"+ofToString(verts[i].z==-0?0:verts[i].z); - string vstring = xStr+yStr+zStr; - if(vertHash.find(vstring) == vertHash.end()) { - for(ofIndexType j = 0; j < triangles.size(); j++) { - for(ofIndexType k = 0; k < 3; k++) { - if(verts[i].x == triangles[j].getVertex(k).x) { - if(verts[i].y == triangles[j].getVertex(k).y) { - if(verts[i].z == triangles[j].getVertex(k).z) { - vertHash[vstring].push_back( j ); - } - } - } - } - } - } - } - -// for( map >::iterator it = vertHash.begin(); it != vertHash.end(); ++it) { -// //for( map::iterator it = vertHash.begin(); it != vertHash.end(); ++it) { -// ofLogNotice("ofMesh") << "smoothNormals(): " << it->first << " num = " << it->second.size(); -// } - - - ofVec3f normal; - float angleCos = cos(angle * DEG_TO_RAD ); - float numNormals=0; - ofVec3f f1, f2; - ofVec3f vert; - - for(ofIndexType j = 0; j < triangles.size(); j++) { - for(ofIndexType k = 0; k < 3; k++) { - vert = triangles[j].getVertex(k); - xStr = "x"+ofToString(vert.x==-0?0:vert.x); - yStr = "y"+ofToString(vert.y==-0?0:vert.y); - zStr = "z"+ofToString(vert.z==-0?0:vert.z); - - string vstring = xStr+yStr+zStr; - numNormals=0; - normal.set(0,0,0); - if(vertHash.find(vstring) != vertHash.end()) { - for(ofIndexType i = 0; i < vertHash[vstring].size(); i++) { - f1 = triangles[j].getFaceNormal(); - f2 = triangles[vertHash[vstring][i]].getFaceNormal(); - if(f1.dot(f2) >= angleCos ) { - normal += f2; - numNormals+=1.f; - } - } - //normal /= (float)vertHash[vstring].size(); - normal /= numNormals; - - triangles[j].setNormal(k, normal); - } - } - } - - //ofLogNotice("ofMesh") << "smoothNormals(): setting from triangles "; - setFromTriangles( triangles ); - - } + + string xStr, yStr, zStr; + + for(ofIndexType i = 0; i < verts.size(); i++ ) { + xStr = "x"+ofToString(verts[i].x==-0?0:verts[i].x); + yStr = "y"+ofToString(verts[i].y==-0?0:verts[i].y); + zStr = "z"+ofToString(verts[i].z==-0?0:verts[i].z); + string vstring = xStr+yStr+zStr; + if(vertHash.find(vstring) == vertHash.end()) { + for(ofIndexType j = 0; j < triangles.size(); j++) { + for(ofIndexType k = 0; k < 3; k++) { + if(verts[i].x == triangles[j].getVertex(k).x) { + if(verts[i].y == triangles[j].getVertex(k).y) { + if(verts[i].z == triangles[j].getVertex(k).z) { + vertHash[vstring].push_back( j ); + } + } + } + } + } + } + } + +// for( map >::iterator it = vertHash.begin(); it != vertHash.end(); ++it) { +// //for( map::iterator it = vertHash.begin(); it != vertHash.end(); ++it) { +// ofLogNotice("ofMesh") << "smoothNormals(): " << it->first << " num = " << it->second.size(); +// } + + ofVec3f normal; + float angleCos = cos(angle * DEG_TO_RAD ); + float numNormals=0; + ofVec3f f1, f2; + ofVec3f vert; + + for(ofIndexType j = 0; j < triangles.size(); j++) { + for(ofIndexType k = 0; k < 3; k++) { + vert = triangles[j].getVertex(k); + xStr = "x"+ofToString(vert.x==-0?0:vert.x); + yStr = "y"+ofToString(vert.y==-0?0:vert.y); + zStr = "z"+ofToString(vert.z==-0?0:vert.z); + + string vstring = xStr+yStr+zStr; + numNormals=0; + normal.set(0,0,0); + if(vertHash.find(vstring) != vertHash.end()) { + for(ofIndexType i = 0; i < vertHash[vstring].size(); i++) { + f1 = triangles[j].getFaceNormal(); + f2 = triangles[vertHash[vstring][i]].getFaceNormal(); + if(f1.dot(f2) >= angleCos ) { + normal += f2; + numNormals+=1.f; + } + } + //normal /= (float)vertHash[vstring].size(); + normal /= numNormals; + + triangles[j].setNormal(k, normal); + } + } + } + + //ofLogNotice("ofMesh") << "smoothNormals(): setting from triangles "; + setFromTriangles( triangles ); + + } } // PLANE MESH // //-------------------------------------------------------------- ofMesh ofMesh::plane(float width, float height, int columns, int rows, ofPrimitiveMode mode ) { - ofMesh mesh; - - if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { - ofLogWarning("ofMesh") << "ofGetPlaneMesh(): primtive mode " << mode << " not supported, setting to OF_PRIMITIVE_TRIANGLES"; - mode = OF_PRIMITIVE_TRIANGLES; - } - - mesh.setMode(mode); - - ofVec3f vert; - ofVec3f normal(0, 0, 1); // always facing forward // - ofVec2f texcoord; - - // the origin of the plane is the center // - float halfW = width/2.f; - float halfH = height/2.f; - // add the vertexes // - for(int iy = 0; iy < rows; iy++) { - for(int ix = 0; ix < columns; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)columns-1.f)); - texcoord.y = ((float)iy/((float)rows-1.f)); - - vert.x = texcoord.x * width - halfW; - vert.y = texcoord.y * height - halfH; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - if(mode == OF_PRIMITIVE_TRIANGLE_STRIP) { - for(int y = 0; y < rows-1; y++) { - // even rows // - if((y&1)==0) { - for(int x = 0; x < columns; x++) { - mesh.addIndex( (y) * columns + x ); - mesh.addIndex( (y+1) * columns + x); - } - } else { - for(int x = columns-1; x >0; x--) { - mesh.addIndex( (y+1) * columns + x ); - mesh.addIndex( y * columns + x-1 ); - } - } - } - - if(rows%2!=0) mesh.addIndex(mesh.getNumVertices()-columns); - } else { - // Triangles // - for(int y = 0; y < rows-1; y++) { - for(int x = 0; x < columns-1; x++) { - // first triangle // - mesh.addIndex((y)*columns + x); - mesh.addIndex((y)*columns + x+1); - mesh.addIndex((y+1)*columns + x); - - // second triangle // - mesh.addIndex((y)*columns + x+1); - mesh.addIndex((y+1)*columns + x+1); - mesh.addIndex((y+1)*columns + x); - } - } - } - - return mesh; + ofMesh mesh; + + if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { + ofLogWarning("ofMesh") << "ofGetPlaneMesh(): primtive mode " << mode << " not supported, setting to OF_PRIMITIVE_TRIANGLES"; + mode = OF_PRIMITIVE_TRIANGLES; + } + + mesh.setMode(mode); + + ofVec3f vert; + ofVec3f normal(0, 0, 1); // always facing forward // + ofVec2f texcoord; + + // the origin of the plane is the center // + float halfW = width/2.f; + float halfH = height/2.f; + // add the vertexes // + for(int iy = 0; iy < rows; iy++) { + for(int ix = 0; ix < columns; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)columns-1.f)); + texcoord.y = ((float)iy/((float)rows-1.f)); + + vert.x = texcoord.x * width - halfW; + vert.y = texcoord.y * height - halfH; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + if(mode == OF_PRIMITIVE_TRIANGLE_STRIP) { + for(int y = 0; y < rows-1; y++) { + // even rows // + if((y&1)==0) { + for(int x = 0; x < columns; x++) { + mesh.addIndex( (y) * columns + x ); + mesh.addIndex( (y+1) * columns + x); + } + } else { + for(int x = columns-1; x >0; x--) { + mesh.addIndex( (y+1) * columns + x ); + mesh.addIndex( y * columns + x-1 ); + } + } + } + + if(rows%2!=0) mesh.addIndex(mesh.getNumVertices()-columns); + } else { + // Triangles // + for(int y = 0; y < rows-1; y++) { + for(int x = 0; x < columns-1; x++) { + // first triangle // + mesh.addIndex((y)*columns + x); + mesh.addIndex((y)*columns + x+1); + mesh.addIndex((y+1)*columns + x); + + // second triangle // + mesh.addIndex((y)*columns + x+1); + mesh.addIndex((y+1)*columns + x+1); + mesh.addIndex((y+1)*columns + x); + } + } + } + + return mesh; } //---------------------------------------------------------- ofMesh ofMesh::sphere( float radius, int res, ofPrimitiveMode mode ) { - - ofMesh mesh; - - float doubleRes = res*2.f; - float polarInc = PI/(res); // ringAngle - float azimInc = TWO_PI/(doubleRes); // segAngle // - - if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { - mode = OF_PRIMITIVE_TRIANGLE_STRIP; - } - mesh.setMode(mode); - - ofVec3f vert; - ofVec2f tcoord; - - for(float i = 0; i < res+1; i++) { - - float tr = sin( PI-i * polarInc ); - float ny = cos( PI-i * polarInc ); - - tcoord.y = i / res; - - for(float j = 0; j <= doubleRes; j++) { - - float nx = tr * sin(j * azimInc); - float nz = tr * cos(j * azimInc); - - tcoord.x = j / (doubleRes); - - vert.set(nx, ny, nz); - mesh.addNormal(vert); - vert *= radius; - mesh.addVertex(vert); - mesh.addTexCoord(tcoord); - } - } - - int nr = doubleRes+1; - if(mode == OF_PRIMITIVE_TRIANGLES) { - - int index1, index2, index3; - - for(float iy = 0; iy < res; iy++) { - for(float ix = 0; ix < doubleRes; ix++) { - - // first tri // - if(iy > 0) { - index1 = (iy+0) * (nr) + (ix+0); - index2 = (iy+0) * (nr) + (ix+1); - index3 = (iy+1) * (nr) + (ix+0); - - mesh.addIndex(index1); - mesh.addIndex(index3); - mesh.addIndex(index2); - } - - if(iy < res-1 ) { - // second tri // - index1 = (iy+0) * (nr) + (ix+1); - index2 = (iy+1) * (nr) + (ix+1); - index3 = (iy+1) * (nr) + (ix+0); - - mesh.addIndex(index1); - mesh.addIndex(index3); - mesh.addIndex(index2); - - } - } - } - - } else { - for(int y = 0; y < res; y++) { - for(int x = 0; x <= doubleRes; x++) { - mesh.addIndex( (y)*nr + x ); - mesh.addIndex( (y+1)*nr + x ); - } - } - } - - - return mesh; + + ofMesh mesh; + + float doubleRes = res*2.f; + float polarInc = PI/(res); // ringAngle + float azimInc = TWO_PI/(doubleRes); // segAngle // + + if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { + mode = OF_PRIMITIVE_TRIANGLE_STRIP; + } + mesh.setMode(mode); + + ofVec3f vert; + ofVec2f tcoord; + + for(float i = 0; i < res+1; i++) { + + float tr = sin( PI-i * polarInc ); + float ny = cos( PI-i * polarInc ); + + tcoord.y = i / res; + + for(float j = 0; j <= doubleRes; j++) { + + float nx = tr * sin(j * azimInc); + float nz = tr * cos(j * azimInc); + + tcoord.x = j / (doubleRes); + + vert.set(nx, ny, nz); + mesh.addNormal(vert); + vert *= radius; + mesh.addVertex(vert); + mesh.addTexCoord(tcoord); + } + } + + int nr = doubleRes+1; + if(mode == OF_PRIMITIVE_TRIANGLES) { + + ofIndexType index1, index2, index3; + + for(float iy = 0; iy < res; iy++) { + for(float ix = 0; ix < doubleRes; ix++) { + + // first tri // + if(iy > 0) { + index1 = (iy+0) * (nr) + (ix+0); + index2 = (iy+0) * (nr) + (ix+1); + index3 = (iy+1) * (nr) + (ix+0); + + mesh.addIndex(index1); + mesh.addIndex(index3); + mesh.addIndex(index2); + } + + if(iy < res-1 ) { + // second tri // + index1 = (iy+0) * (nr) + (ix+1); + index2 = (iy+1) * (nr) + (ix+1); + index3 = (iy+1) * (nr) + (ix+0); + + mesh.addIndex(index1); + mesh.addIndex(index3); + mesh.addIndex(index2); + + } + } + } + + } else { + for(int y = 0; y < res; y++) { + for(int x = 0; x <= doubleRes; x++) { + mesh.addIndex( (y)*nr + x ); + mesh.addIndex( (y+1)*nr + x ); + } + } + } + + + return mesh; } /* @@ -1708,59 +1713,59 @@ ofMesh ofMesh::sphere( float radius, int res, ofPrimitiveMode mode ) { // use ofGetIcoSphere(radius, 0) // 0 iterations will return Icosahedron // //---------------------------------------------------------- ofMesh ofMesh::icosahedron(float radius) { - ofMesh mesh; - - const float sqrt5 = sqrt(5.0f); - const float phi = (1.0f + sqrt5) * 0.5f; - - /// Step 1 : Generate icosahedron - float invnorm = 1/sqrt(phi*phi+1); - - mesh.addVertex(invnorm*ofVec3f(-1, phi, 0));//0 - mesh.addVertex(invnorm*ofVec3f( 1, phi, 0));//1 - mesh.addVertex(invnorm*ofVec3f(0, 1, -phi));//2 - mesh.addVertex(invnorm*ofVec3f(0, 1, phi));//3 - mesh.addVertex(invnorm*ofVec3f(-phi,0, -1));//4 - mesh.addVertex(invnorm*ofVec3f(-phi,0, 1));//5 - mesh.addVertex(invnorm*ofVec3f( phi,0, -1));//6 - mesh.addVertex(invnorm*ofVec3f( phi,0, 1));//7 - mesh.addVertex(invnorm*ofVec3f(0, -1, -phi));//8 - mesh.addVertex(invnorm*ofVec3f(0, -1, phi));//9 - mesh.addVertex(invnorm*ofVec3f(-1, -phi,0));//10 - mesh.addVertex(invnorm*ofVec3f( 1, -phi,0));//11 - - ofIndexType firstFaces[] = { - 0,1,2, - 0,3,1, - 0,4,5, - 1,7,6, - 1,6,2, - 1,3,7, - 0,2,4, - 0,5,3, - 2,6,8, - 2,8,4, - 3,5,9, - 3,9,7, - 11,6,7, - 10,5,4, - 10,4,8, - 10,9,5, - 11,8,6, - 11,7,9, - 10,8,11, - 10,11,9 - }; - - for(ofIndexType i = 0; i < mesh.getNumVertices(); i++) { - mesh.setVertex(i, mesh.getVertex(i) * radius); - } - - for(ofIndexType i = 0; i < 60; i+=3) { - mesh.addTriangle(firstFaces[i], firstFaces[i+1], firstFaces[i+2]); - } - - return mesh; + ofMesh mesh; + + const float sqrt5 = sqrt(5.0f); + const float phi = (1.0f + sqrt5) * 0.5f; + + /// Step 1 : Generate icosahedron + float invnorm = 1/sqrt(phi*phi+1); + + mesh.addVertex(invnorm*ofVec3f(-1, phi, 0));//0 + mesh.addVertex(invnorm*ofVec3f( 1, phi, 0));//1 + mesh.addVertex(invnorm*ofVec3f(0, 1, -phi));//2 + mesh.addVertex(invnorm*ofVec3f(0, 1, phi));//3 + mesh.addVertex(invnorm*ofVec3f(-phi,0, -1));//4 + mesh.addVertex(invnorm*ofVec3f(-phi,0, 1));//5 + mesh.addVertex(invnorm*ofVec3f( phi,0, -1));//6 + mesh.addVertex(invnorm*ofVec3f( phi,0, 1));//7 + mesh.addVertex(invnorm*ofVec3f(0, -1, -phi));//8 + mesh.addVertex(invnorm*ofVec3f(0, -1, phi));//9 + mesh.addVertex(invnorm*ofVec3f(-1, -phi,0));//10 + mesh.addVertex(invnorm*ofVec3f( 1, -phi,0));//11 + + ofIndexType firstFaces[] = { + 0,1,2, + 0,3,1, + 0,4,5, + 1,7,6, + 1,6,2, + 1,3,7, + 0,2,4, + 0,5,3, + 2,6,8, + 2,8,4, + 3,5,9, + 3,9,7, + 11,6,7, + 10,5,4, + 10,4,8, + 10,9,5, + 11,8,6, + 11,7,9, + 10,8,11, + 10,11,9 + }; + + for(ofIndexType i = 0; i < mesh.getNumVertices(); i++) { + mesh.setVertex(i, mesh.getVertex(i) * radius); + } + + for(ofIndexType i = 0; i < 60; i+=3) { + mesh.addTriangle(firstFaces[i], firstFaces[i+1], firstFaces[i+2]); + } + + return mesh; } @@ -1770,127 +1775,127 @@ ofMesh ofMesh::icosahedron(float radius) { // For the latest info, see http://code.google.com/p/ogre-procedural/ // //---------------------------------------------------------- ofMesh ofMesh::icosphere(float radius, std::size_t iterations) { - - //ofMesh icosahedron = ofGetIcosahedronMesh( 1.f ); - ofMesh icosahedron = ofMesh::icosahedron( 1.f ); - vector vertices = icosahedron.getVertices(); - vector faces = icosahedron.getIndices(); - - ofIndexType size = faces.size(); - - /// Step 2 : tessellate - for (ofIndexType iteration = 0; iteration < iterations; iteration++) - { - size*=4; - vector newFaces; - newFaces.clear(); - //newFaces.resize(size); - for (ofIndexType i=0; i texCoords; - for (ofIndexType i=0;i indexToSplit; - - for (ofIndexType i=0;i0.5) - { - if (t0.x<0.5) - indexToSplit.push_back(faces[i*3]); - else - indexToSplit.push_back(faces[i*3+2]); - } - if (abs(t1.x-t0.x)>0.5) - { - if (t0.x<0.5) - indexToSplit.push_back(faces[i*3]); - else - indexToSplit.push_back(faces[i*3+1]); - } - if (abs(t2.x-t1.x)>0.5) - { - if (t1.x<0.5) - indexToSplit.push_back(faces[i*3+1]); - else - indexToSplit.push_back(faces[i*3+2]); - } - } - - //split vertices - for (ofIndexType i=0;i0.5) || (texCoords[index2].x>0.5)) - { - faces[j] = newIndex; - } - } - } - } - + + //ofMesh icosahedron = ofGetIcosahedronMesh( 1.f ); + ofMesh icosahedron = ofMesh::icosahedron( 1.f ); + vector vertices = icosahedron.getVertices(); + vector faces = icosahedron.getIndices(); + + ofIndexType size = faces.size(); + + /// Step 2 : tessellate + for (ofIndexType iteration = 0; iteration < iterations; iteration++) + { + size*=4; + vector newFaces; + newFaces.clear(); + //newFaces.resize(size); + for (ofIndexType i=0; i texCoords; + for (ofIndexType i=0;i indexToSplit; + + for (ofIndexType i=0;i0.5) + { + if (t0.x<0.5) + indexToSplit.push_back(faces[i*3]); + else + indexToSplit.push_back(faces[i*3+2]); + } + if (abs(t1.x-t0.x)>0.5) + { + if (t0.x<0.5) + indexToSplit.push_back(faces[i*3]); + else + indexToSplit.push_back(faces[i*3+1]); + } + if (abs(t2.x-t1.x)>0.5) + { + if (t1.x<0.5) + indexToSplit.push_back(faces[i*3+1]); + else + indexToSplit.push_back(faces[i*3+2]); + } + } + + //split vertices + for (ofIndexType i=0;i0.5) || (texCoords[index2].x>0.5)) + { + faces[j] = newIndex; + } + } + } + } + // tig: flip face(=triangle) winding order, so that we are consistent with all other ofPrimitives. // i wish there was a more elegant way to do this, but anything happening before "split vertices" // makes things very, very complicated. @@ -1899,18 +1904,18 @@ ofMesh ofMesh::icosphere(float radius, std::size_t iterations) { std::swap(faces[i+1], faces[i+2]); } - ofMesh sphere; - - sphere.addIndices( faces ); - sphere.addNormals( vertices ); - sphere.addTexCoords( texCoords ); - - for(ofIndexType i = 0; i < vertices.size(); i++ ) { - vertices[i] *= radius; - } - sphere.addVertices( vertices ); - - return sphere; + ofMesh sphere; + + sphere.addIndices( faces ); + sphere.addNormals( vertices ); + sphere.addTexCoords( texCoords ); + + for(ofIndexType i = 0; i < vertices.size(); i++ ) { + vertices[i] *= radius; + } + sphere.addVertices( vertices ); + + return sphere; } /* ----------------------------------------------------------------------------- @@ -1923,603 +1928,595 @@ ofMesh ofMesh::icosphere(float radius, std::size_t iterations) { // Cylinder Mesh //---------------------------------------------------------- ofMesh ofMesh::cylinder( float radius, float height, int radiusSegments, int heightSegments, int numCapSegments, bool bCapped, ofPrimitiveMode mode ) { - ofMesh mesh; - if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { - mode = OF_PRIMITIVE_TRIANGLE_STRIP; - } - mesh.setMode(mode); - - radiusSegments = radiusSegments+1; - int capSegs = numCapSegments; - capSegs = capSegs+1; - heightSegments = heightSegments+1; - if(heightSegments < 2) heightSegments = 2; - if( capSegs < 2 ) bCapped = false; - if(!bCapped) capSegs=1; - - float angleIncRadius = -1 * (TWO_PI/((float)radiusSegments-1.f)); - float heightInc = height/((float)heightSegments-1.f); - float halfH = height*.5f; - - float newRad; - ofVec3f vert; - ofVec2f tcoord; - ofVec3f normal; - ofVec3f up(0,1,0); - - int vertOffset = 0; - - float maxTexY = heightSegments-1.f; - if(capSegs > 0) { - maxTexY += (capSegs*2)-2.f; - } - float maxTexYNormalized = (capSegs-1.f) / maxTexY; - - // add the top cap // - if(bCapped && capSegs > 0) { - normal.set(0,-1,0); - for(int iy = 0; iy < capSegs; iy++) { - for(int ix = 0; ix < radiusSegments; ix++) { - newRad = ofMap((float)iy, 0, capSegs-1, 0.0, radius); - vert.x = cos((float)ix*angleIncRadius) * newRad; - vert.z = sin((float)ix*angleIncRadius) * newRad; - vert.y = -halfH; - - tcoord.x = (float)ix/((float)radiusSegments-1.f); - tcoord.y = ofMap(iy, 0, capSegs-1, 0, maxTexYNormalized); - - mesh.addTexCoord( tcoord ); - mesh.addVertex( vert ); - mesh.addNormal( normal ); - } - } - - if(mode == OF_PRIMITIVE_TRIANGLES) { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments-1; x++) { - if(y > 0) { - // first triangle // - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - - // second triangle // - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } else { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments; x++) { - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } - - vertOffset = mesh.getNumVertices(); - - } - - //maxTexY = heightSegments-1.f + capSegs-1.f; - float minTexYNormalized = 0; - if(bCapped) minTexYNormalized = maxTexYNormalized; - maxTexYNormalized = 1.f; - if(bCapped) maxTexYNormalized = (heightSegments) / maxTexY; - - // cylinder vertices // - for(int iy = 0; iy < heightSegments; iy++) { - normal.set(1,0,0); - for(int ix = 0; ix < radiusSegments; ix++) { - - //newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius); - vert.x = cos((float)ix*angleIncRadius) * radius; - vert.y = heightInc*((float)iy) - halfH; - vert.z = sin((float)ix*angleIncRadius) * radius; - - tcoord.x = (float)ix/((float)radiusSegments-1.f); - tcoord.y = ofMap(iy, 0, heightSegments-1, minTexYNormalized, maxTexYNormalized ); - - mesh.addTexCoord( tcoord ); - mesh.addVertex( vert ); - mesh.addNormal( normal ); - - normal.rotateRad(-angleIncRadius, up); - - } - } - - if(mode == OF_PRIMITIVE_TRIANGLES) { - for(int y = 0; y < heightSegments-1; y++) { - for(int x = 0; x < radiusSegments-1; x++) { - // first triangle // - mesh.addIndex( (y)*radiusSegments + x + vertOffset); - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); - - // second triangle // - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); - } - } - } else { - for(int y = 0; y < heightSegments-1; y++) { - for(int x = 0; x < radiusSegments; x++) { - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); - } - } - } - - vertOffset = mesh.getNumVertices(); - - // add the bottom cap - if(bCapped && capSegs > 0) { - minTexYNormalized = maxTexYNormalized; - maxTexYNormalized = 1.f; - - normal.set(0, 1,0); - for(int iy = 0; iy < capSegs; iy++) { - for(int ix = 0; ix < radiusSegments; ix++) { - newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0); - vert.x = cos((float)ix*angleIncRadius) * newRad; - vert.z = sin((float)ix*angleIncRadius) * newRad; - vert.y = halfH; - - tcoord.x = (float)ix/((float)radiusSegments-1.f); - tcoord.y = ofMap(iy, 0, capSegs-1, minTexYNormalized, maxTexYNormalized); - - mesh.addTexCoord( tcoord ); - mesh.addVertex( vert ); - mesh.addNormal( normal ); - } - } - - if(mode == OF_PRIMITIVE_TRIANGLES) { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments-1; x++) { - // first triangle // - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - - if(y < capSegs -1 && capSegs > 2) { - // second triangle // - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } - } else { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments; x++) { - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } - - vertOffset = mesh.getNumVertices(); - - } - - return mesh; + ofMesh mesh; + if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { + mode = OF_PRIMITIVE_TRIANGLE_STRIP; + } + mesh.setMode(mode); + + radiusSegments = radiusSegments+1; + int capSegs = numCapSegments; + capSegs = capSegs+1; + heightSegments = heightSegments+1; + if(heightSegments < 2) heightSegments = 2; + if( capSegs < 2 ) bCapped = false; + if(!bCapped) capSegs=1; + + float angleIncRadius = -1 * (TWO_PI/((float)radiusSegments-1.f)); + float heightInc = height/((float)heightSegments-1.f); + float halfH = height*.5f; + + float newRad; + ofVec3f vert; + ofVec2f tcoord; + ofVec3f normal; + ofVec3f up(0,1,0); + + std::size_t vertOffset = 0; + + float maxTexY = heightSegments-1.f; + if(capSegs > 0) { + maxTexY += (capSegs*2)-2.f; + } + float maxTexYNormalized = (capSegs-1.f) / maxTexY; + + // add the top cap // + if(bCapped && capSegs > 0) { + normal.set(0,-1,0); + for(int iy = 0; iy < capSegs; iy++) { + for(int ix = 0; ix < radiusSegments; ix++) { + newRad = ofMap((float)iy, 0, capSegs-1, 0.0, radius); + vert.x = cos((float)ix*angleIncRadius) * newRad; + vert.z = sin((float)ix*angleIncRadius) * newRad; + vert.y = -halfH; + + tcoord.x = (float)ix/((float)radiusSegments-1.f); + tcoord.y = ofMap(iy, 0, capSegs-1, 0, maxTexYNormalized); + + mesh.addTexCoord( tcoord ); + mesh.addVertex( vert ); + mesh.addNormal( normal ); + } + } + + if(mode == OF_PRIMITIVE_TRIANGLES) { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments-1; x++) { + if(y > 0) { + // first triangle // + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + + // second triangle // + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } else { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments; x++) { + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } + + vertOffset = mesh.getNumVertices(); + + } + + //maxTexY = heightSegments-1.f + capSegs-1.f; + float minTexYNormalized = 0; + if(bCapped) minTexYNormalized = maxTexYNormalized; + maxTexYNormalized = 1.f; + if(bCapped) maxTexYNormalized = (heightSegments) / maxTexY; + + // cylinder vertices // + for(int iy = 0; iy < heightSegments; iy++) { + normal.set(1,0,0); + for(int ix = 0; ix < radiusSegments; ix++) { + + //newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius); + vert.x = cos((float)ix*angleIncRadius) * radius; + vert.y = heightInc*((float)iy) - halfH; + vert.z = sin((float)ix*angleIncRadius) * radius; + + tcoord.x = (float)ix/((float)radiusSegments-1.f); + tcoord.y = ofMap(iy, 0, heightSegments-1, minTexYNormalized, maxTexYNormalized ); + + mesh.addTexCoord( tcoord ); + mesh.addVertex( vert ); + mesh.addNormal( normal ); + + normal.rotateRad(-angleIncRadius, up); + + } + } + + if(mode == OF_PRIMITIVE_TRIANGLES) { + for(int y = 0; y < heightSegments-1; y++) { + for(int x = 0; x < radiusSegments-1; x++) { + // first triangle // + mesh.addIndex( (y)*radiusSegments + x + vertOffset); + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); + + // second triangle // + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); + } + } + } else { + for(int y = 0; y < heightSegments-1; y++) { + for(int x = 0; x < radiusSegments; x++) { + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset ); + } + } + } + + vertOffset = mesh.getNumVertices(); + + // add the bottom cap + if(bCapped && capSegs > 0) { + minTexYNormalized = maxTexYNormalized; + maxTexYNormalized = 1.f; + + normal.set(0, 1,0); + for(int iy = 0; iy < capSegs; iy++) { + for(int ix = 0; ix < radiusSegments; ix++) { + newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0); + vert.x = cos((float)ix*angleIncRadius) * newRad; + vert.z = sin((float)ix*angleIncRadius) * newRad; + vert.y = halfH; + + tcoord.x = (float)ix/((float)radiusSegments-1.f); + tcoord.y = ofMap(iy, 0, capSegs-1, minTexYNormalized, maxTexYNormalized); + + mesh.addTexCoord( tcoord ); + mesh.addVertex( vert ); + mesh.addNormal( normal ); + } + } + + if(mode == OF_PRIMITIVE_TRIANGLES) { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments-1; x++) { + // first triangle // + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + + if(y < capSegs -1 && capSegs > 2) { + // second triangle // + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } + } else { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments; x++) { + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } + + vertOffset = mesh.getNumVertices(); + + } + + return mesh; } // Cone Mesh // //-------------------------------------------------------------- ofMesh ofMesh::cone( float radius, float height, int radiusSegments, int heightSegments, int capSegments, ofPrimitiveMode mode ) { - ofMesh mesh; - if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { - mode = OF_PRIMITIVE_TRIANGLE_STRIP; - } - mesh.setMode(mode); - - radiusSegments = radiusSegments+1; - capSegments = capSegments+1; - heightSegments = heightSegments+1; - if(heightSegments < 2) heightSegments = 2; - int capSegs = capSegments; - if( capSegs < 2 ) { - capSegs = 0; - } - - - float angleIncRadius = -1.f * ((TWO_PI/((float)radiusSegments-1.f))); - float heightInc = height/((float)heightSegments-1); - float halfH = height*.5f; - - float newRad; - ofVec3f vert; - ofVec3f normal; - ofVec2f tcoord; - ofVec3f up(0,1,0); - - - int vertOffset = 0; - - float maxTexY = heightSegments-1.f; - if(capSegs > 0) { - maxTexY += capSegs-1.f; - } - - ofVec3f startVec(0, -halfH-1.f, 0); - - // cone vertices // - for(int iy = 0; iy < heightSegments; iy++) { - normal.set(1,0,0); - for(int ix = 0; ix < radiusSegments; ix++) { - - newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius); - vert.x = cos((float)ix*angleIncRadius) * newRad; - vert.y = heightInc*((float)iy) - halfH; - vert.z = sin((float)ix*angleIncRadius) * newRad; - - tcoord.x = (float)ix/((float)radiusSegments-1.f); - tcoord.y = (float)iy/((float)maxTexY); - - mesh.addTexCoord( tcoord ); - mesh.addVertex( vert ); - - if(iy == 0) { - newRad = 1.f; - vert.x = cos((float)ix*angleIncRadius) * newRad; - vert.y = heightInc*((float)iy) - halfH; - vert.z = sin((float)ix*angleIncRadius) * newRad; - } - - ofVec3f diff = vert-startVec; - ofVec3f crossed = up.getCrossed(vert); - normal = crossed.getNormalized(); - normal = crossed.getPerpendicular(diff); - - normal.normalize(); - - mesh.addNormal( normal ); - //} - - } - } - - if(mode == OF_PRIMITIVE_TRIANGLES) { - for(int y = 0; y < heightSegments-1; y++) { - for(int x = 0; x < radiusSegments-1; x++) { - if(y > 0){ - // first triangle // - mesh.addIndex( (y)*radiusSegments + x ); - mesh.addIndex( (y)*radiusSegments + x+1 ); - mesh.addIndex( (y+1)*radiusSegments + x ); - } - - // second triangle // - mesh.addIndex( (y)*radiusSegments + x+1 ); - mesh.addIndex( (y+1)*radiusSegments + x+1 ); - mesh.addIndex( (y+1)*radiusSegments + x ); - } - } - } else { - for(int y = 0; y < heightSegments-1; y++) { - for(int x = 0; x < radiusSegments; x++) { - mesh.addIndex( (y)*radiusSegments + x ); - mesh.addIndex( (y+1)*radiusSegments + x ); - } - } - } - - vertOffset = mesh.getNumVertices(); - float maxTexYNormalized = (heightSegments-1.f) / maxTexY; - - // add the cap // - normal.set(0,1,0); - for(int iy = 0; iy < capSegs; iy++) { - for(int ix = 0; ix < radiusSegments; ix++) { - newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0); - vert.x = cos((float)ix*angleIncRadius) * newRad; - vert.z = sin((float)ix*angleIncRadius) * newRad; - vert.y = halfH; - - tcoord.x = (float)ix/((float)radiusSegments-1.f); - tcoord.y = ofMap(iy, 0, capSegs-1, maxTexYNormalized, 1.f); - - mesh.addTexCoord( tcoord ); - mesh.addVertex( vert ); - mesh.addNormal( normal ); - } - } - - if(mode == OF_PRIMITIVE_TRIANGLES) { - if( capSegs > 0 ) { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments-1; x++) { - //if(y > 0) { - // first triangle // - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - //} - - if(y < capSegs-1) { - // second triangle // - mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } - } - } else { - if(capSegs > 0 ) { - for(int y = 0; y < capSegs-1; y++) { - for(int x = 0; x < radiusSegments; x++) { - mesh.addIndex( (y)*radiusSegments + x + vertOffset ); - mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); - } - } - } - } - - return mesh; -} + ofMesh mesh; + if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) { + mode = OF_PRIMITIVE_TRIANGLE_STRIP; + } + mesh.setMode(mode); + + radiusSegments = radiusSegments+1; + capSegments = capSegments+1; + heightSegments = heightSegments+1; + if(heightSegments < 2) heightSegments = 2; + int capSegs = capSegments; + if( capSegs < 2 ) { + capSegs = 0; + } + + + float angleIncRadius = -1.f * ((TWO_PI/((float)radiusSegments-1.f))); + float heightInc = height/((float)heightSegments-1); + float halfH = height*.5f; + + float newRad; + ofVec3f vert; + ofVec3f normal; + ofVec2f tcoord; + ofVec3f up(0,1,0); + + std::size_t vertOffset = 0; + + float maxTexY = heightSegments-1.f; + if(capSegs > 0) { + maxTexY += capSegs-1.f; + } + + ofVec3f startVec(0, -halfH-1.f, 0); + + // cone vertices // + for(int iy = 0; iy < heightSegments; iy++) { + normal.set(1,0,0); + for(int ix = 0; ix < radiusSegments; ix++) { + newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius); + vert.x = cos((float)ix*angleIncRadius) * newRad; + vert.y = heightInc*((float)iy) - halfH; + vert.z = sin((float)ix*angleIncRadius) * newRad; + + tcoord.x = (float)ix/((float)radiusSegments-1.f); + tcoord.y = (float)iy/((float)maxTexY); + + mesh.addTexCoord( tcoord ); + mesh.addVertex( vert ); + + if(iy == 0) { + newRad = 1.f; + vert.x = cos((float)ix*angleIncRadius) * newRad; + vert.y = heightInc*((float)iy) - halfH; + vert.z = sin((float)ix*angleIncRadius) * newRad; + } + + ofVec3f diff = vert-startVec; + ofVec3f crossed = up.getCrossed(vert); + normal = crossed.getNormalized(); + normal = crossed.getPerpendicular(diff); + + normal.normalize(); + + mesh.addNormal( normal ); + + } + } + + if(mode == OF_PRIMITIVE_TRIANGLES) { + for(int y = 0; y < heightSegments-1; y++) { + for(int x = 0; x < radiusSegments-1; x++) { + if(y > 0){ + // first triangle // + mesh.addIndex( (y)*radiusSegments + x ); + mesh.addIndex( (y)*radiusSegments + x+1 ); + mesh.addIndex( (y+1)*radiusSegments + x ); + } + + // second triangle // + mesh.addIndex( (y)*radiusSegments + x+1 ); + mesh.addIndex( (y+1)*radiusSegments + x+1 ); + mesh.addIndex( (y+1)*radiusSegments + x ); + } + } + } else { + for(int y = 0; y < heightSegments-1; y++) { + for(int x = 0; x < radiusSegments; x++) { + mesh.addIndex( (y)*radiusSegments + x ); + mesh.addIndex( (y+1)*radiusSegments + x ); + } + } + } + + vertOffset = mesh.getNumVertices(); + float maxTexYNormalized = (heightSegments-1.f) / maxTexY; + + // add the cap // + normal.set(0,1,0); + for(int iy = 0; iy < capSegs; iy++) { + for(int ix = 0; ix < radiusSegments; ix++) { + newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0); + vert.x = cos((float)ix*angleIncRadius) * newRad; + vert.z = sin((float)ix*angleIncRadius) * newRad; + vert.y = halfH; + + tcoord.x = (float)ix/((float)radiusSegments-1.f); + tcoord.y = ofMap(iy, 0, capSegs-1, maxTexYNormalized, 1.f); + + mesh.addTexCoord( tcoord ); + mesh.addVertex( vert ); + mesh.addNormal( normal ); + } + } + + if(mode == OF_PRIMITIVE_TRIANGLES) { + if( capSegs > 0 ) { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments-1; x++) { + // first triangle // + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + + if(y < capSegs-1) { + // second triangle // + mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } + } + } else { + if(capSegs > 0 ) { + for(int y = 0; y < capSegs-1; y++) { + for(int x = 0; x < radiusSegments; x++) { + mesh.addIndex( (y)*radiusSegments + x + vertOffset ); + mesh.addIndex( (y+1)*radiusSegments + x + vertOffset); + } + } + } + } + + return mesh; +} // Box Mesh // //-------------------------------------------------------------- ofMesh ofMesh::box( float width, float height, float depth, int resX, int resY, int resZ ) { - // mesh only available as triangles // - ofMesh mesh; - mesh.setMode( OF_PRIMITIVE_TRIANGLES ); - - resX = resX + 1; - resY = resY + 1; - resZ = resZ + 1; - - if( resX < 2 ) resX = 0; - if( resY < 2 ) resY = 0; - if( resZ < 2 ) resZ = 0; - - // halves // - float halfW = width * .5f; - float halfH = height * .5f; - float halfD = depth * .5f; - - ofVec3f vert; - ofVec2f texcoord; - ofVec3f normal; - int vertOffset = 0; - - // TRIANGLES // - - // Front Face // - normal.set(0, 0, 1); - // add the vertexes // - for(int iy = 0; iy < resY; iy++) { - for(int ix = 0; ix < resX; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resX-1.f)); - texcoord.y = ((float)iy/((float)resY-1.f)); - - vert.x = texcoord.x * width - halfW; - vert.y = texcoord.y * height - halfH; - vert.z = halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resY-1; y++) { - for(int x = 0; x < resX-1; x++) { - // first triangle // - mesh.addIndex((y)*resX + x + vertOffset); - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - } - } - - vertOffset = mesh.getNumVertices(); - - - // Right Side Face // - normal.set(1, 0, 0); - // add the vertexes // - for(int iy = 0; iy < resY; iy++) { - for(int ix = 0; ix < resZ; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resZ-1.f)); - texcoord.y = ((float)iy/((float)resY-1.f)); - - //vert.x = texcoord.x * width - halfW; - vert.x = halfW; - vert.y = texcoord.y * height - halfH; - vert.z = texcoord.x * -depth + halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resY-1; y++) { - for(int x = 0; x < resZ-1; x++) { - // first triangle // - mesh.addIndex((y)*resZ + x + vertOffset); - mesh.addIndex((y)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x + vertOffset); - } - } - - vertOffset = mesh.getNumVertices(); - - // Left Side Face // - normal.set(-1, 0, 0); - // add the vertexes // - for(int iy = 0; iy < resY; iy++) { - for(int ix = 0; ix < resZ; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resZ-1.f)); - texcoord.y = ((float)iy/((float)resY-1.f)); - - //vert.x = texcoord.x * width - halfW; - vert.x = -halfW; - vert.y = texcoord.y * height - halfH; - vert.z = texcoord.x * depth - halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resY-1; y++) { - for(int x = 0; x < resZ-1; x++) { - // first triangle // - mesh.addIndex((y)*resZ + x + vertOffset); - mesh.addIndex((y)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x+1 + vertOffset); - mesh.addIndex((y+1)*resZ + x + vertOffset); - } - } - - vertOffset = mesh.getNumVertices(); - - - // Back Face // - normal.set(0, 0, -1); - // add the vertexes // - for(int iy = 0; iy < resY; iy++) { - for(int ix = 0; ix < resX; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resX-1.f)); - texcoord.y = ((float)iy/((float)resY-1.f)); - - vert.x = texcoord.x * -width + halfW; - vert.y = texcoord.y * height - halfH; - vert.z = -halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resY-1; y++) { - for(int x = 0; x < resX-1; x++) { - // first triangle // - mesh.addIndex((y)*resX + x + vertOffset); - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - } - } - - vertOffset = mesh.getNumVertices(); - - - - // Top Face // - normal.set(0, -1, 0); - // add the vertexes // - for(int iy = 0; iy < resZ; iy++) { - for(int ix = 0; ix < resX; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resX-1.f)); - texcoord.y = ((float)iy/((float)resZ-1.f)); - - vert.x = texcoord.x * width - halfW; - //vert.y = texcoord.y * height - halfH; - vert.y = -halfH; - vert.z = texcoord.y * depth - halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resZ-1; y++) { - for(int x = 0; x < resX-1; x++) { - // first triangle // - mesh.addIndex((y)*resX + x + vertOffset); - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - } - } - - vertOffset = mesh.getNumVertices(); - - - // Bottom Face // - normal.set(0, 1, 0); - // add the vertexes // - for(int iy = 0; iy < resZ; iy++) { - for(int ix = 0; ix < resX; ix++) { - - // normalized tex coords // - texcoord.x = ((float)ix/((float)resX-1.f)); - texcoord.y = ((float)iy/((float)resZ-1.f)); - - vert.x = texcoord.x * width - halfW; - //vert.y = texcoord.y * height - halfH; - vert.y = halfH; - vert.z = texcoord.y * -depth + halfD; - - mesh.addVertex(vert); - mesh.addTexCoord(texcoord); - mesh.addNormal(normal); - } - } - - for(int y = 0; y < resZ-1; y++) { - for(int x = 0; x < resX-1; x++) { - // first triangle // - mesh.addIndex((y)*resX + x + vertOffset); - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - - // second triangle // - mesh.addIndex((y)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x+1 + vertOffset); - mesh.addIndex((y+1)*resX + x + vertOffset); - } - } - - - - return mesh; + // mesh only available as triangles // + ofMesh mesh; + mesh.setMode( OF_PRIMITIVE_TRIANGLES ); + + resX = resX + 1; + resY = resY + 1; + resZ = resZ + 1; + + if( resX < 2 ) resX = 0; + if( resY < 2 ) resY = 0; + if( resZ < 2 ) resZ = 0; + + // halves // + float halfW = width * .5f; + float halfH = height * .5f; + float halfD = depth * .5f; + + ofVec3f vert; + ofVec2f texcoord; + ofVec3f normal; + std::size_t vertOffset = 0; + + // TRIANGLES // + + // Front Face // + normal.set(0, 0, 1); + // add the vertexes // + for(int iy = 0; iy < resY; iy++) { + for(int ix = 0; ix < resX; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resX-1.f)); + texcoord.y = ((float)iy/((float)resY-1.f)); + + vert.x = texcoord.x * width - halfW; + vert.y = texcoord.y * height - halfH; + vert.z = halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resY-1; y++) { + for(int x = 0; x < resX-1; x++) { + // first triangle // + mesh.addIndex((y)*resX + x + vertOffset); + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + } + } + + vertOffset = mesh.getNumVertices(); + + + // Right Side Face // + normal.set(1, 0, 0); + // add the vertexes // + for(int iy = 0; iy < resY; iy++) { + for(int ix = 0; ix < resZ; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resZ-1.f)); + texcoord.y = ((float)iy/((float)resY-1.f)); + + //vert.x = texcoord.x * width - halfW; + vert.x = halfW; + vert.y = texcoord.y * height - halfH; + vert.z = texcoord.x * -depth + halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resY-1; y++) { + for(int x = 0; x < resZ-1; x++) { + // first triangle // + mesh.addIndex((y)*resZ + x + vertOffset); + mesh.addIndex((y)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x + vertOffset); + } + } + + vertOffset = mesh.getNumVertices(); + + // Left Side Face // + normal.set(-1, 0, 0); + // add the vertexes // + for(int iy = 0; iy < resY; iy++) { + for(int ix = 0; ix < resZ; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resZ-1.f)); + texcoord.y = ((float)iy/((float)resY-1.f)); + + //vert.x = texcoord.x * width - halfW; + vert.x = -halfW; + vert.y = texcoord.y * height - halfH; + vert.z = texcoord.x * depth - halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resY-1; y++) { + for(int x = 0; x < resZ-1; x++) { + // first triangle // + mesh.addIndex((y)*resZ + x + vertOffset); + mesh.addIndex((y)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x+1 + vertOffset); + mesh.addIndex((y+1)*resZ + x + vertOffset); + } + } + + vertOffset = mesh.getNumVertices(); + + + // Back Face // + normal.set(0, 0, -1); + // add the vertexes // + for(int iy = 0; iy < resY; iy++) { + for(int ix = 0; ix < resX; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resX-1.f)); + texcoord.y = ((float)iy/((float)resY-1.f)); + + vert.x = texcoord.x * -width + halfW; + vert.y = texcoord.y * height - halfH; + vert.z = -halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resY-1; y++) { + for(int x = 0; x < resX-1; x++) { + // first triangle // + mesh.addIndex((y)*resX + x + vertOffset); + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + } + } + + vertOffset = mesh.getNumVertices(); + + + // Top Face // + normal.set(0, -1, 0); + // add the vertexes // + for(int iy = 0; iy < resZ; iy++) { + for(int ix = 0; ix < resX; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resX-1.f)); + texcoord.y = ((float)iy/((float)resZ-1.f)); + + vert.x = texcoord.x * width - halfW; + //vert.y = texcoord.y * height - halfH; + vert.y = -halfH; + vert.z = texcoord.y * depth - halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resZ-1; y++) { + for(int x = 0; x < resX-1; x++) { + // first triangle // + mesh.addIndex((y)*resX + x + vertOffset); + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + } + } + + vertOffset = mesh.getNumVertices(); + + + // Bottom Face // + normal.set(0, 1, 0); + // add the vertexes // + for(int iy = 0; iy < resZ; iy++) { + for(int ix = 0; ix < resX; ix++) { + + // normalized tex coords // + texcoord.x = ((float)ix/((float)resX-1.f)); + texcoord.y = ((float)iy/((float)resZ-1.f)); + + vert.x = texcoord.x * width - halfW; + //vert.y = texcoord.y * height - halfH; + vert.y = halfH; + vert.z = texcoord.y * -depth + halfD; + + mesh.addVertex(vert); + mesh.addTexCoord(texcoord); + mesh.addNormal(normal); + } + } + + for(int y = 0; y < resZ-1; y++) { + for(int x = 0; x < resX-1; x++) { + // first triangle // + mesh.addIndex((y)*resX + x + vertOffset); + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + + // second triangle // + mesh.addIndex((y)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x+1 + vertOffset); + mesh.addIndex((y+1)*resX + x + vertOffset); + } + } + + return mesh; } @@ -2527,9 +2524,9 @@ ofMesh ofMesh::box( float width, float height, float depth, int resX, int resY, /// Returns an ofMesh representing an XYZ coordinate system. ofMesh ofMesh::axis( float size ) { - ofMesh mesh; + ofMesh mesh; - // mesh only available as wireframe // + // mesh only available as wireframe // mesh.setMode(OF_PRIMITIVE_LINES); ofVec3f vertices[6] = { @@ -2548,10 +2545,10 @@ ofMesh ofMesh::axis( float size ) { ofColor::blue, ofColor::blue, }; - + mesh.addVertices(vertices, 6); mesh.addColors(colors, 6); - + return mesh; } @@ -2567,54 +2564,55 @@ ofMeshFace::ofMeshFace() } const ofVec3f & ofMeshFace::getFaceNormal() const{ - if(bFaceNormalDirty) calculateFaceNormal(); - return faceNormal; + if(bFaceNormalDirty) calculateFaceNormal(); + return faceNormal; } void ofMeshFace::calculateFaceNormal() const{ - ofVec3f U, V; + ofVec3f U, V; - U = (vertices[1]-vertices[0]); - V = (vertices[2]-vertices[0]); + U = (vertices[1]-vertices[0]); + V = (vertices[2]-vertices[0]); - faceNormal = U.getCrossed(V); - faceNormal.normalize(); - bFaceNormalDirty = false; + faceNormal = U.getCrossed(V); + faceNormal.normalize(); + bFaceNormalDirty = false; } void ofMeshFace::setVertex( ofIndexType index, const ofVec3f& v ) { - vertices[index].set( v ); - bFaceNormalDirty = true; + vertices[index].set( v ); + bFaceNormalDirty = true; } const ofVec3f& ofMeshFace::getVertex( ofIndexType index ) const{ - return vertices[index]; + return vertices[index]; } void ofMeshFace::setNormal( ofIndexType index, const ofVec3f& n ) { - normals[index] = n; - bHasNormals = true; + normals[index] = n; + bHasNormals = true; } const ofVec3f& ofMeshFace::getNormal( ofIndexType index ) const{ - return normals[ index ]; + return normals[ index ]; } void ofMeshFace::setColor( ofIndexType index, const ofFloatColor& color ) { - colors[index] = color; - bHasColors = true; + colors[index] = color; + bHasColors = true; } const ofFloatColor& ofMeshFace::getColor( ofIndexType index) const{ - return colors[index]; + return colors[index]; } void ofMeshFace::setTexCoord( ofIndexType index, const ofVec2f& tCoord ) { - texCoords[index] = tCoord; - bHasTexcoords = true; + texCoords[index] = tCoord; + bHasTexcoords = true; } + const ofVec2f& ofMeshFace::getTexCoord( ofIndexType index ) const{ - return texCoords[index]; + return texCoords[index]; } void ofMeshFace::setHasColors( bool bColors ) { @@ -2640,6 +2638,3 @@ bool ofMeshFace::hasNormals() const{ bool ofMeshFace::hasTexcoords() const{ return bHasTexcoords; } - - - diff --git a/libs/openFrameworks/3d/ofMesh.h b/libs/openFrameworks/3d/ofMesh.h index fb138db7e2d..8915cc0b2fe 100644 --- a/libs/openFrameworks/3d/ofMesh.h +++ b/libs/openFrameworks/3d/ofMesh.h @@ -99,10 +99,6 @@ class ofMesh{ void setFromTriangles( const vector& tris, bool bUseFaceNormal=false ); - /// \cond INTERNAL - virtual ~ofMesh(); - /// \endcond - /// \} /// \name Mesh Mode /// \{ @@ -120,12 +116,12 @@ class ofMesh{ /// \} /// \name Primitive constructor helper methods /// \{ - static ofMesh plane(float width, float height, int columns=2, int rows=2, - ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); - static ofMesh sphere(float radius, int res=12, - ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); - static ofMesh icosahedron(float radius); - static ofMesh icosphere(float radius, std::size_t iterations=2); + static ofMesh plane(float width, float height, int columns=2, int rows=2, + ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); + static ofMesh sphere(float radius, int res=12, + ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); + static ofMesh icosahedron(float radius); + static ofMesh icosphere(float radius, std::size_t iterations=2); /// /// \brief A helper method that returns a cylinder made of triangles. /// The resolution settings for the radius, height, and cap are optional @@ -140,9 +136,9 @@ class ofMesh{ /// /// ![image of a simple cylinder](3d/cylinder.jpg) /// - static ofMesh cylinder(float radius, float height, int radiusSegments=12, - int heightSegments=6, int numCapSegments=2, bool bCapped = true, - ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); + static ofMesh cylinder(float radius, float height, int radiusSegments=12, + int heightSegments=6, int numCapSegments=2, bool bCapped = true, + ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP); /// \brief A helper method that returns a cone made of triangles. /// The resolution settings for the radius, height, and cap are optional @@ -177,7 +173,7 @@ class ofMesh{ /// \} /// \name Vertices /// \{ - + /// \brief Add a new vertex at the end of the current list of vertices. /// It is important to remember that the order the vertices are added to /// the list determines how they link they form the polygons and strips @@ -236,11 +232,11 @@ class ofMesh{ /// \brief Add the vertices, normals, texture coordinates and indices of one mesh onto another mesh. /// Everything from the referenced mesh is simply added at the end /// of the current mesh's lists. - void append(const ofMesh & mesh); + void append(const ofMesh & mesh); - void mergeDuplicateVertices(); + void mergeDuplicateVertices(); - /// \returns a ofVec3f defining the centroid of all the vetices in the mesh. + /// \returns a ofVec3f defining the centroid of all the vetices in the mesh. ofVec3f getCentroid() const; @@ -278,7 +274,7 @@ class ofMesh{ /// \brief Remove a normal. void removeNormal(ofIndexType index); - /// \todo + /// \todo Documentation. void setNormal(ofIndexType index, const ofVec3f& n); /// \brief Remove all the normals. @@ -311,42 +307,43 @@ class ofMesh{ bool hasNormals() const; /// \brief Enable mesh normals. - /// Use disableNormals() to turn normals off. - /// Normals are enabled by default when they are added to the mesh. - virtual void enableNormals(); - /// \brief Disable mesh normals. - /// Use enableNormals() to turn normals back on. - virtual void disableNormals(); - virtual bool usingNormals() const; - - void smoothNormals( float angle ); - - /// \} - /// \name Faces - /// \{ + /// Use disableNormals() to turn normals off. + /// Normals are enabled by default when they are added to the mesh. + virtual void enableNormals(); + /// \brief Disable mesh normals. + /// Use enableNormals() to turn normals back on. + virtual void disableNormals(); + virtual bool usingNormals() const; + + void smoothNormals( float angle ); + + /// \} + /// \name Faces + /// \{ /// \returns the vector that contains all of the faces of the mesh. This isn't currently implemented. - ofMeshFace getFace(ofIndexType faceId) const; + ofMeshFace getFace(ofIndexType faceId) const; - /// \brief Get normals for each face - /// As a default it only calculates the normal for the face as a whole but - /// by setting (perVertex = true) it will return the same normal value for - /// each of the three vertices making up a face. - /// \returns a vector containing the calculated normals of each face in the mesh. - vector getFaceNormals( bool perVetex=false) const; + /// \brief Get normals for each face + /// As a default it only calculates the normal for the face as a whole but + /// by setting (perVertex = true) it will return the same normal value for + /// each of the three vertices making up a face. + /// \returns a vector containing the calculated normals of each face in the mesh. + vector getFaceNormals( bool perVetex=false) const; - /// \returns the mesh as a vector of unique ofMeshFaces - /// a list of triangles that do not share vertices or indices - const vector & getUniqueFaces() const; + /// \returns the mesh as a vector of unique ofMeshFaces + /// a list of triangles that do not share vertices or indices + const vector & getUniqueFaces() const; /// \} /// \name Colors /// \{ - /// \brief \returns the color at the index in the colors vector. + /// \brief Get the color at the index in the colors vector. + /// \returns the color at the index in the colors vector. ofFloatColor getColor(ofIndexType i) const; - /// \brief This adds a color to the mesh, + /// \brief This adds a color to the mesh, /// the color will be associated with the vertex in the same position. void addColor(const ofFloatColor& c); @@ -393,12 +390,12 @@ class ofMesh{ /// \brief Enable mesh colors. /// Use disableColors() to turn colors off. /// Colors are enabled by default when they are added to the mesh. - virtual void enableColors(); + virtual void enableColors(); - /// \brief Disable mesh colors. - /// Use enableColors() to turn colors back on. - virtual void disableColors(); - virtual bool usingColors() const; + /// \brief Disable mesh colors. + /// Use enableColors() to turn colors back on. + virtual void disableColors(); + virtual bool usingColors() const; /// \} @@ -464,14 +461,14 @@ class ofMesh{ bool hasTexCoords() const; /// \brief Enable mesh textures. - /// Use disableTextures() to turn textures off. - /// Textures are enabled by default when they are added to the mesh. - virtual void enableTextures(); - - /// \brief Disable mesh textures. - /// Use enableTextures() to turn textures back on. - virtual void disableTextures(); - virtual bool usingTextures() const; + /// Use disableTextures() to turn textures off. + /// Textures are enabled by default when they are added to the mesh. + virtual void enableTextures(); + + /// \brief Disable mesh textures. + /// Use enableTextures() to turn textures back on. + virtual void disableTextures(); + virtual bool usingTextures() const; /// \} @@ -557,23 +554,23 @@ class ofMesh{ /// This is an easy way to create triangles in the mesh. The indices refer to the index of the vertex in the vector of vertices. void addTriangle(ofIndexType index1, ofIndexType index2, ofIndexType index3); - /// \brief Enable mesh indices. - /// Use disableIndices() to turn indices off. - /// Indices are enabled by default when they are added to the mesh. - virtual void enableIndices(); + /// \brief Enable mesh indices. + /// Use disableIndices() to turn indices off. + /// Indices are enabled by default when they are added to the mesh. + virtual void enableIndices(); + + /// \brief Disable mesh indices. + /// Use enableIndices() to turn indices back on. + virtual void disableIndices(); + virtual bool usingIndices() const; - /// \brief Disable mesh indices. - /// Use enableIndices() to turn indices back on. - virtual void disableIndices(); - virtual bool usingIndices() const; + void setColorForIndices( ofIndexType startIndex, ofIndexType endIndex, ofColor color ); - void setColorForIndices( ofIndexType startIndex, ofIndexType endIndex, ofColor color ); + /// The new mesh includes the mesh mode, colors, textures, and normals of the original mesh (assuming any were added). + /// \returns a mesh made up of a range of indices from startIndex to the endIndex. + ofMesh getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex ) const; + ofMesh getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex, ofIndexType startVertIndex, ofIndexType endVertIndex ) const; - /// The new mesh includes the mesh mode, colors, textures, and normals of the original mesh (assuming any were added). - /// \returns a mesh made up of a range of indices from startIndex to the endIndex. - ofMesh getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex ) const; - ofMesh getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex, ofIndexType startVertIndex, ofIndexType endVertIndex ) const; - /// \} /// \name Drawing @@ -601,21 +598,21 @@ class ofMesh{ /// \{ /// \brief Loads a mesh from a file located at the provided path into the mesh. - /// This will replace any existing data within the mesh. - /// - /// It expects that the file will be in the [PLY Format](http://en.wikipedia.org/wiki/PLY_(file_format)). - /// It will only load meshes saved in the PLY ASCII format; the binary format is not supported. + /// This will replace any existing data within the mesh. + /// + /// It expects that the file will be in the [PLY Format](http://en.wikipedia.org/wiki/PLY_(file_format)). + /// It will only load meshes saved in the PLY ASCII format; the binary format is not supported. void load(string path); - /// \brief Saves the mesh at the passed path in the [PLY Format](http://en.wikipedia.org/wiki/PLY_(file_format)). - /// - /// There are two format options for PLY: a binary format and an ASCII format. - /// By default, it will save using the ASCII format. - /// Passing ``true`` into the ``useBinary`` parameter will save it in the binary format. - /// - /// If you're planning on reloading the mesh into ofMesh, ofMesh currently only supports loading the ASCII format. - /// - /// For more information, see the [PLY format specification](http://paulbourke.net/dataformats/ply/). + /// \brief Saves the mesh at the passed path in the [PLY Format](http://en.wikipedia.org/wiki/PLY_(file_format)). + /// + /// There are two format options for PLY: a binary format and an ASCII format. + /// By default, it will save using the ASCII format. + /// Passing ``true`` into the ``useBinary`` parameter will save it in the binary format. + /// + /// If you're planning on reloading the mesh into ofMesh, ofMesh currently only supports loading the ASCII format. + /// + /// For more information, see the [PLY format specification](http://paulbourke.net/dataformats/ply/). void save(string path, bool useBinary = false) const; /// \} @@ -637,10 +634,10 @@ class ofMesh{ bIndicesChanged; ofPrimitiveMode mode; - bool useColors; - bool useTextures; - bool useNormals; - bool useIndices; + bool useColors; + bool useTextures; + bool useNormals; + bool useIndices; // ofMaterial *mat; }; @@ -663,40 +660,40 @@ class ofMesh{ /// this is always a triangle class ofMeshFace { public: - ofMeshFace(); + ofMeshFace(); - const ofVec3f & getFaceNormal() const; + const ofVec3f & getFaceNormal() const; - void setVertex( ofIndexType index, const ofVec3f& v ); - const ofVec3f& getVertex( ofIndexType index ) const; + void setVertex( ofIndexType index, const ofVec3f& v ); + const ofVec3f& getVertex( ofIndexType index ) const; - void setNormal( ofIndexType index, const ofVec3f& n ); - const ofVec3f& getNormal( ofIndexType index ) const; + void setNormal( ofIndexType index, const ofVec3f& n ); + const ofVec3f& getNormal( ofIndexType index ) const; - void setColor( ofIndexType index, const ofFloatColor& color ); - const ofFloatColor& getColor(ofIndexType index) const; + void setColor( ofIndexType index, const ofFloatColor& color ); + const ofFloatColor& getColor(ofIndexType index) const; - void setTexCoord( ofIndexType index, const ofVec2f& tCoord ); - const ofVec2f& getTexCoord( ofIndexType index ) const; + void setTexCoord( ofIndexType index, const ofVec2f& tCoord ); + const ofVec2f& getTexCoord( ofIndexType index ) const; - void setHasColors( bool bColors ); - void setHasNormals( bool bNormals ); - void setHasTexcoords( bool bTexcoords ); + void setHasColors( bool bColors ); + void setHasNormals( bool bNormals ); + void setHasTexcoords( bool bTexcoords ); - bool hasColors() const; - bool hasNormals() const; - bool hasTexcoords() const; + bool hasColors() const; + bool hasNormals() const; + bool hasTexcoords() const; private: - void calculateFaceNormal() const; - bool bHasNormals, bHasColors, bHasTexcoords; + void calculateFaceNormal() const; + bool bHasNormals, bHasColors, bHasTexcoords; // this variables are only caches and returned always as const // mutable allows to change them from const methods - mutable bool bFaceNormalDirty; - mutable ofVec3f faceNormal; - ofVec3f vertices[3]; - ofVec3f normals[3]; - ofFloatColor colors[3]; - ofVec2f texCoords[3]; + mutable bool bFaceNormalDirty; + mutable ofVec3f faceNormal; + ofVec3f vertices[3]; + ofVec3f normals[3]; + ofFloatColor colors[3]; + ofVec2f texCoords[3]; }; diff --git a/libs/openFrameworks/3d/ofNode.cpp b/libs/openFrameworks/3d/ofNode.cpp index 80323037105..c7a557a8642 100644 --- a/libs/openFrameworks/3d/ofNode.cpp +++ b/libs/openFrameworks/3d/ofNode.cpp @@ -4,27 +4,137 @@ #include "ofLog.h" #include "of3dGraphics.h" +//---------------------------------------- ofNode::ofNode() :parent(nullptr) ,legacyCustomDrawOverrided(true){ setPosition(ofVec3f(0, 0, 0)); setOrientation(ofVec3f(0, 0, 0)); setScale(1); + position.disableEvents(); + scale.disableEvents(); + orientation.disableEvents(); +} + +//---------------------------------------- +ofNode::~ofNode(){ + if(parent){ + parent->removeListener(*this); + } + for(auto child: children){ + child->clearParent(); + } +} + +//---------------------------------------- +ofNode::ofNode(const ofNode & node) +:parent(node.parent) +,axis(node.axis) +,localTransformMatrix(node.localTransformMatrix) +,legacyCustomDrawOverrided(true){ + if(parent){ + parent->addListener(*this); + } + position = node.position; + orientation = node.orientation; + scale = node.scale; + position.disableEvents(); + scale.disableEvents(); + orientation.disableEvents(); +} + +//---------------------------------------- +ofNode::ofNode(ofNode && node) +:parent(node.parent) +,position(std::move(node.position)) +,orientation(std::move(node.orientation)) +,scale(std::move(node.scale)) +,axis(std::move(node.axis)) +,localTransformMatrix(std::move(node.localTransformMatrix)) +,legacyCustomDrawOverrided(std::move(node.legacyCustomDrawOverrided)) +,children(std::move(node.children)){ + if(parent){ + parent->addListener(*this); + } +} + +//---------------------------------------- +ofNode & ofNode::operator=(const ofNode & node){ + if(this == &node) return *this; + parent = node.parent; + position = node.position; + orientation = node.orientation; + scale = node.scale; + axis = node.axis; + position.disableEvents(); + scale.disableEvents(); + orientation.disableEvents(); + localTransformMatrix = node.localTransformMatrix; + legacyCustomDrawOverrided = true; + if(parent){ + parent->addListener(*this); + } + return *this; +} + +//---------------------------------------- +ofNode & ofNode::operator=(ofNode && node){ + if(this == &node) return *this; + parent = node.parent; + position = std::move(node.position); + orientation = std::move(node.orientation); + scale = std::move(node.scale); + axis = std::move(node.axis); + localTransformMatrix = std::move(node.localTransformMatrix); + legacyCustomDrawOverrided = std::move(node.legacyCustomDrawOverrided); + children = std::move(node.children); + if(parent){ + parent->addListener(*this); + } + return *this; +} + +//---------------------------------------- +void ofNode::addListener(ofNode & node){ + position.addListener(&node, &ofNode::onParentPositionChanged); + orientation.addListener(&node, &ofNode::onParentOrientationChanged); + scale.addListener(&node, &ofNode::onParentScaleChanged); + position.enableEvents(); + orientation.enableEvents(); + scale.enableEvents(); + children.insert(&node); +} + +//---------------------------------------- +void ofNode::removeListener(ofNode & node){ + position.removeListener(&node, &ofNode::onParentPositionChanged); + orientation.removeListener(&node, &ofNode::onParentOrientationChanged); + scale.removeListener(&node, &ofNode::onParentScaleChanged); + if(position.getNumListeners()==0){ + position.disableEvents(); + scale.disableEvents(); + orientation.disableEvents(); + } + children.erase(&node); } //---------------------------------------- void ofNode::setParent(ofNode& parent, bool bMaintainGlobalTransform) { if(bMaintainGlobalTransform) { ofMatrix4x4 postParentGlobalTransform = getGlobalTransformMatrix() * parent.getGlobalTransformMatrix().getInverse(); - this->parent = &parent; + parent.addListener(*this); setTransformMatrix(postParentGlobalTransform); } else { - this->parent = &parent; + parent.addListener(*this); } + this->parent = &parent; } //---------------------------------------- void ofNode::clearParent(bool bMaintainGlobalTransform) { + if(parent){ + parent->removeListener(*this); + } if(bMaintainGlobalTransform) { ofMatrix4x4 globalTransform(getGlobalTransformMatrix()); this->parent = nullptr; @@ -43,8 +153,14 @@ ofNode* ofNode::getParent() const { void ofNode::setTransformMatrix(const ofMatrix4x4 &m44) { localTransformMatrix = m44; + ofVec3f position; + ofQuaternion orientation; + ofVec3f scale; ofQuaternion so; localTransformMatrix.decompose(position, orientation, scale, so); + this->position = position; + this->orientation = orientation; + this->scale = scale; updateAxis(); onPositionChanged(); @@ -85,17 +201,17 @@ ofVec3f ofNode::getPosition() const { //---------------------------------------- float ofNode::getX() const { - return position.x; + return position->x; } //---------------------------------------- float ofNode::getY() const { - return position.y; + return position->y; } //---------------------------------------- float ofNode::getZ() const { - return position.z; + return position->z; } //---------------------------------------- @@ -128,7 +244,7 @@ ofQuaternion ofNode::getOrientationQuat() const { //---------------------------------------- ofVec3f ofNode::getOrientationEuler() const { - return orientation.getEuler(); + return orientation->getEuler(); } //---------------------------------------- @@ -230,6 +346,19 @@ void ofNode::rotateAround(float degrees, const ofVec3f& axis, const ofVec3f& poi rotateAround(ofQuaternion(degrees, axis), point); } +//---------------------------------------- +void ofNode::lookAt(const ofVec3f& lookAtPosition){ + auto relPosition = (getGlobalPosition() - lookAtPosition); + auto radius = relPosition.length(); + if(radius>0){ + auto latitude = ofRadToDeg(acos(relPosition.y / radius)) - 90; + auto longitude = ofRadToDeg(atan2(relPosition.x , relPosition.z)); + ofQuaternion q(latitude, ofVec3f(1,0,0), longitude, ofVec3f(0,1,0), 0, ofVec3f(0,0,1)); + setGlobalOrientation(q); + } + +} + //---------------------------------------- void ofNode::lookAt(const ofVec3f& lookAtPosition, ofVec3f upVector) { if(parent) upVector = upVector * ofMatrix4x4::getInverseOf(parent->getGlobalTransformMatrix()); @@ -247,6 +376,11 @@ void ofNode::lookAt(const ofVec3f& lookAtPosition, ofVec3f upVector) { } } +//---------------------------------------- +void ofNode::lookAt(const ofNode& lookAtNode){ + lookAt(lookAtNode.getGlobalPosition()); +} + //---------------------------------------- void ofNode::lookAt(const ofNode& lookAtNode, const ofVec3f& upVector) { lookAt(lookAtNode.getGlobalPosition(), upVector); @@ -254,9 +388,9 @@ void ofNode::lookAt(const ofNode& lookAtNode, const ofVec3f& upVector) { //---------------------------------------- void ofNode::updateAxis() { - if(scale[0]>0) axis[0] = getLocalTransformMatrix().getRowAsVec3f(0)/scale[0]; - if(scale[1]>0) axis[1] = getLocalTransformMatrix().getRowAsVec3f(1)/scale[1]; - if(scale[2]>0) axis[2] = getLocalTransformMatrix().getRowAsVec3f(2)/scale[2]; + if(scale->x>0) axis[0] = getLocalTransformMatrix().getRowAsVec3f(0)/scale->x; + if(scale->y>0) axis[1] = getLocalTransformMatrix().getRowAsVec3f(1)/scale->y; + if(scale->z>0) axis[2] = getLocalTransformMatrix().getRowAsVec3f(2)/scale->z; } //---------------------------------------- @@ -333,16 +467,12 @@ ofVec3f ofNode::getGlobalScale() const { //---------------------------------------- void ofNode::orbit(float longitude, float latitude, float radius, const ofVec3f& centerPoint) { - ofMatrix4x4 m; - - // find position - ofVec3f p(0, 0, radius); - p.rotate(ofClamp(latitude, -89, 89), ofVec3f(1, 0, 0)); - p.rotate(longitude, ofVec3f(0, 1, 0)); - p += centerPoint; - setPosition(p); - - lookAt(centerPoint);//, v - centerPoint); + ofQuaternion q(latitude, ofVec3f(1,0,0), longitude, ofVec3f(0,1,0), 0, ofVec3f(0,0,1)); + setPosition((ofVec3f(0,0,radius)-centerPoint)*q +centerPoint); + setOrientation(q); + onOrientationChanged(); + onPositionChanged(); +// lookAt(centerPoint);//, v - centerPoint); } //---------------------------------------- @@ -354,6 +484,7 @@ void ofNode::orbit(float longitude, float latitude, float radius, ofNode& center void ofNode::resetTransform() { setPosition(ofVec3f()); setOrientation(ofVec3f()); + setScale({1.f,1.f,1.f}); } //---------------------------------------- diff --git a/libs/openFrameworks/3d/ofNode.h b/libs/openFrameworks/3d/ofNode.h index cfc9ef56f58..8475629e4af 100644 --- a/libs/openFrameworks/3d/ofNode.h +++ b/libs/openFrameworks/3d/ofNode.h @@ -4,6 +4,8 @@ #include "ofVectorMath.h" #include "of3dUtils.h" #include "ofAppRunner.h" +#include "ofParameter.h" +#include /// \brief A generic 3d object in space with transformation (position, rotation, scale). @@ -42,7 +44,11 @@ class ofNode { /// \cond INTERNAL ofNode(); - virtual ~ofNode() {} + virtual ~ofNode(); + ofNode(const ofNode & node); + ofNode(ofNode && node); + ofNode & operator=(const ofNode & node); + ofNode & operator=(ofNode && node); /// \endcond @@ -114,7 +120,7 @@ class ofNode { ofQuaternion getGlobalOrientation() const; ofVec3f getGlobalScale() const; - /// \} + /// \} /// \name Setters /// \{ @@ -142,7 +148,7 @@ class ofNode { void setScale(const ofVec3f& s); /// \} - /// \name Modifiers + /// \name Modifiers /// \{ /// \brief Move by arbitrary amount @@ -182,13 +188,25 @@ class ofNode { void rotateAround(const ofQuaternion& q, const ofVec3f& point); /// \brief Rotate around arbitrary axis by angle around point - void rotateAround(float degrees, const ofVec3f& axis, const ofVec3f& point); + void rotateAround(float degrees, const ofVec3f& axis, const ofVec3f& point); + + /// \brief Orient node to look at position (-z axis pointing to position) + /// + /// This version calculates the up vector by rotating {0,1,0} by the same + /// angle that will rotate {0,0,1} to the current position - lookAtPosition + void lookAt(const ofVec3f& lookAtPosition); /// \brief Orient node to look at position (-z axis pointing to position) - void lookAt(const ofVec3f& lookAtPosition, ofVec3f upVector = ofVec3f(0, 1, 0)); + void lookAt(const ofVec3f& lookAtPosition, ofVec3f upVector); + + /// \brief Orient node to look at node (-z axis pointing to node) + /// + /// This version calculates the up vector by rotating {0,1,0} by the same + /// angle that will rotate {0,0,1} to the current position - lookAtPosition + void lookAt(const ofNode& lookAtNode); /// \brief Orient node to look at node (-z axis pointing to node) - void lookAt(const ofNode& lookAtNode, const ofVec3f& upVector = ofVec3f(0, 1, 0)); + void lookAt(const ofNode& lookAtNode, const ofVec3f& upVector); /// \brief Orbit object around target at radius void orbit(float longitude, float latitude, float radius, const ofVec3f& centerPoint = ofVec3f(0, 0, 0)); @@ -229,9 +247,6 @@ class ofNode { /// \} protected: - - ofNode *parent; - void createMatrix(); void updateAxis(); @@ -245,14 +260,24 @@ class ofNode { /// \brief classes extending ofNode can override this methods to get notified when the scale changed. virtual void onScaleChanged() {} + ofNode * parent; + private: - ofVec3f position; - ofQuaternion orientation; - ofVec3f scale; - - ofVec3f axis[3]; - + void onParentPositionChanged(ofVec3f & position) {onPositionChanged();} + void onParentOrientationChanged(ofQuaternion & orientation) {onOrientationChanged();} + void onParentScaleChanged(ofVec3f & scale) {onScaleChanged();} + + ofParameter position; + ofParameter orientation; + ofParameter scale; + + std::array axis; + ofMatrix4x4 localTransformMatrix; bool legacyCustomDrawOverrided; + std::set children; + + void addListener(ofNode & node); + void removeListener(ofNode & node); // ofMatrix4x4 globalTransformMatrix; }; diff --git a/libs/openFrameworks/app/ofAppEGLWindow.cpp b/libs/openFrameworks/app/ofAppEGLWindow.cpp index 96617297ea6..6d05635f6c0 100644 --- a/libs/openFrameworks/app/ofAppEGLWindow.cpp +++ b/libs/openFrameworks/app/ofAppEGLWindow.cpp @@ -100,6 +100,16 @@ static int string_ends_with(const char *str, const char *suffix) { return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; } +static int string_begins_with(const char *str, const char *prefix) { + if (!str || !prefix) + return 0; + size_t lenstr = strlen(str); + size_t lenprefix = strlen(prefix); + if (lenprefix > lenstr) + return 0; + return strncmp(str, prefix, lenprefix) == 0; +} + static int dummy_sort(const struct dirent **a,const struct dirent **b) { return 1; // dummy sort } @@ -120,6 +130,14 @@ static int filter_mouse(const struct dirent *d) { } } +static int filter_event(const struct dirent *d) { + if(d->d_type != DT_DIR && string_begins_with(d->d_name,"event")) { + return 1; + } else { + return 0; + } +} + // native #define MOUSE_CURSOR_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \ { unsigned int __bpp; unsigned char *__ip; const unsigned char *__il, *__rd; \ @@ -962,11 +980,8 @@ void ofAppEGLWindow::setWindowRect(const ofRectangle& requestedWindowRect) { &dst_rect, &src_rect, 0, // mask (we aren't changing it here) -#ifdef USE_DISPMANX_TRANSFORM_T (DISPMANX_TRANSFORM_T)0); -#else - (VC_IMAGE_TRANSFORM_T)0); -#endif + vc_dispmanx_update_submit_sync(dispman_update); @@ -1187,11 +1202,8 @@ void ofAppEGLWindow::setWindowPosition(int x, int y){ &dst_rect, NULL, 0, -#ifdef USE_DISPMANX_TRANSFORM_T -(DISPMANX_TRANSFORM_T)0); -#else - (VC_IMAGE_TRANSFORM_T)0); -#endif + (DISPMANX_TRANSFORM_T)0); + vc_dispmanx_update_submit_sync(dispman_update); @@ -1343,17 +1355,23 @@ void ofAppEGLWindow::destroyNativeUDev() { //------------------------------------------------------------ void ofAppEGLWindow::setupNativeMouse() { struct dirent **eps; - int n = scandir("/dev/input/by-path/", &eps, filter_mouse, dummy_sort); - - // make sure that we found an appropriate entry - if(n >= 0 && eps != 0 && eps[0] != 0) { - string devicePathBuffer; - devicePathBuffer.append("/dev/input/by-path/"); - devicePathBuffer.append(eps[0]->d_name); - mouse_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); - ofLogNotice("ofAppEGLWindow") << "setupMouse(): mouse_fd= " << mouse_fd << " devicePath=" << devicePathBuffer; - } else { - ofLogNotice("ofAppEGLWindow") << "setupMouse(): unabled to find mouse"; + // fallback to /dev/input/eventX since some vnc servers use uinput to handle mouse & keyboard + typedef int (*filter_ptr)(const struct dirent *d); + filter_ptr mouse_filters[2] = { filter_mouse, filter_event }; + string devicePathBuffers[2] = { "/dev/input/by-path", "/dev/input/" }; + + for(int i=0; i<2; i++){ + int n = scandir(devicePathBuffers[i].c_str(), &eps, mouse_filters[i], dummy_sort); + + // make sure that we found an appropriate entry + if(n >= 0 && eps != 0 && eps[0] != 0) { + string devicePathBuffer; + devicePathBuffer.append(devicePathBuffers[i]); + devicePathBuffer.append(eps[0]->d_name); + mouse_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); + ofLogNotice("ofAppEGLWindow") << "setupMouse(): mouse_fd=" << mouse_fd << " devicePath=" << devicePathBuffer; + break; + } } if (mouse_fd >= 0) { @@ -1368,7 +1386,7 @@ void ofAppEGLWindow::setupNativeMouse() { if(mouse_fd < 0) { ofLogError("ofAppEGLWindow") << "setupMouse(): did not open mouse, mouse_fd < 0"; - }else { + } else { mouseDetected = true; } @@ -1378,18 +1396,22 @@ void ofAppEGLWindow::setupNativeMouse() { //------------------------------------------------------------ void ofAppEGLWindow::setupNativeKeyboard() { struct dirent **eps; - int n = scandir("/dev/input/by-path/", &eps, filter_kbd, dummy_sort); - - // make sure that we found an appropriate entry - if(n >= 0 && eps != 0 && eps[0] != 0) { - string devicePathBuffer; - devicePathBuffer.append("/dev/input/by-path/"); - devicePathBuffer.append(eps[0]->d_name); - keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); - ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd= " << keyboard_fd << " devicePath=" << devicePathBuffer; - - } else { - ofLogWarning("ofAppEGLWindow") << "setupKeyboard(): unabled to find keyboard"; + typedef int (*filter_ptr)(const struct dirent *d); + filter_ptr kbd_filters[2] = { filter_kbd, filter_event }; + string devicePathBuffers[2] = { "/dev/input/by-path", "/dev/input/" }; + + for(int i=0; i<2; i++){ + int n = scandir(devicePathBuffers[i].c_str(), &eps, kbd_filters[i], dummy_sort); + + // make sure that we found an appropriate entry + if(n >= 0 && eps != 0 && eps[0] != 0) { + string devicePathBuffer; + devicePathBuffer.append(devicePathBuffers[i]); + devicePathBuffer.append(eps[0]->d_name); + keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); + ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd=" << keyboard_fd << " devicePath=" << devicePathBuffer; + break; + } } if (keyboard_fd >= 0) { @@ -1415,7 +1437,7 @@ void ofAppEGLWindow::setupNativeKeyboard() { if(keyboard_fd < 0) { ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard, keyboard_fd < 0"; - }else { + } else { keyboardDetected = true; } } diff --git a/libs/openFrameworks/app/ofAppGLFWWindow.cpp b/libs/openFrameworks/app/ofAppGLFWWindow.cpp index fa6c9aeffbb..d3fd05e3de0 100644 --- a/libs/openFrameworks/app/ofAppGLFWWindow.cpp +++ b/libs/openFrameworks/app/ofAppGLFWWindow.cpp @@ -35,7 +35,7 @@ ofAppGLFWWindow::ofAppGLFWWindow(){ bEnableSetupScreen = true; buttonInUse = 0; buttonPressed = false; - bMultiWindowFullscreen = false; + bWindowNeedsShowing = true; orientation = OF_ORIENTATION_DEFAULT; windowMode = OF_WINDOW; @@ -58,9 +58,12 @@ ofAppGLFWWindow::~ofAppGLFWWindow(){ void ofAppGLFWWindow::close(){ if(windowP){ + //hide the window before we destroy it stops a flicker on OS X on exit. + glfwHideWindow(windowP); glfwDestroyWindow(windowP); windowP = nullptr; events().disable(); + bWindowNeedsShowing = true; } } @@ -71,7 +74,7 @@ void ofAppGLFWWindow::setNumSamples(int _samples){ //------------------------------------------------------------ void ofAppGLFWWindow::setMultiDisplayFullscreen(bool bMultiFullscreen){ - bMultiWindowFullscreen = bMultiFullscreen; + settings.multiMonitorFullScreen = bMultiFullscreen; } //------------------------------------------------------------ @@ -131,7 +134,6 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ // ofLogNotice("ofAppGLFWWindow") << "WINDOW MODE IS " << screenMode; - ofWindowMode requestedMode = _settings.windowMode; glfwDefaultWindowHints(); glfwWindowHint(GLFW_RED_BITS, settings.redBits); glfwWindowHint(GLFW_GREEN_BITS, settings.greenBits); @@ -140,21 +142,21 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ glfwWindowHint(GLFW_DEPTH_BITS, settings.depthBits); glfwWindowHint(GLFW_STENCIL_BITS, settings.stencilBits); glfwWindowHint(GLFW_STEREO, settings.stereo); - glfwWindowHint(GLFW_VISIBLE,GL_FALSE); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); #ifndef TARGET_OSX - glfwWindowHint(GLFW_AUX_BUFFERS,settings.doubleBuffering?1:0); + glfwWindowHint(GLFW_AUX_BUFFERS, settings.doubleBuffering?1:0); #endif - glfwWindowHint(GLFW_SAMPLES,settings.numSamples); + glfwWindowHint(GLFW_SAMPLES, settings.numSamples); glfwWindowHint(GLFW_RESIZABLE, settings.resizable); glfwWindowHint(GLFW_DECORATED, settings.decorated); #ifdef TARGET_OPENGLES glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, settings.glesVersion); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API,GLFW_OPENGL_ES_API); - if(settings.glesVersion>=1){ - currentRenderer = shared_ptr(new ofGLProgrammableRenderer); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + if(settings.glesVersion>=2){ + currentRenderer = shared_ptr(new ofGLProgrammableRenderer(this)); }else{ - currentRenderer = shared_ptr(new ofGLRenderer); + currentRenderer = shared_ptr(new ofGLRenderer(this)); } #else glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); @@ -176,19 +178,50 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ sharedContext = (GLFWwindow*)settings.shareContextWith->getWindowContext(); } - if(requestedMode==OF_GAME_MODE){ + if(settings.windowMode==OF_GAME_MODE){ int count; GLFWmonitor** monitors = glfwGetMonitors(&count); if(count>settings.monitor){ - windowP = glfwCreateWindow(settings.width, settings.height, "", monitors[settings.monitor], sharedContext); + windowP = glfwCreateWindow(settings.width, settings.height, settings.title.c_str(), monitors[settings.monitor], sharedContext); }else{ ofLogError("ofAppGLFWWindow") << "couldn't find any monitors"; return; } }else{ - windowP = glfwCreateWindow(settings.width, settings.height, "", nullptr, sharedContext); + windowP = glfwCreateWindow(settings.width, settings.height, settings.title.c_str(), nullptr, sharedContext); if(!windowP){ ofLogError("ofAppGLFWWindow") << "couldn't create GLFW window"; + return; + } + if(settings.windowMode==OF_FULLSCREEN){ + if(!settings.isPositionSet()){ + int count = 0; + auto monitors = glfwGetMonitors(&count); + if(count > 0){ + int x = 0, y = 0; + settings.monitor = ofClamp(settings.monitor,0,count-1); + glfwGetMonitorPos(monitors[settings.monitor],&x,&y); + settings.setPosition(ofVec2f(x,y)); + setWindowPosition(settings.getPosition().x,settings.getPosition().y); + auto mode = glfwGetVideoMode(monitors[settings.monitor]); + settings.width = mode->width; + settings.height = mode->height; + //for OS X we need to set this first as the window size affects the window positon + setWindowShape(settings.width, settings.height); + setWindowPosition(settings.getPosition().x,settings.getPosition().y); + } + }else{ + setWindowPosition(settings.getPosition().x,settings.getPosition().y); + auto size = getScreenSize(); + settings.width = size.x; + settings.height = size.y; + setWindowShape(settings.width, settings.height); + } + setFullscreen(true); + }else{ + if (settings.isPositionSet()) { + setWindowPosition(settings.getPosition().x,settings.getPosition().y); + } } #ifdef TARGET_LINUX if(!iconSet){ @@ -203,23 +236,16 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ setWindowIcon(iconPixels); } #endif - if(settings.visible){ - glfwShowWindow(windowP); - } if(settings.iconified){ iconify(true); } - if(requestedMode==OF_FULLSCREEN){ - setFullscreen(true); - } } - if(!windowP) { - ofLogError("ofAppGLFWWindow") << "couldn't create window"; - return; - } + + //don't try and show a window if its been requsted to be hidden + bWindowNeedsShowing = settings.visible; glfwSetWindowUserPointer(windowP,this); - windowMode = requestedMode; + windowMode = settings.windowMode; glfwGetWindowSize( windowP, &settings.width, &settings.height ); @@ -233,11 +259,10 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ //this lets us detect if the window is running in a retina mode if( framebufferW != windowW ){ pixelScreenCoordScale = framebufferW / windowW; - - //have to update the windowShape to account for retina coords - if( windowMode == OF_WINDOW ){ - setWindowShape(windowW, windowH); - } + + ofPoint position = getWindowPosition(); + setWindowShape(windowW, windowH); + setWindowPosition(position.x, position.y); } #ifndef TARGET_OPENGLES @@ -276,9 +301,6 @@ void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){ glfwSetWindowCloseCallback(windowP, exit_cb); glfwSetScrollCallback(windowP, scroll_cb); glfwSetDropCallback(windowP, drop_cb); - if (settings.isPositionSet()) { - setWindowPosition(settings.getPosition().x,settings.getPosition().y); - } } #ifdef TARGET_LINUX @@ -322,6 +344,12 @@ shared_ptr & ofAppGLFWWindow::renderer(){ //-------------------------------------------- void ofAppGLFWWindow::update(){ events().notifyUpdate(); + + //show the window right before the first draw call. + if( bWindowNeedsShowing && windowP ){ + glfwShowWindow(windowP); + bWindowNeedsShowing = false; + } } //-------------------------------------------- @@ -435,7 +463,9 @@ int ofAppGLFWWindow::getCurrentMonitor(){ glfwGetMonitorPos(monitors[iC], &xM, &yM); const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[iC]); ofRectangle monitorRect(xM, yM, desktopMode->width, desktopMode->height); - if (monitorRect.inside(xW, yW)){ + bool bPointMatch = xW >= monitorRect.getMinX() && yW >= monitorRect.getMinY() && xW < monitorRect.getMaxX() && yW < monitorRect.getMaxY(); + // if (monitorRect.inside(xW, yW)){ + if( bPointMatch ) { return iC; break; } @@ -455,7 +485,7 @@ ofPoint ofAppGLFWWindow::getScreenSize(){ if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){ return ofVec3f(desktopMode->width*pixelScreenCoordScale, desktopMode->height*pixelScreenCoordScale,0); }else{ - return ofPoint(0,0); //NOTE: shouldn't this be ofVec3f(desktopMode->height*pixelScreenCoordScale, desktopMode->width*pixelScreenCoordScale, 0); + return ofVec3f(desktopMode->height*pixelScreenCoordScale, desktopMode->width*pixelScreenCoordScale, 0); } }else{ return ofPoint(0,0); @@ -514,7 +544,15 @@ void ofAppGLFWWindow::setWindowPosition(int x, int y){ //------------------------------------------------------------ void ofAppGLFWWindow::setWindowShape(int w, int h){ - glfwSetWindowSize(windowP,w/pixelScreenCoordScale,h/pixelScreenCoordScale); + #ifdef TARGET_OSX + ofPoint pos = getWindowPosition(); + glfwSetWindowSize(windowP,w/pixelScreenCoordScale,h/pixelScreenCoordScale); + if( pos != getWindowPosition() ){ + setWindowPosition(pos.x, pos.y); + } + #else + glfwSetWindowSize(windowP,w/pixelScreenCoordScale,h/pixelScreenCoordScale); + #endif } //------------------------------------------------------------ @@ -562,7 +600,7 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ int monitorCount; GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); - if( bMultiWindowFullscreen && monitorCount > 1 ){ + if( settings.multiMonitorFullScreen && monitorCount > 1 ){ // find the monitors at the edges of the virtual desktop int minx=numeric_limits::max(); int miny=numeric_limits::max(); @@ -572,7 +610,9 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ int monitorLeft=0, monitorRight=0, monitorTop=0, monitorBottom=0; for(int i = 0; i < monitorCount; i++){ glfwGetMonitorPos(monitors[i],&x,&y); - glfwGetMonitorPhysicalSize(monitors[i],&w,&h); + auto videoMode = glfwGetVideoMode(monitors[i]); + w = videoMode->width; + h = videoMode->height; if(x 1 ){ + + // save window shape before going fullscreen + ofPoint pos = getWindowPosition(); + windowRect.x = pos.x; + windowRect.y = pos.y; + windowRect.width = windowW; + windowRect.height = windowH; + + if( settings.multiMonitorFullScreen && monitorCount > 1 ){ //calc the sum Rect of all the monitors for(int i = 0; i < monitorCount; i++){ @@ -674,7 +725,8 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ allScreensSpace = allScreensSpace.getUnion(screen); } //for OS X we need to set this first as the window size affects the window positon - setWindowShape(allScreensSpace.width, allScreensSpace.height); + //need to account for the pixel density factor when we're getting the values from glfw + setWindowShape(allScreensSpace.width*pixelScreenCoordScale, allScreensSpace.height*pixelScreenCoordScale); setWindowPosition(allScreensSpace.x, allScreensSpace.y); }else if (monitorCount > 1 && currentMonitor < monitorCount){ @@ -699,29 +751,37 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ setWindowShape(screenSize.x, screenSize.y); setWindowPosition(0,0); } + + // make sure to save current pos if not specified in settings + if( settings.isPositionSet() ) { + ofVec3f pos = getWindowPosition(); + settings.setPosition(ofVec2f(pos.x, pos.y)); + } //make sure the window is getting the mouse/key events [cocoaWindow makeFirstResponder:cocoaWindow.contentView]; }else if( windowMode == OF_WINDOW ){ - int nonFullScreenX = getWindowPosition().x; - int nonFullScreenY = getWindowPosition().y; - - int nonFullScreenW = getWindowSize().x; - int nonFullScreenH = getWindowSize().y; - + + // set window shape if started in fullscreen + if(windowRect.width == 0 && windowRect.height == 0) { + windowRect.x = getWindowPosition().x; + windowRect.y = getWindowPosition().y; + windowRect.width = getWindowSize().x; + windowRect.height = getWindowSize().y; + } [NSApp setPresentationOptions:NSApplicationPresentationDefault]; NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP); [cocoaWindow setStyleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask]; - setWindowShape(nonFullScreenW, nonFullScreenH); + setWindowShape(windowRect.width, windowRect.height); //---------------------------------------------------- // if we have recorded the screen posion, put it there // if not, better to let the system do it (and put it where it wants) if (ofGetFrameNum() > 0){ - setWindowPosition(nonFullScreenX,nonFullScreenY); + setWindowPosition(windowRect.x, windowRect.y); } //---------------------------------------------------- @@ -730,10 +790,12 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ } #elif defined(TARGET_WIN32) if( windowMode == OF_FULLSCREEN){ - int nonFullScreenX = getWindowPosition().x; - int nonFullScreenY = getWindowPosition().y; - int nonFullScreenW = getWindowSize().x; - int nonFullScreenH = getWindowSize().y; + // save window shape before going fullscreen + ofPoint pos = getWindowPosition(); + windowRect.x = pos.x; + windowRect.y = pos.y; + windowRect.width = windowW; + windowRect.height = windowH; //---------------------------------------------------- HWND hwnd = glfwGetWin32Window(windowP); @@ -744,11 +806,15 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ float fullscreenW = getScreenSize().x; float fullscreenH = getScreenSize().y; + + if( orientation == OF_ORIENTATION_90_LEFT || orientation == OF_ORIENTATION_90_RIGHT ){ + std::swap(fullscreenW, fullscreenH); + } int xpos = 0; int ypos = 0; - if( bMultiWindowFullscreen ){ + if( settings.multiMonitorFullScreen ){ int minX = 0; int maxX = 0; @@ -786,10 +852,13 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ SetWindowPos(hwnd, HWND_TOPMOST, xpos, ypos, fullscreenW, fullscreenH, SWP_SHOWWINDOW); }else if( windowMode == OF_WINDOW ){ - int nonFullScreenX = getWindowPosition().x; - int nonFullScreenY = getWindowPosition().y; - int nonFullScreenW = getWindowSize().x; - int nonFullScreenH = getWindowSize().y; + // set window shape if started in fullscreen + if(windowRect.width == 0 && windowRect.height == 0) { + windowRect.x = getWindowPosition().x; + windowRect.y = getWindowPosition().y; + windowRect.width = getWindowSize().x; + windowRect.height = getWindowSize().y; + } HWND hwnd = glfwGetWin32Window(windowP); @@ -803,8 +872,8 @@ void ofAppGLFWWindow::setFullscreen(bool fullscreen){ //not sure why this is - but if we don't do this the window shrinks by 4 pixels in x and y //should look for a better fix. - setWindowPosition(nonFullScreenX-2, nonFullScreenY-2); - setWindowShape(nonFullScreenW+4, nonFullScreenH+4); + setWindowPosition(windowRect.x-2, windowRect.y-2); + setWindowShape(windowRect.width+4, windowRect.height+4); } #endif } @@ -932,7 +1001,7 @@ void ofAppGLFWWindow::entry_cb(GLFWwindow *windowP_, int entered) { void ofAppGLFWWindow::scroll_cb(GLFWwindow* windowP_, double x, double y) { ofAppGLFWWindow * instance = setCurrent(windowP_); rotateMouseXY(instance->orientation, instance->getWidth(), instance->getHeight(), x, y); - instance->events().notifyMouseScrolled(x, y); + instance->events().notifyMouseScrolled(instance->events().getMouseX(), instance->events().getMouseY(), x, y); } //------------------------------------------------------------ @@ -1077,8 +1146,8 @@ void ofAppGLFWWindow::keyboard_cb(GLFWwindow* windowP_, int keycode, int scancod //------------------------------------------------------------ void ofAppGLFWWindow::resize_cb(GLFWwindow* windowP_,int w, int h) { ofAppGLFWWindow * instance = setCurrent(windowP_); - instance->windowW = w; - instance->windowH = h; + instance->windowW = w * instance->pixelScreenCoordScale; + instance->windowH = h * instance->pixelScreenCoordScale; instance->events().notifyWindowResized(w*instance->pixelScreenCoordScale, h*instance->pixelScreenCoordScale); instance->nFramesSinceWindowResized = 0; @@ -1117,6 +1186,7 @@ string ofAppGLFWWindow::getClipboardString() { //------------------------------------------------------------ void ofAppGLFWWindow::listVideoModes(){ + glfwInit(); int numModes; const GLFWvidmode * vidModes = glfwGetVideoModes(nullptr, &numModes ); for(int i=0; i shareContextWith; }; @@ -98,26 +57,16 @@ class ofAppGLFWWindow : public ofAppBaseGLWindow { ofAppGLFWWindow(); ~ofAppGLFWWindow(); + // Can't be copied, use shared_ptr + ofAppGLFWWindow(ofAppGLFWWindow & w) = delete; + ofAppGLFWWindow & operator=(ofAppGLFWWindow & w) = delete; + static void loop(){}; static bool doesLoop(){ return false; } static bool allowsMultiWindow(){ return true; } static bool needsPolling(){ return true; } static void pollEvents(){ glfwPollEvents(); } - // window settings, this functions can be called from main before calling ofSetupOpenGL - void setNumSamples(int samples); - void setDoubleBuffering(bool doubleBuff); - void setColorBits(int r, int g, int b); - void setAlphaBits(int a); - void setDepthBits(int depth); - void setStencilBits(int stencil); - void listVideoModes(); - bool isWindowIconified(); - bool isWindowActive(); - bool isWindowResizeable(); - void iconify(bool bIconify); - void setMultiDisplayFullscreen(bool bMultiFullscreen); //note this just enables the mode, you have to toggle fullscreen to activate it. - // this functions are only meant to be called from inside OF don't call them from your code using ofAppBaseWindow::setup; @@ -145,6 +94,7 @@ class ofAppGLFWWindow : public ofAppBaseGLWindow { GLFWwindow* getGLFWWindow(); void * getWindowContext(){return getGLFWWindow();} + ofGLFWWindowSettings getSettings(){ return settings; } ofVec3f getWindowSize(); ofVec3f getScreenSize(); @@ -174,6 +124,23 @@ class ofAppGLFWWindow : public ofAppBaseGLWindow { void makeCurrent(); + static void listVideoModes(); + static void listMonitors(); + bool isWindowIconified(); + bool isWindowActive(); + bool isWindowResizeable(); + void iconify(bool bIconify); + + // window settings, this functions can only be called from main before calling ofSetupOpenGL + // TODO: remove specialized version of ofSetupOpenGL when these go away + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setNumSamples(int samples)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setDoubleBuffering(bool doubleBuff)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setColorBits(int r, int g, int b)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setAlphaBits(int a)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setDepthBits(int depth)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setStencilBits(int stencil)); + OF_DEPRECATED_MSG("use ofGLFWWindowSettings to create the window instead", void setMultiDisplayFullscreen(bool bMultiFullscreen)); //note this just enables the mode, you have to toggle fullscreen to activate it. + #if defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) Display* getX11Display(); Window getX11Window(); @@ -200,10 +167,6 @@ class ofAppGLFWWindow : public ofAppBaseGLWindow { #endif private: - // private copy construction - ofAppGLFWWindow(ofAppGLFWWindow & w){}; - ofAppGLFWWindow & operator=(ofAppGLFWWindow & w){return w;}; - static ofAppGLFWWindow * setCurrent(GLFWwindow* windowP); static void mouse_cb(GLFWwindow* windowP_, int button, int state, int mods); static void motion_cb(GLFWwindow* windowP_, double x, double y); @@ -229,11 +192,13 @@ class ofAppGLFWWindow : public ofAppBaseGLWindow { bool bEnableSetupScreen; int windowW, windowH; + ofRectangle windowRect; + int buttonInUse; bool buttonPressed; int nFramesSinceWindowResized; - bool bMultiWindowFullscreen; + bool bWindowNeedsShowing; GLFWwindow* windowP; diff --git a/libs/openFrameworks/app/ofAppGlutWindow.cpp b/libs/openFrameworks/app/ofAppGlutWindow.cpp index 88ffc9cb141..62b677bc1ab 100644 --- a/libs/openFrameworks/app/ofAppGlutWindow.cpp +++ b/libs/openFrameworks/app/ofAppGlutWindow.cpp @@ -5,8 +5,13 @@ #include "ofGLRenderer.h" #ifdef TARGET_WIN32 - #define GLUT_BUILDING_LIB - #include "glut.h" + #if (_MSC_VER) + #define GLUT_BUILDING_LIB + #include "glut.h" + #else + #include + #include + #endif #endif #ifdef TARGET_OSX #include @@ -79,7 +84,6 @@ void HandleFiles(WPARAM wParam) // the current file being queried. int count = DragQueryFile(hDrop, 0xFFFFFFFF, szName, MAX_PATH); - #ifdef _MSC_VER // Here we go through all the files that were drag and dropped then display them for(int i = 0; i < count; i++) { @@ -101,23 +105,6 @@ void HandleFiles(WPARAM wParam) // Bring up a message box that displays the current file being processed //MessageBox(GetForegroundWindow(), szName, L"Current file received", MB_OK); } -#else - - HDROP hdrop = (HDROP)(wParam); - int index, length; - count = DragQueryFile(hdrop, 0xFFFFFFFF, nullptr, 0); - for (index=0; index 0) { - TCHAR* lpstr = new TCHAR[length+1]; - DragQueryFile(hdrop, index, lpstr, length+1); - string temp = lpstr; - info.files.push_back(temp); - delete[] lpstr; - } - } - - #endif // Finally, we destroy the HDROP handle so the extra memory // allocated by the application is released. @@ -338,6 +325,12 @@ void ofAppGlutWindow::setup(const ofGLWindowSettings & settings){ if (settings.isPositionSet()) { setWindowPosition(settings.getPosition().x,settings.getPosition().y); } + +#ifdef TARGET_OSX + // The osx implementation of glut changes the cwd, this restores it + // to wherever it was when the app was started + ofRestoreWorkingDirectoryToDefault(); +#endif } #ifdef TARGET_LINUX diff --git a/libs/openFrameworks/app/ofAppRunner.cpp b/libs/openFrameworks/app/ofAppRunner.cpp index d27a67fe1cb..f0ea9182320 100644 --- a/libs/openFrameworks/app/ofAppRunner.cpp +++ b/libs/openFrameworks/app/ofAppRunner.cpp @@ -19,9 +19,24 @@ #include "ofURLFileLoader.h" #include "ofMainLoop.h" +#if !defined( TARGET_OF_IOS ) & !defined(TARGET_ANDROID) & !defined(TARGET_EMSCRIPTEN) & !defined(TARGET_RASPBERRY_PI) + #include "ofAppGLFWWindow.h" + //special case so we preserve supplied settngs + //TODO: remove me when we remove the ofAppGLFWWindow setters. + //-------------------------------------- + void ofSetupOpenGL(shared_ptr windowPtr, int w, int h, ofWindowMode screenMode){ + ofInit(); + auto settings = windowPtr->getSettings(); + settings.width = w; + settings.height = h; + settings.windowMode = screenMode; + ofGetMainLoop()->addWindow(windowPtr); + windowPtr->setup(settings); + } +#endif // adding this for vc2010 compile: error C3861: 'closeQuicktime': identifier not found -#if defined(TARGET_OSX) +#if defined(OF_VIDEO_CAPTURE_QUICKTIME) || defined(OF_VIDEO_PLAYER_QUICKTIME) #include "ofQtUtils.h" #endif @@ -31,45 +46,46 @@ //-------------------------------------- -shared_ptr & mainLoop(){ - static shared_ptr * mainLoop(new shared_ptr(new ofMainLoop)); - return *mainLoop; -} +namespace{ + shared_ptr & mainLoop(){ + static shared_ptr * mainLoop(new shared_ptr(new ofMainLoop)); + return *mainLoop; + } + bool & initialized(){ + static bool * initialized = new bool(false); + return *initialized; + } -static bool & initialized(){ - static bool * initialized = new bool(false); - return *initialized; -} + #if defined(TARGET_LINUX) || defined(TARGET_OSX) + #include + #include + void ofSignalHandler(int signum){ + char* pSignalString = strsignal(signum); -void ofExitCallback(); -void ofURLFileLoaderShutdown(); + if(pSignalString){ + ofLogVerbose("ofSignalHandler") << pSignalString; + }else{ + ofLogVerbose("ofSignalHandler") << "Unknown: " << signum; + } -#if defined(TARGET_LINUX) || defined(TARGET_OSX) - #include - #include + signal(SIGTERM, nullptr); + signal(SIGQUIT, nullptr); + signal(SIGINT, nullptr); + signal(SIGHUP, nullptr); + signal(SIGABRT, nullptr); - static void ofSignalHandler(int signum){ + if(mainLoop()){ + mainLoop()->shouldClose(signum); + } + } + #endif +} - char* pSignalString = strsignal(signum); - if(pSignalString){ - ofLogVerbose("ofSignalHandler") << pSignalString; - }else{ - ofLogVerbose("ofSignalHandler") << "Unknown: " << signum; - } - signal(SIGTERM, nullptr); - signal(SIGQUIT, nullptr); - signal(SIGINT, nullptr); - signal(SIGHUP, nullptr); - signal(SIGABRT, nullptr); - - if(mainLoop()){ - mainLoop()->shouldClose(signum); - } - } -#endif +void ofExitCallback(); +void ofURLFileLoaderShutdown(); void ofInit(){ if(initialized()) return; @@ -93,6 +109,8 @@ void ofInit(){ signal(SIGABRT, &ofSignalHandler); // abort signal #endif + of::priv::initutils(); + #ifdef WIN32_HIGH_RES_TIMING timeBeginPeriod(1); // ! experimental, sets high res time // you need to call timeEndPeriod. @@ -104,19 +122,17 @@ void ofInit(){ // info here:http://www.geisswerks.com/ryan/FAQS/timing.html #endif - ofSeedRandom(); - ofResetElapsedTimeCounter(); - ofSetWorkingDirectoryToDefault(); - #ifdef TARGET_LINUX if(std::locale().name() == "C"){ try{ std::locale::global(std::locale("C.UTF-8")); }catch(...){ - ofLogWarning("ofInit") << "Couldn't set UTF-8 locale, string manipulation functions\n" - "won't work correctly for non ansi characters unless you specify a UTF-8 locale\n" - "manually using std::locale::global(std::locale(\"locale\"))\n" - "available locales can be queried with 'locale -a' in a terminal."; + if(ofToLower(std::locale("").name()).find("utf-8")==std::string::npos){ + ofLogWarning("ofInit") << "Couldn't set UTF-8 locale, string manipulation functions\n" + "won't work correctly for non ansi characters unless you specify a UTF-8 locale\n" + "manually using std::locale::global(std::locale(\"locale\"))\n" + "available locales can be queried with 'locale -a' in a terminal."; + } } } #endif @@ -230,6 +246,8 @@ void ofExitCallback(){ // every object should have ended by now and won't receive any // events + of::priv::endutils(); + initialized() = false; } diff --git a/libs/openFrameworks/app/ofAppRunner.h b/libs/openFrameworks/app/ofAppRunner.h index 7cc0b0b5ef2..47a0d30b61d 100644 --- a/libs/openFrameworks/app/ofAppRunner.h +++ b/libs/openFrameworks/app/ofAppRunner.h @@ -10,10 +10,12 @@ class ofAppBaseWindow; class ofAppBaseGLWindow; class ofAppBaseGLESWindow; +class ofAppGLFWWindow; class ofBaseApp; class ofBaseRenderer; class ofCoreEvents; + void ofInit(); void ofSetupOpenGL(int w, int h, ofWindowMode screenMode); // sets up the opengl context! shared_ptr ofCreateWindow(const ofWindowSettings & settings); // sets up the opengl context! @@ -31,6 +33,9 @@ void ofSetupOpenGL(shared_ptr windowPtr, int w, int h, ofWindowMode scre windowPtr->setup(settings); } +//special case so we preserve supplied settngs +//TODO: remove me when we remove the ofSetupOpenGL legacy approach. +void ofSetupOpenGL(shared_ptr windowPtr, int w, int h, ofWindowMode screenMode); template static void noopDeleter(Window*){} diff --git a/libs/openFrameworks/app/ofBaseApp.h b/libs/openFrameworks/app/ofBaseApp.h index 65ee996ea1a..17f549f46c4 100644 --- a/libs/openFrameworks/app/ofBaseApp.h +++ b/libs/openFrameworks/app/ofBaseApp.h @@ -38,7 +38,7 @@ class ofBaseApp : public ofBaseSoundInput, public ofBaseSoundOutput{ virtual void mouseReleased(int x, int y, int button ){} /// \brief Called on the active window when the mouse wheel is scrolled - virtual void mouseScrolled( float x, float y ){} + virtual void mouseScrolled(int x, int y, float scrollX, float scrollY ){} /// \brief Called on the active window when the mouse cursor enters the /// window area @@ -104,7 +104,7 @@ class ofBaseApp : public ofBaseSoundInput, public ofBaseSoundOutput{ mouseReleased(mouse.x,mouse.y,mouse.button); } virtual void mouseScrolled( ofMouseEventArgs & mouse ){ - mouseScrolled(mouse.x,mouse.y); + mouseScrolled(mouse.x, mouse.y, mouse.scrollX, mouse.scrollY); } virtual void mouseEntered( ofMouseEventArgs & mouse ){ mouseEntered(mouse.x,mouse.y); diff --git a/libs/openFrameworks/app/ofMainLoop.cpp b/libs/openFrameworks/app/ofMainLoop.cpp index af067d49f9c..808e372abc0 100644 --- a/libs/openFrameworks/app/ofMainLoop.cpp +++ b/libs/openFrameworks/app/ofMainLoop.cpp @@ -32,8 +32,6 @@ ofMainLoop::ofMainLoop() :bShouldClose(false) ,status(0) ,allowMultiWindow(true) -,windowLoop(nullptr) -,pollEvents(nullptr) ,escapeQuits(true){ } @@ -121,6 +119,7 @@ int ofMainLoop::loop(){ if(!windowLoop){ while(!bShouldClose && !windowsApps.empty()){ loopOnce(); + pollEvents(); } exit(); }else{ @@ -142,8 +141,11 @@ void ofMainLoop::loopOnce(){ i++; ///< continue to next window } } - if(pollEvents){ - pollEvents(); +} + +void ofMainLoop::pollEvents(){ + if(windowPollEvents){ + windowPollEvents(); } } diff --git a/libs/openFrameworks/app/ofMainLoop.h b/libs/openFrameworks/app/ofMainLoop.h index 2aa010b07f6..04454e6bd3f 100644 --- a/libs/openFrameworks/app/ofMainLoop.h +++ b/libs/openFrameworks/app/ofMainLoop.h @@ -18,7 +18,7 @@ class ofMainLoop { windowLoop = Window::loop; } if(Window::needsPolling()){ - pollEvents = Window::pollEvents; + windowPollEvents = Window::pollEvents; } if(!allowMultiWindow){ windowsApps.clear(); @@ -32,6 +32,7 @@ class ofMainLoop { void run(shared_ptr app); int loop(); void loopOnce(); + void pollEvents(); void exit(); ofCoreEvents & events(); void shouldClose(int status); @@ -49,7 +50,7 @@ class ofMainLoop { shared_ptr currentWindow; int status; bool allowMultiWindow; - void (*windowLoop)(void); - void (*pollEvents)(void); + std::function windowLoop; + std::function windowPollEvents; bool escapeQuits; }; diff --git a/libs/openFrameworks/app/ofWindowSettings.h b/libs/openFrameworks/app/ofWindowSettings.h index fdb68e8a38c..5dae799bb23 100644 --- a/libs/openFrameworks/app/ofWindowSettings.h +++ b/libs/openFrameworks/app/ofWindowSettings.h @@ -1,4 +1,10 @@ #pragma once +#include "ofConstants.h" +#include "ofVec2f.h" + +#include "ofConstants.h" +#include "ofVec2f.h" +#include "ofVec3f.h" class ofWindowSettings{ public: @@ -13,6 +19,7 @@ class ofWindowSettings{ int width; int height; + std::string title; ofWindowMode windowMode; void setPosition(const ofVec2f & position) { diff --git a/libs/openFrameworks/communication/ofArduino.cpp b/libs/openFrameworks/communication/ofArduino.cpp index e7e8036f13c..891ab43b579 100644 --- a/libs/openFrameworks/communication/ofArduino.cpp +++ b/libs/openFrameworks/communication/ofArduino.cpp @@ -7,10 +7,10 @@ * - fixed ability to use analog pins as digital inputs * * 3/5/11: - * - added servo support for firmata 2.2 and greater (should be + * - added servo support for firmata 2.2 and greater (should be * backwards compatible with Erik Sjodin's older firmata servo * implementation) - * + * * * Copyright 2007-2008 (c) Erik Sjodin, eriksjodin.net * @@ -46,12 +46,43 @@ // TODO throw event or exception if the serial port goes down... //--------------------------------------------------------------------------- ofArduino::ofArduino(){ - _portStatus=-1; - _waitForData=0; + _portStatus = -1; + _waitForData = 0; _analogHistoryLength = 2; _digitalHistoryLength = 2; _stringHistoryLength = 1; _sysExHistoryLength = 1; + _initialized = false; + _totalDigitalPins = 0; + _executeMultiByteCommand = 0x00; // 0x00 a pin mode (input), not a command in Firmata -> fail hard + _multiByteChannel = 0; + _firmwareVersionSum = 0; + for(unsigned char & e : _storedInputData){ + e = UCHAR_MAX; + } + for(int & e : _digitalPinMode){ + e = INT_MAX; + } + for(int & e : _digitalPinValue){ + e = INT_MAX; + } + for(int & e : _digitalPortValue){ + e = INT_MAX; + } + for(int & e : _digitalPortReporting){ + e = INT_MAX; + } + for(int & e : _digitalPinReporting){ + e = INT_MAX; + } + for(int & e : _analogPinReporting){ + e = INT_MAX; + } + for(int & e : _servoValue){ + e = INT_MAX; + } + connected = false; + connectTime = 0.0f; _majorProtocolVersion = 0; _minorProtocolVersion = 0; @@ -62,56 +93,58 @@ ofArduino::ofArduino(){ bUseDelay = true; } -ofArduino::~ofArduino() { +ofArduino::~ofArduino(){ _port.close(); } // initialize pins once we get the Firmata version back from the Arduino board // the version is sent automatically by the Arduino board on startup void ofArduino::initPins() const { - int firstAnalogPin; - - if (_initialized) return; // already initialized - - // support Firmata 2.3/Arduino 1.0 with backwards compatibility - // to previous protocol versions - if (_firmwareVersionSum >= FIRMWARE2_3) { - _totalDigitalPins = 20; - firstAnalogPin = 14; - } else { - _totalDigitalPins = ARD_TOTAL_DIGITAL_PINS; - firstAnalogPin = 16; - } - - // ports - for(int i=0; i= FIRMWARE2_3){ + _totalDigitalPins = 20; + firstAnalogPin = 14; + }else{ + _totalDigitalPins = ARD_TOTAL_DIGITAL_PINS; + firstAnalogPin = 16; + } + + // ports + for(int i = 0; i < ARD_TOTAL_PORTS; ++i){ + _digitalPortValue[i] = 0; _digitalPortReporting[i] = ARD_OFF; } - - // digital pins - for(int i=0; i OF_ARDUINO_DELAY_LENGTH) { + if(bUseDelay){ + if(_initialized || (ofGetElapsedTimef() - connectTime) > OF_ARDUINO_DELAY_LENGTH){ initPins(); connected = true; } @@ -131,28 +164,32 @@ bool ofArduino::isArduinoReady() const { return connected; } -void ofArduino::setUseDelay(bool bDelay){ +void ofArduino::setUseDelay(bool bDelay){ bUseDelay = bDelay; } void ofArduino::setDigitalHistoryLength(int length){ - if(length>=2) - _digitalHistoryLength=length; + if(length >= 2){ + _digitalHistoryLength = length; + } } void ofArduino::setAnalogHistoryLength(int length){ - if(length>=2) - _analogHistoryLength=length; + if(length >= 2){ + _analogHistoryLength = length; + } } void ofArduino::setSysExHistoryLength(int length){ - if(length>=1) - _sysExHistoryLength=length; + if(length >= 1){ + _sysExHistoryLength = length; + } } void ofArduino::setStringHistoryLength(int length){ - if(length>=1) - _stringHistoryLength=length; + if(length >= 1){ + _stringHistoryLength = length; + } } void ofArduino::disconnect(){ @@ -160,41 +197,44 @@ void ofArduino::disconnect(){ } void ofArduino::update(){ - vector bytesToProcess; + vector bytesToProcess; int bytesToRead = _port.available(); - if (bytesToRead>0) { + if(bytesToRead > 0){ bytesToProcess.resize(bytesToRead); _port.readBytes(&bytesToProcess[0], bytesToRead); - for (int i = 0; i < bytesToRead; i++) { + for(int i = 0; i < bytesToRead; i++){ processData((char)(bytesToProcess[i])); } } } int ofArduino::getAnalog(int pin) const { - if(_analogHistory[pin].size()>0) + if(_analogHistory[pin].size() > 0){ return _analogHistory[pin].front(); - else + }else{ return -1; + } } int ofArduino::getDigital(int pin) const { - if(_digitalPinMode[pin]==ARD_INPUT && _digitalHistory[pin].size()>0) + if(_digitalPinMode[pin] == ARD_INPUT && _digitalHistory[pin].size() > 0){ return _digitalHistory[pin].front(); - else if (_digitalPinMode[pin]==ARD_OUTPUT) + }else if(_digitalPinMode[pin] == ARD_OUTPUT){ return _digitalPinValue[pin]; - else + }else{ return -1; + } } int ofArduino::getPwm(int pin) const { - if(_digitalPinMode[pin]==ARD_PWM) + if(_digitalPinMode[pin] == ARD_PWM){ return _digitalPinValue[pin]; - else + }else{ return -1; + } } -vector ofArduino::getSysEx() const { +vector ofArduino::getSysEx() const { return _sysExHistory.front(); } @@ -207,65 +247,65 @@ int ofArduino::getDigitalPinMode(int pin) const { } void ofArduino::sendDigital(int pin, int value, bool force){ - if((_digitalPinMode[pin]==ARD_INPUT || _digitalPinMode[pin]==ARD_OUTPUT) && (_digitalPinValue[pin]!=value || force)){ + if((_digitalPinMode[pin] == ARD_INPUT || _digitalPinMode[pin] == ARD_OUTPUT) && (_digitalPinValue[pin] != value || force)){ _digitalPinValue[pin] = value; - int port=0; - int bit=0; - int port1Offset; - int port2Offset; - - // support Firmata 2.3/Arduino 1.0 with backwards compatibility - // to previous protocol versions - if (_firmwareVersionSum >= FIRMWARE2_3) { - port1Offset = 16; - port2Offset = 20; - } else { - port1Offset = 14; - port2Offset = 22; - } - - if(pin < 8 && pin >1){ - port=0; - bit = pin; + int port = 0; + int bit = 0; + int port1Offset; + int port2Offset; + + // support Firmata 2.3/Arduino 1.0 with backwards compatibility + // to previous protocol versions + if(_firmwareVersionSum >= FIRMWARE2_3){ + port1Offset = 16; + port2Offset = 20; + }else{ + port1Offset = 14; + port2Offset = 22; } - else if(pin>7 && pin 1){ + port = 0; + bit = pin; + }else if(pin > 7 && pin < port1Offset){ port = 1; - bit = pin-8; - } - else if(pin>15 && pin 15 && pin < port2Offset){ port = 2; - bit = pin-16; + bit = pin - 16; } // set the bit - if(value==1) + if(value == 1){ _digitalPortValue[port] |= (1 << bit); + } // clear the bit - if(value==0) + if(value == 0){ _digitalPortValue[port] &= ~(1 << bit); + } - sendByte(FIRMATA_DIGITAL_MESSAGE+port); + sendByte(FIRMATA_DIGITAL_MESSAGE + port); sendValueAsTwo7bitBytes(_digitalPortValue[port]); } } void ofArduino::sendPwm(int pin, int value, bool force){ - if(_digitalPinMode[pin]==ARD_PWM && (_digitalPinValue[pin]!=value || force)){ - sendByte(FIRMATA_ANALOG_MESSAGE+pin); + if(_digitalPinMode[pin] == ARD_PWM && (_digitalPinValue[pin] != value || force)){ + sendByte(FIRMATA_ANALOG_MESSAGE + pin); sendValueAsTwo7bitBytes(value); _digitalPinValue[pin] = value; } } -void ofArduino::sendSysEx(int command, vector data){ +void ofArduino::sendSysEx(int command, vector data){ sendByte(FIRMATA_START_SYSEX); sendByte(command); - vector::iterator it = data.begin(); - while( it != data.end() ) { + vector ::iterator it = data.begin(); + while(it != data.end()){ //sendByte(*it); // need to split data into 2 bytes before sending sendValueAsTwo7bitBytes(*it); it++; @@ -285,7 +325,7 @@ void ofArduino::sendString(string str){ sendByte(FIRMATA_START_SYSEX); sendByte(FIRMATA_SYSEX_FIRMATA_STRING); string::iterator it = str.begin(); - while( it != str.end() ) { + while(it != str.end()){ sendValueAsTwo7bitBytes(*it); it++; } @@ -308,23 +348,23 @@ void ofArduino::sendReset(){ void ofArduino::sendAnalogPinReporting(int pin, int mode){ - int firstAnalogPin; - // support Firmata 2.3/Arduino 1.0 with backwards compatibility - // to previous protocol versions - if (_firmwareVersionSum >= FIRMWARE2_3) { - firstAnalogPin = 14; - } else { - firstAnalogPin = 16; - } - - // if this analog pin is set as a digital input, disable digital pin reporting - if (_digitalPinReporting[pin + firstAnalogPin] == ARD_ON) { - sendDigitalPinReporting(pin + firstAnalogPin, ARD_OFF); - } - - _digitalPinMode[firstAnalogPin+pin]=ARD_ANALOG; - - sendByte(FIRMATA_REPORT_ANALOG+pin); + int firstAnalogPin; + // support Firmata 2.3/Arduino 1.0 with backwards compatibility + // to previous protocol versions + if(_firmwareVersionSum >= FIRMWARE2_3){ + firstAnalogPin = 14; + }else{ + firstAnalogPin = 16; + } + + // if this analog pin is set as a digital input, disable digital pin reporting + if(_digitalPinReporting[pin + firstAnalogPin] == ARD_ON){ + sendDigitalPinReporting(pin + firstAnalogPin, ARD_OFF); + } + + _digitalPinMode[firstAnalogPin + pin] = ARD_ANALOG; + + sendByte(FIRMATA_REPORT_ANALOG + pin); sendByte(mode); _analogPinReporting[pin] = mode; } @@ -333,13 +373,12 @@ void ofArduino::sendDigitalPinMode(int pin, int mode){ sendByte(FIRMATA_SET_PIN_MODE); sendByte(pin); sendByte(mode); - _digitalPinMode[pin]=mode; + _digitalPinMode[pin] = mode; // turn on or off reporting on the port - if(mode==ARD_INPUT){ + if(mode == ARD_INPUT){ sendDigitalPinReporting(pin, ARD_ON); - } - else { + }else{ sendDigitalPinReporting(pin, ARD_OFF); } } @@ -348,19 +387,19 @@ int ofArduino::getAnalogPinReporting(int pin) const { return _analogPinReporting[pin]; } -list* ofArduino::getAnalogHistory(int pin){ +list * ofArduino::getAnalogHistory(int pin){ return &_analogHistory[pin]; } -list* ofArduino::getDigitalHistory(int pin){ +list * ofArduino::getDigitalHistory(int pin){ return &_digitalHistory[pin]; } -list >* ofArduino::getSysExHistory(){ +list > * ofArduino::getSysExHistory(){ return &_sysExHistory; } -list* ofArduino::getStringHistory(){ +list * ofArduino::getStringHistory(){ return &_stringHistory; } @@ -397,55 +436,60 @@ void ofArduino::processData(unsigned char inputData){ //Logger::get("Application").information(msg); // we have command data - if(_waitForData>0 && inputData<128) { + if(_waitForData > 0 && inputData < 128){ _waitForData--; // collect the data _storedInputData[_waitForData] = inputData; // we have all data executeMultiByteCommand - if(_waitForData==0) { - switch (_executeMultiByteCommand) { - case FIRMATA_DIGITAL_MESSAGE: - processDigitalPort(_multiByteChannel, (_storedInputData[0] << 7) | _storedInputData[1]); - break; - case FIRMATA_REPORT_VERSION: // report version - _majorProtocolVersion = _storedInputData[1]; - _minorProtocolVersion = _storedInputData[0]; - ofNotifyEvent(EProtocolVersionReceived, _majorProtocolVersion, this); - break; - case FIRMATA_ANALOG_MESSAGE: - if(_analogHistory[_multiByteChannel].size()>0){ - int previous = _analogHistory[_multiByteChannel].front(); - - _analogHistory[_multiByteChannel].push_front((_storedInputData[0] << 7) | _storedInputData[1]); - if((int)_analogHistory[_multiByteChannel].size()>_analogHistoryLength) - _analogHistory[_multiByteChannel].pop_back(); - - // trigger an event if the pin has changed value - if(_analogHistory[_multiByteChannel].front()!=previous) - ofNotifyEvent(EAnalogPinChanged, _multiByteChannel, this); - }else{ - _analogHistory[_multiByteChannel].push_front((_storedInputData[0] << 7) | _storedInputData[1]); - if((int)_analogHistory[_multiByteChannel].size()>_analogHistoryLength) - _analogHistory[_multiByteChannel].pop_back(); - } - break; + if(_waitForData == 0){ + switch(_executeMultiByteCommand){ + case FIRMATA_DIGITAL_MESSAGE: + processDigitalPort(_multiByteChannel, (_storedInputData[0] << 7) | _storedInputData[1]); + break; + + case FIRMATA_REPORT_VERSION: // report version + _majorProtocolVersion = _storedInputData[1]; + _minorProtocolVersion = _storedInputData[0]; + ofNotifyEvent(EProtocolVersionReceived, _majorProtocolVersion, this); + break; + + case FIRMATA_ANALOG_MESSAGE: + if(_analogHistory[_multiByteChannel].size() > 0){ + int previous = _analogHistory[_multiByteChannel].front(); + + _analogHistory[_multiByteChannel].push_front((_storedInputData[0] << 7) | _storedInputData[1]); + if((int)_analogHistory[_multiByteChannel].size() > _analogHistoryLength){ + _analogHistory[_multiByteChannel].pop_back(); + } + + // trigger an event if the pin has changed value + if(_analogHistory[_multiByteChannel].front() != previous){ + ofNotifyEvent(EAnalogPinChanged, _multiByteChannel, this); + } + }else{ + _analogHistory[_multiByteChannel].push_front((_storedInputData[0] << 7) | _storedInputData[1]); + if((int)_analogHistory[_multiByteChannel].size() > _analogHistoryLength){ + _analogHistory[_multiByteChannel].pop_back(); + } + } + break; } } } // we have SysEx command data - else if(_waitForData<0){ - + else if(_waitForData < 0){ + // we have all sysex data - if(inputData==FIRMATA_END_SYSEX){ - _waitForData=0; + if(inputData == FIRMATA_END_SYSEX){ + _waitForData = 0; processSysExData(_sysExData); _sysExData.clear(); } // still have data, collect it - else { + else{ _sysExData.push_back((unsigned char)inputData); } } @@ -455,94 +499,98 @@ void ofArduino::processData(unsigned char inputData){ int command; // extract the command and channel info from a byte if it is less than 0xF0 - if(inputData < 0xF0) { - command = inputData & 0xF0; - _multiByteChannel = inputData & 0x0F; - } - else { - // commands in the 0xF* range don't use channel data - command = inputData; + if(inputData < 0xF0){ + command = inputData & 0xF0; + _multiByteChannel = inputData & 0x0F; + }else{ + // commands in the 0xF* range don't use channel data + command = inputData; } - switch (command) { - case FIRMATA_REPORT_VERSION: - case FIRMATA_DIGITAL_MESSAGE: - case FIRMATA_ANALOG_MESSAGE: - _waitForData = 2; // 2 bytes needed - _executeMultiByteCommand = command; - break; - case FIRMATA_START_SYSEX: - _sysExData.clear(); - _waitForData = -1; // n bytes needed, -1 is used to indicate sysex message - _executeMultiByteCommand = command; - break; + switch(command){ + case FIRMATA_REPORT_VERSION: + case FIRMATA_DIGITAL_MESSAGE: + case FIRMATA_ANALOG_MESSAGE: + _waitForData = 2; // 2 bytes needed + _executeMultiByteCommand = command; + break; + + case FIRMATA_START_SYSEX: + _sysExData.clear(); + _waitForData = -1; // n bytes needed, -1 is used to indicate sysex message + _executeMultiByteCommand = command; + break; } } } // sysex data is assumed to be 8-bit bytes split into two 7-bit bytes. -void ofArduino::processSysExData(vector data){ +void ofArduino::processSysExData(vector data){ string str; - vector::iterator it; + vector ::iterator it; unsigned char buffer; //int i = 1; // act on reserved sysEx messages (extended commands) or trigger SysEx event... - switch(data.front()) { //first byte in buffer is command - case FIRMATA_SYSEX_REPORT_FIRMWARE: - it = data.begin(); - it++; // skip the first byte, which is the firmware version command - _majorFirmwareVersion = *it; - it++; - _minorFirmwareVersion = *it; - it++; - - while( it != data.end() ) { - buffer = *it; - it++; - buffer += *it << 7; - it++; - str+=buffer; - } - _firmwareName = str; - - _firmwareVersionSum = _majorFirmwareVersion * 10 + _minorFirmwareVersion; - ofNotifyEvent(EFirmwareVersionReceived, _majorFirmwareVersion, this); - - // trigger the initialization event - if (!_initialized) { - initPins(); - ofNotifyEvent(EInitialized, _majorFirmwareVersion, this); - - } - - break; - case FIRMATA_SYSEX_FIRMATA_STRING: - it = data.begin(); - it++; // skip the first byte, which is the string command - while( it != data.end() ) { - buffer = *it; - it++; - buffer += *it << 7; - it++; - str+=buffer; - } - - _stringHistory.push_front(str); - if((int)_stringHistory.size()>_stringHistoryLength) - _stringHistory.pop_back(); - - ofNotifyEvent(EStringReceived, str, this); - break; - default: // the message isn't in Firmatas extended command set - _sysExHistory.push_front(data); - if((int)_sysExHistory.size()>_sysExHistoryLength) - _sysExHistory.pop_back(); - ofNotifyEvent(ESysExReceived, data, this); - break; + switch(data.front()){ //first byte in buffer is command + case FIRMATA_SYSEX_REPORT_FIRMWARE: + it = data.begin(); + it++; // skip the first byte, which is the firmware version command + _majorFirmwareVersion = *it; + it++; + _minorFirmwareVersion = *it; + it++; + + while(it != data.end()){ + buffer = *it; + it++; + buffer += *it << 7; + it++; + str += buffer; + } + _firmwareName = str; + + _firmwareVersionSum = _majorFirmwareVersion * 10 + _minorFirmwareVersion; + ofNotifyEvent(EFirmwareVersionReceived, _majorFirmwareVersion, this); + + // trigger the initialization event + if(!_initialized){ + initPins(); + ofNotifyEvent(EInitialized, _majorFirmwareVersion, this); + + } + + break; + + case FIRMATA_SYSEX_FIRMATA_STRING: + it = data.begin(); + it++; // skip the first byte, which is the string command + while(it != data.end()){ + buffer = *it; + it++; + buffer += *it << 7; + it++; + str += buffer; + } + + _stringHistory.push_front(str); + if((int)_stringHistory.size() > _stringHistoryLength){ + _stringHistory.pop_back(); + } + + ofNotifyEvent(EStringReceived, str, this); + break; + + default: // the message isn't in Firmatas extended command set + _sysExHistory.push_front(data); + if((int)_sysExHistory.size() > _sysExHistoryLength){ + _sysExHistory.pop_back(); + } + ofNotifyEvent(ESysExReceived, data, this); + break; } } @@ -553,83 +601,91 @@ void ofArduino::processDigitalPort(int port, unsigned char value){ int previous; int i; int pin; - int port1Pins; - int port2Pins; - - // support Firmata 2.3/Arduino 1.0 with backwards compatibility to previous protocol versions - if (_firmwareVersionSum >= FIRMWARE2_3) { - port1Pins = 8; - port2Pins = 4; - } else { - port1Pins = 6; - port2Pins = 6; - } - - switch(port) { - case 0: // pins 2-7 (0,1 are ignored as serial RX/TX) - for(i=2; i<8; ++i) { - pin = i; - previous = -1; - if(_digitalPinMode[pin]==ARD_INPUT){ - if (_digitalHistory[pin].size() > 0) - previous = _digitalHistory[pin].front(); - - mask = 1 << i; - _digitalHistory[pin].push_front((value & mask)>>i); - - if((int)_digitalHistory[pin].size()>_digitalHistoryLength) - _digitalHistory[pin].pop_back(); - - // trigger an event if the pin has changed value - if(_digitalHistory[pin].front()!=previous){ - ofNotifyEvent(EDigitalPinChanged, pin, this); - } - } - } - break; - case 1: // pins 8-13 (in Firmata 2.3/Arduino 1.0, pins 14 and 15 are analog 0 and 1) - for(i=0; i 0) - previous = _digitalHistory[pin].front(); - - mask = 1 << i; - _digitalHistory[pin].push_front((value & mask)>>i); - - if((int)_digitalHistory[pin].size()>_digitalHistoryLength) - _digitalHistory[pin].pop_back(); - - // trigger an event if the pin has changed value - if(_digitalHistory[pin].front()!=previous){ - ofNotifyEvent(EDigitalPinChanged, pin, this); - } - } - } - break; - case 2: // analog pins used as digital pins 16-21 (in Firmata 2.3/Arduino 1.0, digital pins 14 - 19) - for(i=0; i 0) - previous = _digitalHistory[pin].front(); - - mask = 1 << i; - _digitalHistory[pin].push_front((value & mask)>>i); - - if((int)_digitalHistory[pin].size()>_digitalHistoryLength) - _digitalHistory[pin].pop_back(); - - // trigger an event if the pin has changed value - if(_digitalHistory[pin].front()!=previous){ - ofNotifyEvent(EDigitalPinChanged, pin, this); - } - } - } - break; + int port1Pins; + int port2Pins; + + // support Firmata 2.3/Arduino 1.0 with backwards compatibility to previous protocol versions + if(_firmwareVersionSum >= FIRMWARE2_3){ + port1Pins = 8; + port2Pins = 4; + }else{ + port1Pins = 6; + port2Pins = 6; + } + + switch(port){ + case 0: // pins 2-7 (0,1 are ignored as serial RX/TX) + for(i = 2; i < 8; ++i){ + pin = i; + previous = -1; + if(_digitalPinMode[pin] == ARD_INPUT){ + if(_digitalHistory[pin].size() > 0){ + previous = _digitalHistory[pin].front(); + } + + mask = 1 << i; + _digitalHistory[pin].push_front((value & mask) >> i); + + if((int)_digitalHistory[pin].size() > _digitalHistoryLength){ + _digitalHistory[pin].pop_back(); + } + + // trigger an event if the pin has changed value + if(_digitalHistory[pin].front() != previous){ + ofNotifyEvent(EDigitalPinChanged, pin, this); + } + } + } + break; + + case 1: // pins 8-13 (in Firmata 2.3/Arduino 1.0, pins 14 and 15 are analog 0 and 1) + for(i = 0; i < port1Pins; ++i){ + pin = i + 8; + previous = -1; + if(_digitalPinMode[pin] == ARD_INPUT){ + if(_digitalHistory[pin].size() > 0){ + previous = _digitalHistory[pin].front(); + } + + mask = 1 << i; + _digitalHistory[pin].push_front((value & mask) >> i); + + if((int)_digitalHistory[pin].size() > _digitalHistoryLength){ + _digitalHistory[pin].pop_back(); + } + + // trigger an event if the pin has changed value + if(_digitalHistory[pin].front() != previous){ + ofNotifyEvent(EDigitalPinChanged, pin, this); + } + } + } + break; + + case 2: // analog pins used as digital pins 16-21 (in Firmata 2.3/Arduino 1.0, digital pins 14 - 19) + for(i = 0; i < port2Pins; ++i){ + //pin = i+analogOffset; + pin = i + 16; + previous = -1; + if(_digitalPinMode[pin] == ARD_INPUT){ + if(_digitalHistory[pin].size() > 0){ + previous = _digitalHistory[pin].front(); + } + + mask = 1 << i; + _digitalHistory[pin].push_front((value & mask) >> i); + + if((int)_digitalHistory[pin].size() > _digitalHistoryLength){ + _digitalHistory[pin].pop_back(); + } + + // trigger an event if the pin has changed value + if(_digitalHistory[pin].front() != previous){ + ofNotifyEvent(EDigitalPinChanged, pin, this); + } + } + } + break; } } @@ -639,84 +695,92 @@ void ofArduino::processDigitalPort(int port, unsigned char value){ // all analog reporting will be turned off if this is set to ARD_ON void ofArduino::sendDigitalPortReporting(int port, int mode){ - sendByte(FIRMATA_REPORT_DIGITAL+port); + sendByte(FIRMATA_REPORT_DIGITAL + port); sendByte(mode); _digitalPortReporting[port] = mode; - int offset; - - if (_firmwareVersionSum >= FIRMWARE2_3) { - offset = 2; - } else { - offset = 0; - } - - // for Firmata 2.3 and higher: - if(port==1 && mode==ARD_ON) { - for (int i=0; i<2; i++) { - _analogPinReporting[i] = ARD_OFF; - } - } - - // for Firmata 2.3 and all prior Firmata protocol versions: - if(port==2 && mode==ARD_ON){ // if reporting is turned on on port 2 then ofArduino on the Arduino disables all analog reporting - - for (int i=offset; i= FIRMWARE2_3){ + offset = 2; + }else{ + offset = 0; + } + + // for Firmata 2.3 and higher: + if(port == 1 && mode == ARD_ON){ + for(int i = 0; i < 2; i++){ + _analogPinReporting[i] = ARD_OFF; + } + } + + // for Firmata 2.3 and all prior Firmata protocol versions: + if(port == 2 && mode == ARD_ON){ // if reporting is turned on on port 2 then ofArduino on the Arduino disables all analog reporting + + for(int i = offset; i < ARD_TOTAL_ANALOG_PINS; i++){ + _analogPinReporting[i] = ARD_OFF; } } } void ofArduino::sendDigitalPinReporting(int pin, int mode){ _digitalPinReporting[pin] = mode; - int port1Offset; - int port2Offset; - - // Firmata backwards compatibility mess - if (_firmwareVersionSum >= FIRMWARE2_3) { - port1Offset = 15; - port2Offset = 19; - } else { - port1Offset = 13; - port2Offset = 21; - } - - if(mode==ARD_ON){ // enable reporting for the port - if(pin<=7 && pin>=2) - sendDigitalPortReporting(0, ARD_ON); - // Firmata backwards compatibility mess - if(pin<=port1Offset && pin>=8) - sendDigitalPortReporting(1, ARD_ON); - if(pin<=port2Offset && pin>=16) - sendDigitalPortReporting(2, ARD_ON); + int port1Offset; + int port2Offset; + + // Firmata backwards compatibility mess + if(_firmwareVersionSum >= FIRMWARE2_3){ + port1Offset = 15; + port2Offset = 19; + }else{ + port1Offset = 13; + port2Offset = 21; } - else if(mode==ARD_OFF){ + + if(mode == ARD_ON){ // enable reporting for the port + if(pin <= 7 && pin >= 2){ + sendDigitalPortReporting(0, ARD_ON); + } + // Firmata backwards compatibility mess + if(pin <= port1Offset && pin >= 8){ + sendDigitalPortReporting(1, ARD_ON); + } + if(pin <= port2Offset && pin >= 16){ + sendDigitalPortReporting(2, ARD_ON); + } + }else if(mode == ARD_OFF){ int i; - bool send=true; - if(pin<=7 && pin>=2){ // check if all pins on the port are off, if so set port reporting to off.. - for(i=2; i<8; ++i) { - if(_digitalPinReporting[i]==ARD_ON) - send=false; + bool send = true; + if(pin <= 7 && pin >= 2){ // check if all pins on the port are off, if so set port reporting to off.. + for(i = 2; i < 8; ++i){ + if(_digitalPinReporting[i] == ARD_ON){ + send = false; + } } - if(send) + if(send){ sendDigitalPortReporting(0, ARD_OFF); + } + } + // Firmata backwards compatibility mess + if(pin <= port1Offset && pin >= 8){ + for(i = 8; i <= port1Offset; ++i){ + if(_digitalPinReporting[i] == ARD_ON){ + send = false; + } + } + if(send){ + sendDigitalPortReporting(1, ARD_OFF); + } + } + if(pin <= port2Offset && pin >= 16){ + for(i = 16; i <= port2Offset; ++i){ + if(_digitalPinReporting[i] == ARD_ON){ + send = false; + } + } + if(send){ + sendDigitalPortReporting(2, ARD_OFF); + } } - // Firmata backwards compatibility mess - if(pin<=port1Offset && pin>=8){ - for(i=8; i<=port1Offset; ++i) { - if(_digitalPinReporting[i]==ARD_ON) - send=false; - } - if(send) - sendDigitalPortReporting(1, ARD_OFF); - } - if(pin<=port2Offset && pin>=16){ - for(i=16; i<=port2Offset; ++i) { - if(_digitalPinReporting[i]==ARD_ON) - send=false; - } - if(send) - sendDigitalPortReporting(2, ARD_OFF); - } } } @@ -729,76 +793,76 @@ void ofArduino::sendByte(unsigned char byte){ // in Firmata (and MIDI) data bytes are 7-bits. The 8th bit serves as a flag to mark a byte as either command or data. // therefore you need two data bytes to send 8-bits (a char). -void ofArduino::sendValueAsTwo7bitBytes(int value) -{ +void ofArduino::sendValueAsTwo7bitBytes(int value){ sendByte(value & 127); // LSB sendByte(value >> 7 & 127); // MSB } // SysEx data is sent as 8-bit bytes split into two 7-bit bytes, this function merges two 7-bit bytes back into one 8-bit byte. int ofArduino::getValueFromTwo7bitBytes(unsigned char lsb, unsigned char msb){ - return (msb << 7) | lsb; + return (msb << 7) | lsb; } void ofArduino::sendServo(int pin, int value, bool force){ // for firmata v2.2 and greater - if (_firmwareVersionSum >= FIRMWARE2_2) { - if(_digitalPinMode[pin]==ARD_SERVO && (_digitalPinValue[pin]!=value || force)){ - sendByte(FIRMATA_ANALOG_MESSAGE+pin); + if(_firmwareVersionSum >= FIRMWARE2_2){ + if(_digitalPinMode[pin] == ARD_SERVO && (_digitalPinValue[pin] != value || force)){ + sendByte(FIRMATA_ANALOG_MESSAGE + pin); sendValueAsTwo7bitBytes(value); _digitalPinValue[pin] = value; } - } + } // for versions prior to 2.2 - else { - if(_digitalPinMode[pin]==ARD_SERVO && (_servoValue[pin]!=value || force)){ + else{ + if(_digitalPinMode[pin] == ARD_SERVO && (_servoValue[pin] != value || force)){ sendByte(FIRMATA_START_SYSEX); sendByte(SYSEX_SERVO_WRITE); sendByte(pin); sendValueAsTwo7bitBytes(value); sendByte(FIRMATA_END_SYSEX); - _servoValue[pin]=value; - } + _servoValue[pin] = value; + } } } // angle parameter is no longer supported. keeping for backwards compatibility -void ofArduino::sendServoAttach(int pin, int minPulse, int maxPulse, int angle) { +void ofArduino::sendServoAttach(int pin, int minPulse, int maxPulse, int angle){ sendByte(FIRMATA_START_SYSEX); // for firmata v2.2 and greater - if (_firmwareVersionSum >= FIRMWARE2_2) { + if(_firmwareVersionSum >= FIRMWARE2_2){ sendByte(FIRMATA_SYSEX_SERVO_CONFIG); - } + } // for versions prior to 2.2 - else { + else{ sendByte(SYSEX_SERVO_ATTACH); } sendByte(pin); sendValueAsTwo7bitBytes(minPulse); sendValueAsTwo7bitBytes(maxPulse); sendByte(FIRMATA_END_SYSEX); - _digitalPinMode[pin]=ARD_SERVO; + _digitalPinMode[pin] = ARD_SERVO; } // sendServoDetach depricated as of Firmata 2.2 -void ofArduino::sendServoDetach(int pin) { +void ofArduino::sendServoDetach(int pin){ sendByte(FIRMATA_START_SYSEX); sendByte(SYSEX_SERVO_DETACH); sendByte(pin); sendByte(FIRMATA_END_SYSEX); - _digitalPinMode[pin]=ARD_OUTPUT; + _digitalPinMode[pin] = ARD_OUTPUT; } int ofArduino::getServo(int pin) const { - if(_digitalPinMode[pin]==ARD_SERVO) + if(_digitalPinMode[pin] == ARD_SERVO){ // for firmata v2.2 and greater - if (_firmwareVersionSum >= FIRMWARE2_2) { + if(_firmwareVersionSum >= FIRMWARE2_2){ return _digitalPinValue[pin]; - } + } // for versions prior to 2.2 - else { + else{ return _servoValue[pin]; - } - else + } + }else{ return -1; + } } diff --git a/libs/openFrameworks/communication/ofArduino.h b/libs/openFrameworks/communication/ofArduino.h index fc1036feadf..ef67907baab 100644 --- a/libs/openFrameworks/communication/ofArduino.h +++ b/libs/openFrameworks/communication/ofArduino.h @@ -25,9 +25,7 @@ #pragma once #include -#include -#include -#include +#include "ofConstants.h" #include "ofEvents.h" @@ -39,107 +37,107 @@ * software can test whether it will be compatible with the currently installed firmware. */ -#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes -#define FIRMATA_MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages +#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes +#define FIRMATA_MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages // message command bytes (128-255/0x80-0xFF) -#define FIRMATA_DIGITAL_MESSAGE 0x90 // send data for a digital pin -#define FIRMATA_ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) -#define FIRMATA_REPORT_ANALOG 0xC0 // enable analog input by pin # -#define FIRMATA_REPORT_DIGITAL 0xD0 // enable digital input by port pair +#define FIRMATA_DIGITAL_MESSAGE 0x90 // send data for a digital pin +#define FIRMATA_ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) +#define FIRMATA_REPORT_ANALOG 0xC0 // enable analog input by pin # +#define FIRMATA_REPORT_DIGITAL 0xD0 // enable digital input by port pair // #define FIRMATA_SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc // -#define FIRMATA_REPORT_VERSION 0xF9 // report protocol version +#define FIRMATA_REPORT_VERSION 0xF9 // report protocol version #define FIRMATA_SYSTEM_RESET 0xFF // reset from MIDI // -#define FIRMATA_START_SYSEX 0xF0 // start a MIDI Sysex message -#define FIRMATA_END_SYSEX 0xF7 // end a MIDI Sysex message +#define FIRMATA_START_SYSEX 0xF0 // start a MIDI Sysex message +#define FIRMATA_END_SYSEX 0xF7 // end a MIDI Sysex message // pin modes -#define FIRMATA_INPUT 0x00 -#define FIRMATA_OUTPUT 0x01 -#define FIRMATA_ANALOG 0x02 // analog pin in analogInput mode -#define FIRMATA_PWM 0x03 // digital pin in PWM output mode -#define FIRMATA_SERVO 0x04 // digital pin in Servo output mode -#define SHIFT 0x05 // shiftIn/shiftOut mode -#define I2C 0x06 // pin included in I2C setup -#define TOTAL_PIN_MODES 7 +#define FIRMATA_INPUT 0x00 +#define FIRMATA_OUTPUT 0x01 +#define FIRMATA_ANALOG 0x02 // analog pin in analogInput mode +#define FIRMATA_PWM 0x03 // digital pin in PWM output mode +#define FIRMATA_SERVO 0x04 // digital pin in Servo output mode +#define SHIFT 0x05 // shiftIn/shiftOut mode +#define I2C 0x06 // pin included in I2C setup +#define TOTAL_PIN_MODES 7 // extended command set using SysEx (0-127/0x00-0x7F) /* 0x00-0x0F reserved for custom commands */ -#define FIRMATA_SYSEX_SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define FIRMATA_SYSEX_FIRMATA_STRING 0x71 // a string message with 14-bits per char -#define SHIFT_DATA 0x75 // a bitstram to/from a shift register -#define I2C_REQUEST 0x76 // send an I2C read/write request -#define I2C_REPLY 0x77 // a reply to an I2C request -#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins -#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin -#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value -#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value -#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins -#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution -#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers -#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info -#define FIRMATA_SYSEX_REPORT_FIRMWARE 0x79 // report name and version of the firmware -#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop -#define FIRMATA_SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages -#define FIRMATA_SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages +#define FIRMATA_SYSEX_SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq +#define FIRMATA_SYSEX_FIRMATA_STRING 0x71 // a string message with 14-bits per char +#define SHIFT_DATA 0x75 // a bitstram to/from a shift register +#define I2C_REQUEST 0x76 // send an I2C read/write request +#define I2C_REPLY 0x77 // a reply to an I2C request +#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins +#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin +#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value +#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value +#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins +#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution +#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers +#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info +#define FIRMATA_SYSEX_REPORT_FIRMWARE 0x79 // report name and version of the firmware +#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop +#define FIRMATA_SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages +#define FIRMATA_SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages // ---- arduino constants (for Arduino NG and Diecimila) // board settings -#define ARD_TOTAL_DIGITAL_PINS 22 // total number of pins currently supported -#define ARD_TOTAL_ANALOG_PINS 6 -#define ARD_TOTAL_PORTS 3 // total number of ports for the board +#define ARD_TOTAL_DIGITAL_PINS 22 // total number of pins currently supported +#define ARD_TOTAL_ANALOG_PINS 6 +#define ARD_TOTAL_PORTS 3 // total number of ports for the board // pin modes -#define ARD_INPUT 0x00 -#define ARD_OUTPUT 0x01 -#define ARD_ANALOG 0x02 // analog pin in analogInput mode -#define ARD_PWM 0x03 // digital pin in PWM output mode -#define ARD_SERVO 0x04 // digital pin in Servo output mode +#define ARD_INPUT 0x00 +#define ARD_OUTPUT 0x01 +#define ARD_ANALOG 0x02 // analog pin in analogInput mode +#define ARD_PWM 0x03 // digital pin in PWM output mode +#define ARD_SERVO 0x04 // digital pin in Servo output mode #define ARD_HIGH 1 -#define ARD_LOW 0 -#define ARD_ON 1 -#define ARD_OFF 0 +#define ARD_LOW 0 +#define ARD_ON 1 +#define ARD_OFF 0 /* #if defined(__AVR_ATmega168__) // Arduino NG and Diecimila - #define ARD_TOTAL_ANALOG_PINS 8 - #define ARD_TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog - #define ARD_TOTAL_PORTS 3 // total number of ports for the board - #define ARD_ANALOG_PORT 2 // port# of analog used as digital + #define ARD_TOTAL_ANALOG_PINS 8 + #define ARD_TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog + #define ARD_TOTAL_PORTS 3 // total number of ports for the board + #define ARD_ANALOG_PORT 2 // port# of analog used as digital #elif defined(__AVR_ATmega8__) // old Arduinos - #define ARD_TOTAL_ANALOG_PINS 6 - #define ARD_TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog - #define ARD_TOTAL_PORTS 3 // total number of ports for the board - #define ARD_ANALOG_PORT 2 // port# of analog used as digital + #define ARD_TOTAL_ANALOG_PINS 6 + #define ARD_TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog + #define ARD_TOTAL_PORTS 3 // total number of ports for the board + #define ARD_ANALOG_PORT 2 // port# of analog used as digital #elif defined(__AVR_ATmega128__)// Wiring - #define ARD_TOTAL_ANALOG_PINS 8 - #define ARD_TOTAL_DIGITAL_PINS 43 - #define ARD_TOTAL_PORTS 5 // total number of ports for the board - #define ARD_ANALOG_PORT 2 // port# of analog used as digital + #define ARD_TOTAL_ANALOG_PINS 8 + #define ARD_TOTAL_DIGITAL_PINS 43 + #define ARD_TOTAL_PORTS 5 // total number of ports for the board + #define ARD_ANALOG_PORT 2 // port# of analog used as digital #else // anything else - #define ARD_TOTAL_ANALOG_PINS 6 - #define ARD_TOTAL_DIGITAL_PINS 14 - #define ARD_TOTAL_PORTS 3 // total number of ports for the board - #define ARD_ANALOG_PORT 2 // port# of analog used as digital + #define ARD_TOTAL_ANALOG_PINS 6 + #define ARD_TOTAL_DIGITAL_PINS 14 + #define ARD_TOTAL_PORTS 3 // total number of ports for the board + #define ARD_ANALOG_PORT 2 // port# of analog used as digital #endif */ // DEPRECATED as of firmata v2.2 -#define SYSEX_SERVO_ATTACH 0x00 -#define SYSEX_SERVO_DETACH 0x01 -#define SYSEX_SERVO_WRITE 0x02 +#define SYSEX_SERVO_ATTACH 0x00 +#define SYSEX_SERVO_DETACH 0x01 +#define SYSEX_SERVO_WRITE 0x02 -#define OF_ARDUINO_DELAY_LENGTH 4.0 +#define OF_ARDUINO_DELAY_LENGTH 4.0 -#define FIRMWARE2_2 22 -#define FIRMWARE2_3 23 +#define FIRMWARE2_2 22 +#define FIRMWARE2_3 23 /// \brief This is a way to control an Arduino that has had the firmata library /// loaded onto it, from OF. /// -/// To load firmata onto your Arduino, run the Arduino IDE, open the Examples > +/// To load firmata onto your Arduino, run the Arduino IDE, open the Examples > /// Firmata > StandardFirmata sketch, and upload it to the Arduino board. /// /// Once the ofArduino instance returns true from isArduinoReady() you can set @@ -147,348 +145,348 @@ /// /// This sets pin 9 to input so that it can read a button press /// ~~~~{.cpp} -/// sendDigitalPinMode(9, ARD_INPUT) +/// sendDigitalPinMode(9, ARD_INPUT) /// ~~~~ /// /// This sets pin 9 to be a PWM out pin. Note that this only works on pins /// that are PWM enabled. /// ~~~~{.cpp} -/// sendDigitalPinMode(9, ARD_PWM) +/// sendDigitalPinMode(9, ARD_PWM) /// ~~~~ -class ofArduino{ - -public: - /// \name Constructor and Destructor - /// \{ - - ofArduino(); - - virtual ~ofArduino(); - - /// \} - /// \name Connect - /// \{ - - /// \brief Opens a serial port connection to the arduino - /// \param device The name of the device. - /// You can get the name from the Arduino IDE - /// \param baud The baud rate the connection uses - bool connect(const std::string& device, int baud = 57600); - - /// \brief Returns true if a succesfull connection has been established - /// and the Arduino has reported a firmware - bool isInitialized() const; - - bool isArduinoReady() const; - - /// \brief Closes the serial port connection. - /// Does not turn the Arduino off. - void disconnect(); - - /// \} - /// \name Update - /// \{ - - /// \brief Polls data from the serial port, this has to be called periodically - void update(); - - /// \} - /// \name Setup - /// \{ - - /// \brief Setting a pins mode to ARD_INPUT turns on reporting for the port the pin is on - /// \param pin Pin on arduino (2-13) - /// \param mode `ARD_INPUT`, `ARD_OUTPUT`, `ARD_PWM` - /// \note Analog pins 0-5 can be used as digitial pins 16-21 but if the - /// mode of _one_ of these pins is set to `ARD_INPUT` then _all_ analog pin - /// reporting will be turned off - void sendDigitalPinMode(int pin, int mode); - - void sendAnalogPinReporting(int pin, int mode); - // pin: 0-5 - // mode: ARD_ON or ARD_OFF - // Note: analog pins 0-5 can be used as digitial pins 16-21 but if reporting for _one_ analog pin is enabled then reporting for _all_ of digital pin 16-21 will be turned off - - void setUseDelay(bool bDelay); - - void setDigitalHistoryLength(int length); - void setAnalogHistoryLength(int length); - void setStringHistoryLength(int length); - void setSysExHistoryLength(int nSysEx); - - /// \} - /// \name Senders - /// \{ - - void sendDigital(int pin, int value, bool force = false); - // pin: 2-13 - // value: ARD_LOW or ARD_HIGH - // the pins mode has to be set to ARD_OUTPUT or ARD_INPUT (in the latter mode pull-up resistors are enabled/disabled) - // Note: pin 16-21 can also be used if analog inputs 0-5 are used as digital pins - - - void sendPwm(int pin, int value, bool force = false); - - void sendSysEx(int command, vector data); - - /// \brief Send a string to the Arduino - /// \note Firmata can not handle strings longer than 12 characters. - void sendString(string str); - - void sendProtocolVersionRequest(); - - void sendFirmwareVersionRequest(); - - /// \brief This will cause your Arduino to reset and boot into the program again. - void sendReset(); - - /// \brief Sends the `FIRMATA_START_SYSEX` command - void sendSysExBegin(); - - /// \brief Sends the `FIRMATA_END_SYSEX` command - void sendSysExEnd(); - - /// \brief Sends a byte without wrapping it in a firmata message. - /// - /// Data has to be in the 0-127 range. Values > 127 will be interpreted as - /// commands. - void sendByte(unsigned char byte); - - /// \brief Send value as two 7 bit bytes. - /// - /// Sends a value as two 7-bit bytes without wrapping it in a firmata - /// message. Values in the range 0 - 16384 will be sent as two bytes - /// within the 0-127 data range. - /// - /// \param value The value to send. - void sendValueAsTwo7bitBytes(int value); - - /// \} - /// \name Getters - /// \{ - - /// \brief Returns the last set PWM value (0-255) for the given pin - /// - /// The pins mode has to be ARD_PWM - /// - /// On the Arduino Uno the following pins are supported: 3, 5, 6, 9, 10 and 11 - /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as digital pins - int getPwm(int pin) const; - - /// \brief Returns the last received value (if the pin mode is ARD_INPUT) - /// or the last set value (if the pin mode is ARD_OUTPUT) for the given - /// pin - /// - /// Returns whether the pin is reading high or low, 1 or 0. You can test - /// against this with an if() statement which is handy: - /// ~~~~{.cpp} - /// if(arduino.getDigital(pin)){ - /// // do something on high - /// } else { - /// // do something on low - /// } - /// ~~~~ - /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as digital pins - int getDigital(int pin) const; - - /// \brief Returns the analog in value that the pin is currently reading. - /// because the Arduino has a 10 bit ADC you get between 0 and 1023 for - /// possible values. - /// - /// \param pin The pin number (0-5) - int getAnalog(int pin) const; - - /// \returns the last received SysEx message. - vector getSysEx() const; - - /// \returns the last received string. - string getString() const; - - /// \brief Returns the major firmware version - int getMajorProtocolVersion() const; - - /// \returns the minor firmware version. - int getMinorProtocolVersion() const; - - /// \returns the major firmware version. - int getMajorFirmwareVersion() const; - - /// \returns the minor firmware version. - int getMinorFirmwareVersion() const; - - /// \returns the name of the firmware. - string getFirmwareName() const; - - /// \brief Returns a pointer to the digital data history list for the - /// given pin - /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as - /// digital pins - /// \param pin The pin number (2-13) - list* getDigitalHistory(int pin); - - /// \brief Returns a pointer to the analog data history list for the given pin. - /// \param pin The Arduino Uno pin: 0-5 - list* getAnalogHistory(int pin); - - /// \returns a pointer to the SysEx history. - list >* getSysExHistory(); - - /// \returns a pointer to the string history. - list* getStringHistory(); - - /// \brief Get the pin mode of the given pin - /// - /// \returns `ARD_INPUT`, `ARD_OUTPUT`, `ARD_PWM`, `ARD_SERVO`, `ARD_ANALOG` - int getDigitalPinMode(int pin) const; - - /// \returns `ARD_ON` or `ARD_OFF` - int getAnalogPinReporting(int pin) const; - - /// \brief Useful for parsing SysEx messages - int getValueFromTwo7bitBytes(unsigned char lsb, unsigned char msb); - - /// \} - /// \name Events - /// \{ - - /// \brief Triggered when a digital pin changes value, the pin that - /// changed is passed as an argument. - ofEvent EDigitalPinChanged; - - /// \brief Triggered when an analog pin changes value, the pin that - /// changed is passed as an argument. - ofEvent EAnalogPinChanged; - - /// \brief Triggered when a SysEx message that isn't in the extended - /// command set is received, the SysEx message is passed as an argument - ofEvent > ESysExReceived; - - /// \brief Triggered when a protocol version is received, the major version - /// is passed as an argument. - ofEvent EProtocolVersionReceived; - - /// \brief Triggered when a firmware version is received, the major version - /// is passed as an argument. - ofEvent EFirmwareVersionReceived; - - /// \brief Triggered when the firmware version is received upon connect, - /// the major firmware version is passed as an argument. From this point - /// it's safe to send to the Arduino. - ofEvent EInitialized; - - /// \brief Triggered when a string is received, the string is passed as an - /// argument - ofEvent EStringReceived; - - /// \} - /// \name Servos - /// \{ - - /// \brief Send a value to a servo. - /// - /// A servo has to be atached to the pin prior - /// \param pin 9 or 10 - /// \param value The value to send - void sendServo(int pin, int value, bool force=false); - - /// \param angle parameter DEPRECATED as of Firmata 2.2 - void sendServoAttach(int pin, int minPulse=544, int maxPulse=2400, int angle=180); - - /// \brief Detaches a servo on a pin - /// \note sendServoDetach DEPRECATED as of Firmata 2.2 - void sendServoDetach(int pin); - - /// \returns the last set servo value for a pin if the pin has a servo attached. - int getServo(int pin) const; - - /// \} - -protected: - mutable bool _initialized; - - void initPins() const; - mutable int _totalDigitalPins; - - void sendDigitalPinReporting(int pin, int mode); - // sets pin reporting to ARD_ON or ARD_OFF - // enables / disables reporting for the pins port - - void sendDigitalPortReporting(int port, int mode); - // sets port reporting to ARD_ON or ARD_OFF - // enables / disables reporting for ports 0-2 - // port 0: pins 2-7 (0,1 are serial RX/TX) - // port 1: pins 8-13 (14,15 are disabled for the crystal) - // port 2: pins 16-21 analog pins used as digital, all analog reporting will be turned off if this is set to ARD_ON - - void processData(unsigned char inputData); - void processDigitalPort(int port, unsigned char value); - virtual void processSysExData(vector data); - - ofSerial _port; - int _portStatus; - - // --- history variables - int _analogHistoryLength; - int _digitalHistoryLength; - int _stringHistoryLength; - int _sysExHistoryLength; - - // --- data processing variables - int _waitForData; - int _executeMultiByteCommand; - int _multiByteChannel; // indicates which pin data came from - - // --- data holders - unsigned char _storedInputData[FIRMATA_MAX_DATA_BYTES]; - vector _sysExData; - int _majorProtocolVersion; - int _minorProtocolVersion; - int _majorFirmwareVersion; - int _minorFirmwareVersion; - string _firmwareName; - - // sum of majorFirmwareVersion * 10 + minorFirmwareVersion - int _firmwareVersionSum; - - list > _sysExHistory; - // maintains a history of received sysEx messages (excluding SysEx messages in the extended command set) - - list _stringHistory; - // maintains a history of received strings - - mutable list _analogHistory[ARD_TOTAL_ANALOG_PINS]; - // a history of received data for each analog pin - - mutable list _digitalHistory[ARD_TOTAL_DIGITAL_PINS]; - // a history of received data for each digital pin - - mutable int _digitalPinMode[ARD_TOTAL_DIGITAL_PINS]; - // the modes for all digital pins - - mutable int _digitalPinValue[ARD_TOTAL_DIGITAL_PINS]; - // the last set values (DIGITAL/PWM) on all digital pins - - mutable int _digitalPortValue[ARD_TOTAL_PORTS]; - // the last set values on all ports - - mutable int _digitalPortReporting[ARD_TOTAL_PORTS]; - // whether pin reporting is enabled / disabled - - mutable int _digitalPinReporting[ARD_TOTAL_DIGITAL_PINS]; - // whether pin reporting is enabled / disabled - - mutable int _analogPinReporting[ARD_TOTAL_ANALOG_PINS]; - // whether pin reporting is enabled / disabled - - bool bUseDelay; - - mutable bool connected; - - float connectTime; - - mutable int _servoValue[ARD_TOTAL_DIGITAL_PINS]; - // the last set servo values - +class ofArduino { + + public: + /// \name Constructor and Destructor + /// \{ + + ofArduino(); + + virtual ~ofArduino(); + + /// \} + /// \name Connect + /// \{ + + /// \brief Opens a serial port connection to the arduino + /// \param device The name of the device. + /// You can get the name from the Arduino IDE + /// \param baud The baud rate the connection uses + bool connect(const std::string & device, int baud = 57600); + + /// \brief Returns true if a succesfull connection has been established + /// and the Arduino has reported a firmware + bool isInitialized() const; + + bool isArduinoReady() const; + + /// \brief Closes the serial port connection. + /// Does not turn the Arduino off. + void disconnect(); + + /// \} + /// \name Update + /// \{ + + /// \brief Polls data from the serial port, this has to be called periodically + void update(); + + /// \} + /// \name Setup + /// \{ + + /// \brief Setting a pins mode to ARD_INPUT turns on reporting for the port the pin is on + /// \param pin Pin on arduino (2-13) + /// \param mode `ARD_INPUT`, `ARD_OUTPUT`, `ARD_PWM` + /// \note Analog pins 0-5 can be used as digitial pins 16-21 but if the + /// mode of _one_ of these pins is set to `ARD_INPUT` then _all_ analog pin + /// reporting will be turned off + void sendDigitalPinMode(int pin, int mode); + + void sendAnalogPinReporting(int pin, int mode); + // pin: 0-5 + // mode: ARD_ON or ARD_OFF + // Note: analog pins 0-5 can be used as digitial pins 16-21 but if reporting for _one_ analog pin is enabled then reporting for _all_ of digital pin 16-21 will be turned off + + void setUseDelay(bool bDelay); + + void setDigitalHistoryLength(int length); + void setAnalogHistoryLength(int length); + void setStringHistoryLength(int length); + void setSysExHistoryLength(int nSysEx); + + /// \} + /// \name Senders + /// \{ + + void sendDigital(int pin, int value, bool force = false); + // pin: 2-13 + // value: ARD_LOW or ARD_HIGH + // the pins mode has to be set to ARD_OUTPUT or ARD_INPUT (in the latter mode pull-up resistors are enabled/disabled) + // Note: pin 16-21 can also be used if analog inputs 0-5 are used as digital pins + + + void sendPwm(int pin, int value, bool force = false); + + void sendSysEx(int command, vector data); + + /// \brief Send a string to the Arduino + /// \note Firmata can not handle strings longer than 12 characters. + void sendString(string str); + + void sendProtocolVersionRequest(); + + void sendFirmwareVersionRequest(); + + /// \brief This will cause your Arduino to reset and boot into the program again. + void sendReset(); + + /// \brief Sends the `FIRMATA_START_SYSEX` command + void sendSysExBegin(); + + /// \brief Sends the `FIRMATA_END_SYSEX` command + void sendSysExEnd(); + + /// \brief Sends a byte without wrapping it in a firmata message. + /// + /// Data has to be in the 0-127 range. Values > 127 will be interpreted as + /// commands. + void sendByte(unsigned char byte); + + /// \brief Send value as two 7 bit bytes. + /// + /// Sends a value as two 7-bit bytes without wrapping it in a firmata + /// message. Values in the range 0 - 16384 will be sent as two bytes + /// within the 0-127 data range. + /// + /// \param value The value to send. + void sendValueAsTwo7bitBytes(int value); + + /// \} + /// \name Getters + /// \{ + + /// \brief Returns the last set PWM value (0-255) for the given pin + /// + /// The pins mode has to be ARD_PWM + /// + /// On the Arduino Uno the following pins are supported: 3, 5, 6, 9, 10 and 11 + /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as digital pins + int getPwm(int pin) const; + + /// \brief Returns the last received value (if the pin mode is ARD_INPUT) + /// or the last set value (if the pin mode is ARD_OUTPUT) for the given + /// pin + /// + /// Returns whether the pin is reading high or low, 1 or 0. You can test + /// against this with an if() statement which is handy: + /// ~~~~{.cpp} + /// if(arduino.getDigital(pin)){ + /// // do something on high + /// } else { + /// // do something on low + /// } + /// ~~~~ + /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as digital pins + int getDigital(int pin) const; + + /// \brief Returns the analog in value that the pin is currently reading. + /// because the Arduino has a 10 bit ADC you get between 0 and 1023 for + /// possible values. + /// + /// \param pin The pin number (0-5) + int getAnalog(int pin) const; + + /// \returns the last received SysEx message. + vector getSysEx() const; + + /// \returns the last received string. + string getString() const; + + /// \brief Returns the major firmware version + int getMajorProtocolVersion() const; + + /// \returns the minor firmware version. + int getMinorProtocolVersion() const; + + /// \returns the major firmware version. + int getMajorFirmwareVersion() const; + + /// \returns the minor firmware version. + int getMinorFirmwareVersion() const; + + /// \returns the name of the firmware. + string getFirmwareName() const; + + /// \brief Returns a pointer to the digital data history list for the + /// given pin + /// \note Pin 16-21 can also be used if analog inputs 0-5 are used as + /// digital pins + /// \param pin The pin number (2-13) + list * getDigitalHistory(int pin); + + /// \brief Returns a pointer to the analog data history list for the given pin. + /// \param pin The Arduino Uno pin: 0-5 + list * getAnalogHistory(int pin); + + /// \returns a pointer to the SysEx history. + list > * getSysExHistory(); + + /// \returns a pointer to the string history. + list * getStringHistory(); + + /// \brief Get the pin mode of the given pin + /// + /// \returns `ARD_INPUT`, `ARD_OUTPUT`, `ARD_PWM`, `ARD_SERVO`, `ARD_ANALOG` + int getDigitalPinMode(int pin) const; + + /// \returns `ARD_ON` or `ARD_OFF` + int getAnalogPinReporting(int pin) const; + + /// \brief Useful for parsing SysEx messages + int getValueFromTwo7bitBytes(unsigned char lsb, unsigned char msb); + + /// \} + /// \name Events + /// \{ + + /// \brief Triggered when a digital pin changes value, the pin that + /// changed is passed as an argument. + ofEvent EDigitalPinChanged; + + /// \brief Triggered when an analog pin changes value, the pin that + /// changed is passed as an argument. + ofEvent EAnalogPinChanged; + + /// \brief Triggered when a SysEx message that isn't in the extended + /// command set is received, the SysEx message is passed as an argument + ofEvent > ESysExReceived; + + /// \brief Triggered when a protocol version is received, the major version + /// is passed as an argument. + ofEvent EProtocolVersionReceived; + + /// \brief Triggered when a firmware version is received, the major version + /// is passed as an argument. + ofEvent EFirmwareVersionReceived; + + /// \brief Triggered when the firmware version is received upon connect, + /// the major firmware version is passed as an argument. From this point + /// it's safe to send to the Arduino. + ofEvent EInitialized; + + /// \brief Triggered when a string is received, the string is passed as an + /// argument + ofEvent EStringReceived; + + /// \} + /// \name Servos + /// \{ + + /// \brief Send a value to a servo. + /// + /// A servo has to be atached to the pin prior + /// \param pin 9 or 10 + /// \param value The value to send + void sendServo(int pin, int value, bool force = false); + + /// \param angle parameter DEPRECATED as of Firmata 2.2 + void sendServoAttach(int pin, int minPulse = 544, int maxPulse = 2400, int angle = 180); + + /// \brief Detaches a servo on a pin + /// \note sendServoDetach DEPRECATED as of Firmata 2.2 + void sendServoDetach(int pin); + + /// \returns the last set servo value for a pin if the pin has a servo attached. + int getServo(int pin) const; + + /// \} + + protected: + mutable bool _initialized; ///\< \brief Indicate that pins are initialized. + + void initPins() const; + mutable int _totalDigitalPins; ///\< \brief Indicate the total number of digital pins of the board in use. + + void sendDigitalPinReporting(int pin, int mode); + // sets pin reporting to ARD_ON or ARD_OFF + // enables / disables reporting for the pins port + + void sendDigitalPortReporting(int port, int mode); + // sets port reporting to ARD_ON or ARD_OFF + // enables / disables reporting for ports 0-2 + // port 0: pins 2-7 (0,1 are serial RX/TX) + // port 1: pins 8-13 (14,15 are disabled for the crystal) + // port 2: pins 16-21 analog pins used as digital, all analog reporting will be turned off if this is set to ARD_ON + + void processData(unsigned char inputData); + void processDigitalPort(int port, unsigned char value); + virtual void processSysExData(vector data); + + ofSerial _port; + int _portStatus; + + // --- history variables + int _analogHistoryLength; + int _digitalHistoryLength; + int _stringHistoryLength; + int _sysExHistoryLength; + + // --- data processing variables + int _waitForData; + int _executeMultiByteCommand; ///< \brief Indicate Firmata command to execute. + int _multiByteChannel; ///< \brief Indicates which pin the data came from. + + // --- data holders + unsigned char _storedInputData[FIRMATA_MAX_DATA_BYTES]; + vector _sysExData; + int _majorProtocolVersion; + int _minorProtocolVersion; + int _majorFirmwareVersion; + int _minorFirmwareVersion; + string _firmwareName; + + // sum of majorFirmwareVersion * 10 + minorFirmwareVersion -> Firmata (?) + int _firmwareVersionSum; + + list > _sysExHistory; + // maintains a history of received sysEx messages (excluding SysEx messages in the extended command set) + + list _stringHistory; + // maintains a history of received strings + + mutable list _analogHistory[ARD_TOTAL_ANALOG_PINS]; + // a history of received data for each analog pin + + mutable list _digitalHistory[ARD_TOTAL_DIGITAL_PINS]; + // a history of received data for each digital pin + + mutable int _digitalPinMode[ARD_TOTAL_DIGITAL_PINS]; + // the modes for all digital pins + + mutable int _digitalPinValue[ARD_TOTAL_DIGITAL_PINS]; + // the last set values (DIGITAL/PWM) on all digital pins + + mutable int _digitalPortValue[ARD_TOTAL_PORTS]; + // the last set values on all ports + + mutable int _digitalPortReporting[ARD_TOTAL_PORTS]; + // whether pin reporting is enabled / disabled + + mutable int _digitalPinReporting[ARD_TOTAL_DIGITAL_PINS]; + // whether pin reporting is enabled / disabled + + mutable int _analogPinReporting[ARD_TOTAL_ANALOG_PINS]; + // whether pin reporting is enabled / disabled + + bool bUseDelay; + + mutable bool connected; ///< \brief This yields true if a serial connection to Arduino exists. + + float connectTime; ///< \brief This represents the (running) time of establishing a serial connection. + + mutable int _servoValue[ARD_TOTAL_DIGITAL_PINS]; + // the last set servo values + }; typedef ofArduino ofStandardFirmata; diff --git a/libs/openFrameworks/communication/ofSerial.cpp b/libs/openFrameworks/communication/ofSerial.cpp index a490b968183..7e280331639 100644 --- a/libs/openFrameworks/communication/ofSerial.cpp +++ b/libs/openFrameworks/communication/ofSerial.cpp @@ -14,6 +14,10 @@ #include #include +#ifdef TARGET_LINUX + #include +#endif + #ifdef TARGET_WIN32 @@ -155,10 +159,7 @@ void ofSerial::buildDeviceList(){ #ifdef TARGET_LINUX - #ifdef TARGET_RASPBERRY_PI - prefixMatch.push_back("ttyACM"); - #endif - + prefixMatch.push_back("ttyACM"); prefixMatch.push_back("ttyS"); prefixMatch.push_back("ttyUSB"); prefixMatch.push_back("rfc"); @@ -166,34 +167,23 @@ void ofSerial::buildDeviceList(){ #endif #if defined( TARGET_OSX ) || defined( TARGET_LINUX ) - DIR *dir; - dir = opendir("/dev"); - - string deviceName = ""; - - if(dir == nullptr){ - ofLogError("ofSerial") << "buildDeviceList(): error listing devices in /dev"; - } else { - int deviceCount = 0; - //for each device - struct dirent *entry; - while((entry = readdir(dir)) != nullptr){ - deviceName = (char *)entry->d_name; - - //we go through the prefixes - for(int k = 0; k < (int)prefixMatch.size(); k++){ - //if the device name is longer than the prefix - if(deviceName.size() > prefixMatch[k].size()){ - //do they match ? - if(deviceName.substr(0, prefixMatch[k].size()) == prefixMatch[k].c_str()){ - devices.push_back(ofSerialDeviceInfo("/dev/"+deviceName, deviceName, deviceCount)); - deviceCount++; - break; - } + ofDirectory dir("/dev"); + int deviceCount = 0; + for(auto & entry: dir){ + std::string deviceName = entry.path(); + + //we go through the prefixes + for(auto & prefix: prefixMatch){ + //if the device name is longer than the prefix + if(deviceName.size() > prefix.size()){ + //do they match ? + if(deviceName.substr(0, prefix.size()) == prefix.c_str()){ + devices.push_back(ofSerialDeviceInfo("/dev/"+deviceName, deviceName, deviceCount)); + deviceCount++; + break; } } } - closedir(dir); } #endif @@ -209,12 +199,15 @@ void ofSerial::buildDeviceList(){ #endif - //here we sort the device to have the aruino ones first. - partition(devices.begin(), devices.end(), isDeviceArduino); - //we are reordering the device ids. too! - for(int k = 0; k < (int)devices.size(); k++){ - devices[k].deviceID = k; - } + #if defined( TARGET_OSX ) + //here we sort the device to have the aruino ones first. + partition(devices.begin(), devices.end(), isDeviceArduino); + //we are reordering the device ids. too! + int k = 0; + for(auto & device: devices){ + device.deviceID = k++; + } + #endif bHaveEnumeratedDevices = true; } @@ -223,8 +216,8 @@ void ofSerial::buildDeviceList(){ //---------------------------------------------------------------- void ofSerial::listDevices(){ buildDeviceList(); - for(int k = 0; k < (int)devices.size(); k++){ - ofLogNotice("ofSerial") << "[" << devices[k].getDeviceID() << "] = "<< devices[k].getDeviceName().c_str(); + for(auto & device: devices){ + ofLogNotice("ofSerial") << "[" << device.getDeviceID() << "] = "<< device.getDeviceName().c_str(); } } @@ -365,7 +358,13 @@ bool ofSerial::setup(string portName, int baud){ options.c_oflag &= (tcflag_t) ~(OPOST); options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); - + #ifdef TARGET_LINUX + struct serial_struct kernel_serial_settings; + if (ioctl(fd, TIOCGSERIAL, &kernel_serial_settings) == 0) { + kernel_serial_settings.flags |= ASYNC_LOW_LATENCY; + ioctl(fd, TIOCSSERIAL, &kernel_serial_settings); + } + #endif bInited = true; ofLogNotice("ofSerial") << "opened " << portName << " sucessfully @ " << baud << " bps"; @@ -398,28 +397,16 @@ bool ofSerial::setup(string portName, int baud){ // now try the settings: COMMCONFIG cfg; DWORD cfgSize; - char buf[80]; + WCHAR buf[80]; cfgSize = sizeof(cfg); GetCommConfig(hComm, &cfg, &cfgSize); int bps = baud; - sprintf(buf, "baud=%d parity=N data=8 stop=1", bps); - - #if (_MSC_VER) // microsoft visual studio - // msvc doesn't like BuildCommDCB, - //so we need to use this version: BuildCommDCBA - if(!BuildCommDCBA(buf, &cfg.dcb)){ - ofLogError("ofSerial") << "setup(): unable to build comm dcb, (" << buf << ")"; - } - - #else - - if(!BuildCommDCB(buf, &cfg.dcb)){ - ofLogError("ofSerial") << "setup(): unable to build comm dcb, (" << buf << ")"; - } - - #endif + swprintf(buf, L"baud=%d parity=N data=8 stop=1", bps); + if(!BuildCommDCBW(buf, &cfg.dcb)){ + ofLogError("ofSerial") << "setup(): unable to build comm dcb, (" << buf << ")"; + } // Set baudrate and bits etc. // Note that BuildCommDCB() clears XON/XOFF and hardware control by default @@ -453,28 +440,35 @@ bool ofSerial::setup(string portName, int baud){ //---------------------------------------------------------------- -int ofSerial::writeBytes(unsigned char * buffer, int length){ +long ofSerial::writeBytes(const char * buffer, size_t length){ if(!bInited){ ofLogError("ofSerial") << "writeBytes(): serial not inited"; return OF_SERIAL_ERROR; } #if defined( TARGET_OSX ) || defined( TARGET_LINUX ) - int numWritten = write(fd, buffer, length); - if(numWritten <= 0){ - if(errno == EAGAIN){ - return 0; - } - ofLogError("ofSerial") << "writeBytes(): couldn't write to port: " << errno << " " << strerror(errno); - return OF_SERIAL_ERROR; + size_t written=0; + fd_set wfds; + struct timeval tv; + while (written < length) { + auto n = write(fd, buffer + written, length - written); + if (n < 0 && (errno == EAGAIN || errno == EINTR)) n = 0; + //printf("Write, n = %d\n", n); + if (n < 0) return OF_SERIAL_ERROR; + if (n > 0) { + written += n; + } else { + tv.tv_sec = 10; + tv.tv_usec = 0; + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + n = select(fd+1, NULL, &wfds, NULL, &tv); + if (n < 0 && errno == EINTR) n = 1; + if (n <= 0) return OF_SERIAL_ERROR; + } } - - ofLogVerbose("ofSerial") << "wrote " << (int) numWritten << " bytes"; - return numWritten; - - #endif - - #ifdef TARGET_WIN32 + return written; + #elif defined(TARGET_WIN32) DWORD written; if(!WriteFile(hComm, buffer, length, &written,0)){ @@ -492,7 +486,22 @@ int ofSerial::writeBytes(unsigned char * buffer, int length){ } //---------------------------------------------------------------- -int ofSerial::readBytes(unsigned char * buffer, int length){ +long ofSerial::writeBytes(const unsigned char * buffer, size_t length){ + return writeBytes(reinterpret_cast(buffer), length); +} + +//---------------------------------------------------------------- +bool ofSerial::writeByte(char singleByte){ + return writeByte(static_cast(singleByte)); +} + +//---------------------------------------------------------------- +long ofSerial::writeBytes(const ofBuffer & buffer){ + return writeBytes(buffer.getData(),buffer.size()); +} + +//---------------------------------------------------------------- +long ofSerial::readBytes(char * buffer, size_t length){ if (!bInited){ ofLogError("ofSerial") << "readBytes(): serial not inited"; return OF_SERIAL_ERROR; @@ -500,7 +509,7 @@ int ofSerial::readBytes(unsigned char * buffer, int length){ #if defined( TARGET_OSX ) || defined( TARGET_LINUX ) - int nRead = read(fd, buffer, length); + auto nRead = read(fd, buffer, length); if(nRead < 0){ if ( errno == EAGAIN ) return OF_SERIAL_NO_DATA; @@ -526,49 +535,24 @@ int ofSerial::readBytes(unsigned char * buffer, int length){ #endif } +//---------------------------------------------------------------- +long ofSerial::readBytes(unsigned char * buffer, size_t length){ + return readBytes(reinterpret_cast(buffer), length); +} + +//---------------------------------------------------------------- +long ofSerial::readBytes(ofBuffer & buffer, size_t length){ + buffer.allocate(length); + return readBytes(buffer.getData(),length); +} + //---------------------------------------------------------------- bool ofSerial::writeByte(unsigned char singleByte){ if (!bInited){ ofLogError("ofSerial") << "writeByte(): serial not inited"; - //return OF_SERIAL_ERROR; // this looks wrong. return false; } - - #if defined( TARGET_OSX ) || defined( TARGET_LINUX ) - - int numWritten = 0; - numWritten = write(fd, &singleByte, 1); - if(numWritten <= 0 ){ - if(errno == EAGAIN){ - return 0; - } - ofLogError("ofSerial") << "writeByte(): couldn't write to port: " << errno << " " << strerror(errno); - //return OF_SERIAL_ERROR; // this looks wrong. - return false; - } - ofLogVerbose("ofSerial") << "wrote byte"; - - return (numWritten > 0 ? true : false); - - #elif defined( TARGET_WIN32 ) - - DWORD written = 0; - if(!WriteFile(hComm, &singleByte, 1, &written,0)){ - ofLogError("ofSerial") << "writeByte(): couldn't write to port"; - //return OF_SERIAL_ERROR; // this looks wrong. - return false; - } - - ofLogVerbose("ofSerial") << "wrote byte"; - - return ((int)written > 0 ? true : false); - - #else - - ofLogError("ofSerial") << "not defined in this platform"; - return false; - - #endif + return writeBytes(&singleByte,1) > 0; } //---------------------------------------------------------------- @@ -590,6 +574,7 @@ int ofSerial::readByte(){ ofLogError("ofSerial") << "readByte(): couldn't read from port: " << errno << " " << strerror(errno); return OF_SERIAL_ERROR; } + if(nRead == 0){ return OF_SERIAL_NO_DATA; } @@ -601,6 +586,10 @@ int ofSerial::readByte(){ ofLogError("ofSerial") << "readByte(): couldn't read from port"; return OF_SERIAL_ERROR; } + + if(nRead == 0){ + return OF_SERIAL_NO_DATA; + } #else diff --git a/libs/openFrameworks/communication/ofSerial.h b/libs/openFrameworks/communication/ofSerial.h index a64335ab3e6..b310d619dfc 100644 --- a/libs/openFrameworks/communication/ofSerial.h +++ b/libs/openFrameworks/communication/ofSerial.h @@ -1,7 +1,9 @@ #pragma once +#include #include "ofConstants.h" #include "ofTypes.h" +#include "ofFileUtils.h" #if defined( TARGET_OSX ) || defined( TARGET_LINUX ) || defined (TARGET_ANDROID) #include @@ -16,10 +18,10 @@ #define MAX_SERIAL_PORTS 256 /// \endcond #include - #ifdef __MINGW32__ + /*#ifndef _MSC_VER #define INITGUID #include // needed for dev-c++ & DEFINE_GUID - #endif + #endif*/ #endif @@ -189,7 +191,9 @@ class ofSerial { /// Be aware that the type of your buffer can only be unsigned char. If you're /// trying to receieve ints or signed chars over a serial connection you'll /// need to do some bit manipulation to correctly interpret that values. - int readBytes(unsigned char * buffer, int length); + long readBytes(unsigned char * buffer, size_t length); + long readBytes(char * buffer, size_t length); + long readBytes(ofBuffer & buffer, size_t length); /// \brief Reads and returns a single byte from the requested device. /// @@ -222,7 +226,9 @@ class ofSerial { /// unsigned char buf[3] = {'o', 'f', '!'}; /// device.writeBytes(&buf[0], 3); /// ~~~~ - int writeBytes(unsigned char * buffer, int length); + long writeBytes(const unsigned char * buffer, size_t length); + long writeBytes(const char * buffer, size_t length); + long writeBytes(const ofBuffer & buffer); /// \brief Writes a single byte to the connected serial device. /// @@ -236,6 +242,7 @@ class ofSerial { /// ofLog(OF_LOG_ERROR, "Byte was not written to serial port"); /// ~~~~ bool writeByte(unsigned char singleByte); + bool writeByte(char singleByte); /// \} /// \name Clear Data @@ -245,7 +252,7 @@ class ofSerial { /// /// Any data in the cleared buffers is discarded. /// \param flushIn If true then it clears the incoming data buffer - /// \param fluhOut If true then it clears the outgoing data buffer. + /// \param flushOut If true then it clears the outgoing data buffer. void flush(bool flushIn = true, bool flushOut = true); /// \brief Drain is only available on OSX and Linux and is very similar to diff --git a/libs/openFrameworks/events/ofEvent.h b/libs/openFrameworks/events/ofEvent.h index b827a281a45..7a5f3497cc5 100644 --- a/libs/openFrameworks/events/ofEvent.h +++ b/libs/openFrameworks/events/ofEvent.h @@ -6,155 +6,301 @@ #include #include #include +#include class ofEventAttendedException: public std::exception{}; -template -class ofBaseEvent{ -public: - /// \brief Basic constructor enabling an ofBaseEvent. - /// - /// \see ofBaseEvent::ofBaseEvent(const ofBaseEvent & mom) - /// \see ofBaseEvent::enable() - /// \see ofBaseEvent::disable() - /// \see ofBaseEvent::isEnabled() - ofBaseEvent() - :enabled(true){ - } - - /// \brief Copy-constructor for ofBaseEvent. - /// - /// \see ofBaseEvent::ofBaseEvent() - ofBaseEvent(const ofBaseEvent & mom): enabled(mom.enabled){ - std::unique_lock lck(const_cast(mom).mtx); - std::transform(functions.begin(), functions.end(),std::back_inserter(functions), - [&](Function&f){ - return std::unique_ptr(new Function(*f)); - }); - } - - /// \brief Overloading the assignment operator. - ofBaseEvent & operator=(const ofBaseEvent & mom){ - if(&mom==this){ - return *this; - } - std::unique_lock lck(const_cast(mom).mtx); - functions = mom.functions; - enabled = mom.enabled; - return *this; - } - - /// \brief Enable an event. - /// - /// \see ofBaseEvent::disable() - /// \see ofBaseEvent::isEnabled() - void enable() { - enabled = true; - } +/*! \cond PRIVATE */ +namespace of{ +namespace priv{ + class NoopMutex{ + public: + void lock(){} + void unlock(){} + }; - /// \brief Disable an event. - /// - /// \see ofBaseEvent::enable() - /// \see ofBaseEvent::isEnabled() - void disable() { - enabled = false; - } + class AbstractEventToken{ + public: + virtual ~AbstractEventToken(); + }; - /// \brief Check whether an event is enabled or not. - /// - /// \returns true if enables - /// \see ofBaseEvent::enable() - /// \see ofBaseEvent::disable() - bool isEnabled() const { - return enabled; - } + class BaseFunctionId{ + public: + BaseFunctionId(){} + BaseFunctionId(const BaseFunctionId &) = delete; + BaseFunctionId & operator=(const BaseFunctionId &) = delete; + virtual ~BaseFunctionId(); + virtual bool operator==(const BaseFunctionId &) const = 0; + virtual BaseFunctionId * clone() const = 0; + }; - std::size_t size() const { - return functions.size(); - } + class StdFunctionId: public BaseFunctionId{ + static std::atomic nextId; + uint64_t id; -protected: - template - void add(TFunction && f){ - std::unique_lock lck(mtx); - auto it = functions.begin(); - for(; it!=functions.end(); ++it){ - if(it->priority>f.priority) break; + StdFunctionId(uint64_t id) + :id(id){} + public: + StdFunctionId(){ + id = nextId++; } - functions.emplace(it, std::move(f)); - } - - template - void remove(const TFunction & function){ - std::unique_lock lck(mtx); - functions.erase(std::remove_if(functions.begin(), functions.end(), - [&](const Function & f){ - return f == function; - }), functions.end()); - } - Mutex mtx; - std::vector functions; - bool enabled; + virtual ~StdFunctionId(); -}; + bool operator==(const BaseFunctionId & otherid) const{ + const auto * other = dynamic_cast(&otherid); + return other && id == other->id; + } -/*! \cond PRIVATE */ -namespace of{ -namespace priv{ - class NoopMutex{ - public: - void lock(){} - void unlock(){} + BaseFunctionId * clone() const{ + return new StdFunctionId(id); + } }; - class BaseFunctionId{}; - template + inline std::unique_ptr make_function_id(){ + return std::unique_ptr(new StdFunctionId()); + } + + template class Function{ public: Function(int priority, std::function function, std::unique_ptr&& id ) :priority(priority) - ,function(function) - ,id(std::move(id)){} + ,id(std::move(id)) + ,function(function){} - template - bool operator==(const F & f1) const{ - const auto * thisAsF = dynamic_cast(this); - return thisAsF && f1.priority == priority && id == f1.id; + bool operator==(const Function & f) const{ + return f.priority == priority && *id == *f.id; + } + + inline bool notify(const void*s,T&t){ + std::unique_lock lck(mtx); + try{ + return function(s,t); + }catch(std::bad_function_call &){ + return false; + } + } + + inline void disable(){ + std::unique_lock lck(mtx); + function = nullptr; } int priority; - std::function function; std::unique_ptr id; + + private: + std::function function; + Mutex mtx; }; - template<> - class Function{ + template + class Function{ public: Function(int priority, std::function function, std::unique_ptr && id ) :priority(priority) - ,function(function) - ,id(std::move(id)){} + ,id(std::move(id)) + ,function(function){} - template - bool operator==(const F & f1) const{ - const auto * thisAsF = dynamic_cast(this); - return thisAsF && f1.priority == priority && id == f1.id; + bool operator==(const Function & f) const{ + return f.priority == priority && *id == *f.id; + } + + inline bool notify(const void*s){ + std::unique_lock lck(mtx); + try{ + return function(s); + }catch(std::bad_function_call &){ + return false; + } + } + + inline void disable(){ + std::unique_lock lck(mtx); + function = nullptr; } int priority; - std::function function; std::unique_ptr id; + private: + std::function function; + Mutex mtx; + }; + + + template + class BaseEvent{ + public: + BaseEvent(){} + + BaseEvent(const BaseEvent & mom){ + std::unique_lock lck(const_cast(mom).self->mtx); + self->functions = mom.self->functions; + } + + BaseEvent & operator=(const BaseEvent & mom){ + if(&mom==this){ + return *this; + } + std::unique_lock lck(const_cast(mom).self->mtx); + std::unique_lock lck2(self->mtx); + self->functions = mom.self->functions; + self->enabled = mom.self->enabled; + return *this; + } + + BaseEvent(BaseEvent && mom){ + std::unique_lock lck(const_cast(mom).self->mtx); + self->functions = std::move(mom.self->functions); + self->enabled = std::move(mom.self->enabled); + } + + BaseEvent & operator=(BaseEvent && mom){ + if(&mom==this){ + return *this; + } + std::unique_lock lck(const_cast(mom).self->mtx); + std::unique_lock lck2(self->mtx); + self->functions = mom.self->functions; + self->enabled = mom.self->enabled; + return *this; + } + + void enable() { + self->enabled = true; + } + + void disable() { + self->enabled = false; + } + + bool isEnabled() const { + return self->enabled; + } + + std::size_t size() const { + return self->functions.size(); + } + + protected: + +#if _MSC_VER + template struct check_function; + template + struct check_function : public std::function { + template::value + || std::is_convertible< + decltype(std::declval()(std::declval()...)), + R>::value>::type> + check_function(T &&t) : std::function(std::forward(t)) { } + }; +#endif + + struct Data{ + Mutex mtx; + std::vector> functions; + bool enabled = true; + + void remove(const BaseFunctionId & id){ + std::unique_lock lck(mtx); + auto it = functions.begin(); + for(; it!=functions.end(); ++it){ + auto f = *it; + if(*f->id == id){ + f->disable(); + functions.erase(it); + break; + } + } + } + }; + std::shared_ptr self{new Data}; + + class EventToken: public AbstractEventToken{ + public: + EventToken() {}; + template + EventToken(std::shared_ptr & event, const Id & id) + :event(event) + ,id(id.clone()){ + + } + + ~EventToken(){ + auto event = this->event.lock(); + if(event){ + event->remove(*id); + } + } + + private: + std::weak_ptr event; + std::unique_ptr id; + }; + + std::unique_ptr make_token(const Function & f){ + return std::unique_ptr(new EventToken(self,*f.id)); + } + + template + void addNoToken(TFunction && f){ + std::unique_lock lck(self->mtx); + auto it = self->functions.begin(); + for(; it!=self->functions.end(); ++it){ + if((*it)->priority>f->priority) break; + } + self->functions.emplace(it, f); + } + + template + std::unique_ptr addFunction(TFunction && f){ + std::unique_lock lck(self->mtx); + auto it = self->functions.begin(); + for(; it!=self->functions.end(); ++it){ + if((*it)->priority>f->priority) break; + } + self->functions.emplace(it, f); + return make_token(*f); + } + + template + void removeFunction(const TFunction & function){ + self->remove(*function->id); + } }; } } /*! \endcond */ -template -class ofEvent: public ofBaseEvent,Mutex>{ +enum ofEventOrder{ + OF_EVENT_ORDER_BEFORE_APP=0, + OF_EVENT_ORDER_APP=100, + OF_EVENT_ORDER_AFTER_APP=200 +}; + +class ofEventListener{ +public: + ofEventListener(){} + ofEventListener(std::unique_ptr && token) + :token(std::move(token)){} + void unsubscribe(){ + token.reset(); + } +private: + std::unique_ptr token; +}; + + +template +class ofEvent: public of::priv::BaseEvent,Mutex>{ protected: + typedef of::priv::Function Function; + typedef std::shared_ptr FunctionPtr; template class FunctionId: public of::priv::BaseFunctionId{ @@ -168,10 +314,19 @@ class ofEvent: public ofBaseEvent,Mutex>{ } + BaseFunctionId * clone() const{ + return new FunctionId(listener, method); + } + template bool operator==(const F & f1) const{ return f1.listener == this->listener && f1.method == this->method; } + + bool operator==(const BaseFunctionId & f) const{ + const auto * other = dynamic_cast*>(&f); + return other && other->listener == this->listener && other->method == this->method; + } }; template @@ -180,84 +335,142 @@ class ofEvent: public ofBaseEvent,Mutex>{ } template - of::priv::Function make_function(TObj * listener, bool (TObj::*method)(T&), int priority){ - return of::priv::Function(priority, std::bind(method,listener,std::placeholders::_2), make_function_id(listener,method)); + FunctionPtr make_function(TObj * listener, bool (TObj::*method)(T&), int priority){ + return std::make_shared(priority, std::bind(method,listener,std::placeholders::_2), make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, void (TObj::*method)(T&), int priority){ - return of::priv::Function(priority, [listener, method](const void*, T&t){ - std::bind(method,listener,std::placeholders::_1)(t); + FunctionPtr make_function(TObj * listener, void (TObj::*method)(T&), int priority){ + return std::make_shared(priority, [listener, method](const void*, T&t){ + ((listener)->*(method))(t); return false; }, make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, bool (TObj::*method)(const void*, T&), int priority){ - return of::priv::Function(priority, std::bind(method,listener,std::placeholders::_1,std::placeholders::_2), make_function_id(listener,method)); + FunctionPtr make_function(TObj * listener, bool (TObj::*method)(const void*, T&), int priority){ + return std::make_shared(priority, std::bind(method,listener,std::placeholders::_1,std::placeholders::_2), make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, void (TObj::*method)(const void*, T&), int priority){ - return of::priv::Function(priority, [listener, method](const void*s, T&t){ + FunctionPtr make_function(TObj * listener, void (TObj::*method)(const void*, T&), int priority){ + return std::make_shared(priority, [listener, method](const void*s, T&t){ std::bind(method,listener,std::placeholders::_1,std::placeholders::_2)(s,t); return false; }, make_function_id(listener,method)); } - of::priv::Function make_function(bool (*function)(T&), int priority){ - return of::priv::Function(priority, std::bind(function,std::placeholders::_2), make_function_id((ofEvent*)nullptr,function)); + FunctionPtr make_function(bool (*function)(T&), int priority){ + return std::make_shared(priority, std::bind(function,std::placeholders::_2), make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(void (*function)(T&), int priority){ - return of::priv::Function(priority, [function](const void*, T&t){ + FunctionPtr make_function(void (*function)(T&), int priority){ + return std::make_shared(priority, [function](const void*, T&t){ (function)(t); return false; }, make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(bool (*function)(const void*, T&), int priority){ - return of::priv::Function(priority, function, make_function_id((ofEvent*)nullptr,function)); + FunctionPtr make_function(bool (*function)(const void*, T&), int priority){ + return std::make_shared(priority, function, make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(void (*function)(const void*, T&), int priority){ - return of::priv::Function(priority, [function](const void*s, T&t){ + FunctionPtr make_function(void (*function)(const void*, T&), int priority){ + return std::make_shared(priority, [function](const void*s, T&t){ function(s,t); return false; }, make_function_id((ofEvent*)nullptr,function)); } + +#ifdef _MSC_VER + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*,T&t){return f(t);}, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, f, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*,T&t){f(t);return false;}, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*s,T&t){f(s,t); return false;}, of::priv::make_function_id()); + } +#else + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*, T&t) {return f(t); }, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, f, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*, T&t) {f(t); return false; }, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*s, T&t) {f(s, t); return false; }, of::priv::make_function_id()); + } + + using of::priv::BaseEvent,Mutex>::removeFunction; + using of::priv::BaseEvent,Mutex>::addFunction; + using of::priv::BaseEvent,Mutex>::addNoToken; +#endif + public: + template + ofEventListener newListener(TObj * listener, TMethod method, int priority = OF_EVENT_ORDER_AFTER_APP){ + return ofEventListener(addFunction(make_function(listener,method,priority))); + } + template void add(TObj * listener, TMethod method, int priority){ - ofBaseEvent,Mutex>::add(make_function(listener,method,priority)); + addNoToken(make_function(listener,method,priority)); } template void remove(TObj * listener, TMethod method, int priority){ - ofBaseEvent,Mutex>::remove(make_function(listener,method,priority)); + removeFunction(make_function(listener,method,priority)); + } + + template + ofEventListener newListener(TFunction function, int priority = OF_EVENT_ORDER_AFTER_APP) { + return ofEventListener(addFunction(make_function(function, priority))); } template void add(TFunction function, int priority){ - ofBaseEvent,Mutex>::add(make_function(function,priority)); + addNoToken(make_function(function,priority)); } template void remove(TFunction function, int priority){ - ofBaseEvent,Mutex>::remove(make_function(function,priority)); + removeFunction(make_function(function,priority)); } inline void notify(const void* sender, T & param){ - if(this->template enabled && !this->template functions.empty()){ - std::vector*> functions_copy; - { - std::unique_lock lck(this->template mtx); - std::transform(this->template functions.begin(), this->template functions.end(), - std::back_inserter(functions_copy), - [&](of::priv::Function&f){return &f;}); + if(ofEvent::self->enabled && !ofEvent::self->functions.empty()){ + std::unique_lock lck(ofEvent::self->mtx); + std::vector>> functions_copy(ofEvent::self->functions); + lck.unlock(); + for(auto & f: functions_copy){ + if(f->notify(sender,param)){ + throw ofEventAttendedException(); + } } + } + } + + inline void notify(T & param){ + if(ofEvent::self->enabled && !ofEvent::self->functions.empty()){ + std::unique_lock lck(ofEvent::self->mtx); + std::vector>> functions_copy(ofEvent::self->functions); + lck.unlock(); for(auto & f: functions_copy){ - if(f->function(sender,param)){ + if(f->notify(nullptr,param)){ throw ofEventAttendedException(); } } @@ -266,8 +479,10 @@ class ofEvent: public ofBaseEvent,Mutex>{ }; template -class ofEvent: public ofBaseEvent,Mutex>{ +class ofEvent: public of::priv::BaseEvent,Mutex>{ protected: + typedef of::priv::Function Function; + typedef std::shared_ptr FunctionPtr; template class FunctionId: public of::priv::BaseFunctionId{ @@ -281,10 +496,19 @@ class ofEvent: public ofBaseEvent,Mutex>{ } + BaseFunctionId * clone() const{ + return new FunctionId(listener, method); + } + template bool operator==(const F & f1) const{ return f1.listener == this->listener && f1.method == this->method; } + + bool operator==(const BaseFunctionId & f) const{ + const auto * other = dynamic_cast*>(&f); + return other && other->listener == this->listener && other->method == this->method; + } }; @@ -294,84 +518,142 @@ class ofEvent: public ofBaseEvent,Mutex>{ } template - of::priv::Function make_function(TObj * listener, bool (TObj::*method)(), int priority){ - return of::priv::Function(priority, std::bind(method,listener), make_function_id(listener,method)); + FunctionPtr make_function(TObj * listener, bool (TObj::*method)(), int priority){ + return std::make_shared(priority, std::bind(method,listener), make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, void (TObj::*method)(), int priority){ - return of::priv::Function(priority,[listener, method](const void*){ + FunctionPtr make_function(TObj * listener, void (TObj::*method)(), int priority){ + return std::make_shared(priority,[listener, method](const void*){ std::bind(method,listener)(); return false; }, make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, bool (TObj::*method)(const void*), int priority){ - return of::priv::Function(priority,std::bind(method,listener,std::placeholders::_1), make_function_id(listener,method)); + FunctionPtr make_function(TObj * listener, bool (TObj::*method)(const void*), int priority){ + return std::make_shared(priority,std::bind(method,listener,std::placeholders::_1), make_function_id(listener,method)); } template - of::priv::Function make_function(TObj * listener, void (TObj::*method)(const void*), int priority){ - return of::priv::Function(priority,[listener, method](const void* sender){ + FunctionPtr make_function(TObj * listener, void (TObj::*method)(const void*), int priority){ + return std::make_shared(priority,[listener, method](const void* sender){ std::bind(method,listener,std::placeholders::_1)(sender); return false; }, make_function_id(listener,method)); } - of::priv::Function make_function(bool (*function)(), int priority){ - return of::priv::Function(priority, std::bind(function), make_function_id((ofEvent*)nullptr,function)); + FunctionPtr make_function(bool (*function)(), int priority){ + return std::make_shared(priority, std::bind(function), make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(void (*function)(), int priority){ - return of::priv::Function(priority,[function](const void*){ + FunctionPtr make_function(void (*function)(), int priority){ + return std::make_shared(priority,[function](const void*){ function(); return false; }, make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(bool (*function)(const void*), int priority){ - return of::priv::Function(priority, function, make_function_id((ofEvent*)nullptr,function)); + FunctionPtr make_function(bool (*function)(const void*), int priority){ + return std::make_shared(priority, function, make_function_id((ofEvent*)nullptr,function)); } - of::priv::Function make_function(void (*function)(const void*), int priority){ - return of::priv::Function(priority,[function](const void* sender){ + FunctionPtr make_function(void (*function)(const void*), int priority){ + return std::make_shared(priority,[function](const void* sender){ function(sender); return false; }, make_function_id((ofEvent*)nullptr,function)); } + +#ifdef _MSC_VER + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*){return f();}, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, f, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*){f(); return false;}, of::priv::make_function_id()); + } + + FunctionPtr make_function(check_function f, int priority){ + return std::make_shared(priority, [f](const void*s){f(s); return false;}, of::priv::make_function_id()); + } +#else + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*) {return f(); }, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, f, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*) {f(); return false; }, of::priv::make_function_id()); + } + + FunctionPtr make_function(std::function f, int priority) { + return std::make_shared(priority, [f](const void*s) {f(s); return false; }, of::priv::make_function_id()); + } + + using of::priv::BaseEvent,Mutex>::removeFunction; + using of::priv::BaseEvent,Mutex>::addFunction; + using of::priv::BaseEvent,Mutex>::addNoToken; +#endif + public: template void add(TObj * listener, TMethod method, int priority){ - ofBaseEvent,Mutex>::add(make_function(listener,method,priority)); + addNoToken(make_function(listener,method,priority)); + } + + template + ofEventListener newListener(TObj * listener, TMethod method, int priority = OF_EVENT_ORDER_AFTER_APP){ + return ofEventListener(addFunction(make_function(listener,method,priority))); } template void remove(TObj * listener, TMethod method, int priority){ - ofBaseEvent,Mutex>::remove(make_function(listener,method,priority)); + removeFunction(make_function(listener,method,priority)); } template void add(TFunction function, int priority){ - ofBaseEvent,Mutex>::add(make_function(function,priority)); + addNoToken(make_function(function,priority)); + } + + template + ofEventListener newListener(TFunction function, int priority = OF_EVENT_ORDER_AFTER_APP) { + return ofEventListener(addFunction(make_function(function, priority))); } template void remove(TFunction function, int priority){ - ofBaseEvent,Mutex>::remove(make_function(function,priority)); + removeFunction(make_function(function,priority)); } void notify(const void* sender){ - if(this->template enabled && !this->template functions.empty()){ - std::vector*> functions_copy; - { - std::unique_lock lck(this->template mtx); - std::transform(this->template functions.begin(), this->template functions.end(), - std::back_inserter(functions_copy), - [&](of::priv::Function & f){return &f;}); + if(ofEvent::self->enabled && !ofEvent::self->functions.empty()){ + std::unique_lock lck(ofEvent::self->mtx); + std::vector>> functions_copy(ofEvent::self->functions); + lck.unlock(); + for(auto & f: functions_copy){ + if(f->notify(sender)){ + throw ofEventAttendedException(); + } } + } + } + + void notify(){ + if(ofEvent::self->enabled && !ofEvent::self->functions.empty()){ + std::unique_lock lck(ofEvent::self->mtx); + std::vector>> functions_copy(ofEvent::self->functions); + lck.unlock(); for(auto & f: functions_copy){ - if(f->function(sender)){ + if(f->notify(nullptr)){ throw ofEventAttendedException(); } } @@ -385,11 +667,11 @@ template class ofFastEvent: public ofEvent{ public: inline void notify(const void* sender, T & param){ - if(this->template enabled && !this->template functions.empty()){ - for(auto & f: this->template functions){ - if(f.function(sender,param)){ - throw ofEventAttendedException(); - } + if(ofFastEvent::enabled){ + for(auto & f: ofFastEvent::functions){ + if(f->notify(sender,param)){ + throw ofEventAttendedException(); + } } } } diff --git a/libs/openFrameworks/events/ofEventUtils.h b/libs/openFrameworks/events/ofEventUtils.h index 74a09327ed4..1d5823ec43f 100644 --- a/libs/openFrameworks/events/ofEventUtils.h +++ b/libs/openFrameworks/events/ofEventUtils.h @@ -6,14 +6,6 @@ #include #include - - -enum ofEventOrder{ - OF_EVENT_ORDER_BEFORE_APP=0, - OF_EVENT_ORDER_APP=100, - OF_EVENT_ORDER_AFTER_APP=200 -}; - //---------------------------------------------------- // register any method of any class to an event. // the method must provide one of the following @@ -219,7 +211,7 @@ inline void ofNotifyEvent(EventType & event, ArgumentsType & args, SenderType * template inline void ofNotifyEvent(EventType & event, ArgumentsType & args){ try{ - event.notify(nullptr,args); + event.notify(args); }catch(ofEventAttendedException &){ } @@ -237,7 +229,7 @@ inline void ofNotifyEvent(EventType & event, const ArgumentsType & args, SenderT template inline void ofNotifyEvent(EventType & event, const ArgumentsType & args){ try{ - event.notify(nullptr,args); + event.notify(args); }catch(ofEventAttendedException &){ } @@ -254,7 +246,7 @@ inline void ofNotifyEvent(ofEvent & event, SenderType * sender){ inline void ofNotifyEvent(ofEvent & event){ try{ - event.notify(nullptr); + event.notify(); }catch(ofEventAttendedException &){ } diff --git a/libs/openFrameworks/events/ofEvents.cpp b/libs/openFrameworks/events/ofEvents.cpp index 735bb62b166..589ef4c93bb 100644 --- a/libs/openFrameworks/events/ofEvents.cpp +++ b/libs/openFrameworks/events/ofEvents.cpp @@ -311,7 +311,7 @@ void ofCoreEvents::notifyMouseEvent(const ofMouseEventArgs & mouseEvent){ notifyMouseReleased(mouseEvent.x,mouseEvent.y,mouseEvent.button); break; case ofMouseEventArgs::Scrolled: - notifyMouseScrolled(mouseEvent.x,mouseEvent.y); + notifyMouseScrolled(mouseEvent.x,mouseEvent.y,mouseEvent.scrollX,mouseEvent.scrollY); break; case ofMouseEventArgs::Entered: notifyMouseEntered(mouseEvent.x,mouseEvent.y); @@ -398,12 +398,10 @@ void ofCoreEvents::notifyMouseMoved(int x, int y){ } //------------------------------------------ -void ofCoreEvents::notifyMouseScrolled(float x, float y){ +void ofCoreEvents::notifyMouseScrolled(int x, int y, float scrollX, float scrollY){ ofMouseEventArgs mouseEventArgs(ofMouseEventArgs::Scrolled,x,y); - - mouseEventArgs.x = x; - mouseEventArgs.y = y; - mouseEventArgs.type = ofMouseEventArgs::Scrolled; + mouseEventArgs.scrollX = scrollX; + mouseEventArgs.scrollY = scrollY; ofNotifyEvent( mouseScrolled, mouseEventArgs ); } @@ -445,3 +443,16 @@ void ofSendMessage(string messageString){ ofMessage msg(messageString); ofSendMessage(msg); } + +//------------------------------------------ +namespace of{ + namespace priv{ + std::atomic StdFunctionId::nextId; + + AbstractEventToken::~AbstractEventToken(){} + + BaseFunctionId::~BaseFunctionId(){} + + StdFunctionId::~StdFunctionId(){} + } +} diff --git a/libs/openFrameworks/events/ofEvents.h b/libs/openFrameworks/events/ofEvents.h index 76639695086..cc0068a22ed 100644 --- a/libs/openFrameworks/events/ofEvents.h +++ b/libs/openFrameworks/events/ofEvents.h @@ -88,20 +88,31 @@ class ofMouseEventArgs : public ofEventArgs, public ofVec2f { ofMouseEventArgs() :type(Pressed) - ,button(OF_MOUSE_BUTTON_LEFT){} + ,button(OF_MOUSE_BUTTON_LEFT) + ,scrollX(0.f) + ,scrollY(0.f) + {} ofMouseEventArgs(Type type, float x, float y, int button) :ofVec2f(x,y) ,type(type) - ,button(button){} + ,button(button) + ,scrollX(0.f) + ,scrollY(0.f) + {} ofMouseEventArgs(Type type, float x, float y) :ofVec2f(x,y) ,type(type) - ,button(0){} + ,button(0) + ,scrollX(0.f) + ,scrollY(0.f) + {} Type type; int button; + float scrollX; + float scrollY; }; class ofTouchEventArgs : public ofEventArgs, public ofVec2f { @@ -244,7 +255,7 @@ class ofCoreEvents { void notifyMouseReleased(int x, int y, int button); void notifyMouseDragged(int x, int y, int button); void notifyMouseMoved(int x, int y); - void notifyMouseScrolled(float x, float y); + void notifyMouseScrolled(int x, int y, float scrollX, float scrollY); void notifyMouseEntered(int x, int y); void notifyMouseExited(int x, int y); void notifyMouseEvent(const ofMouseEventArgs & mouseEvent); diff --git a/libs/openFrameworks/gl/ofBufferObject.cpp b/libs/openFrameworks/gl/ofBufferObject.cpp index a4511eb0aa5..d20c17f0f56 100644 --- a/libs/openFrameworks/gl/ofBufferObject.cpp +++ b/libs/openFrameworks/gl/ofBufferObject.cpp @@ -63,11 +63,15 @@ void ofBufferObject::bind(GLenum target) const{ if(data){ glBindBuffer(target, data->id); data->lastTarget = target; + data->isBound = true; } } void ofBufferObject::unbind(GLenum target) const{ glBindBuffer(target, 0); + if(data){ + data->isBound = false; + } } #ifndef TARGET_OPENGLES @@ -75,17 +79,22 @@ void ofBufferObject::bindBase(GLenum target,GLuint index) const{ if(data){ glBindBufferBase(target,index,data->id); data->lastTarget = target; + data->isBound = true; } } void ofBufferObject::unbindBase(GLenum target,GLuint index) const{ glBindBufferBase(target,index,0); + if(data){ + data->isBound = false; + } } void ofBufferObject::bindRange(GLenum target,GLuint index, GLintptr offset, GLsizeiptr size) const{ if(data){ glBindBufferRange(target,index,data->id,offset,size); data->lastTarget = target; + data->isBound = true; } } @@ -133,6 +142,10 @@ void ofBufferObject::updateData(GLintptr offset, GLsizeiptr bytes, const void * unbind(this->data->lastTarget); } +void ofBufferObject::updateData(GLsizeiptr bytes, const void * data){ + updateData(0,bytes,data); +} + #ifndef TARGET_OPENGLES void * ofBufferObject::map(GLenum access){ if(!this->data) return nullptr; @@ -144,13 +157,28 @@ void * ofBufferObject::map(GLenum access){ #endif /// --------| invariant: direct state access is not available + if(!data->isBound){ + // if the buffer wasn't already bound and the operation + // is one of unpack/pack buffer alternate between the 2 + // since the tipical use is to pack to copy to the buffer + // then unpack to copy from it. + // for more advanced usages one can just bind the buffer + // before mapping + if(data->lastTarget==GL_PIXEL_PACK_BUFFER){ + data->lastTarget = GL_PIXEL_UNPACK_BUFFER; + }else if(data->lastTarget == GL_PIXEL_UNPACK_BUFFER){ + data->lastTarget = GL_PIXEL_PACK_BUFFER; + } + glBindBuffer(data->lastTarget, data->id); + } + + auto ret = glMapBuffer(data->lastTarget,access); - if(data->lastTarget==GL_PIXEL_PACK_BUFFER){ - bind(GL_PIXEL_UNPACK_BUFFER); - }else{ - bind(data->lastTarget); + if(!data->isBound){ + unbind(data->lastTarget); } - return glMapBuffer(data->lastTarget,access); + + return ret; } void ofBufferObject::unmap(){ @@ -164,9 +192,15 @@ void ofBufferObject::unmap(){ #endif /// --------| invariant: direct state access is not available + if(!data->isBound){ + glBindBuffer(data->lastTarget, data->id); + } glUnmapBuffer(data->lastTarget); - unbind(data->lastTarget); + + if(!data->isBound){ + unbind(data->lastTarget); + } } void * ofBufferObject::mapRange(GLintptr offset, GLsizeiptr length, GLenum access){ diff --git a/libs/openFrameworks/gl/ofBufferObject.h b/libs/openFrameworks/gl/ofBufferObject.h index 0e3900c220d..a89c74b7703 100644 --- a/libs/openFrameworks/gl/ofBufferObject.h +++ b/libs/openFrameworks/gl/ofBufferObject.h @@ -65,6 +65,7 @@ class ofBufferObject { /// before GL 4.5 emulates glNamedBufferSubData by binding to last known target /// for this buffer uploading data to that target and unbinding again void updateData(GLintptr offset, GLsizeiptr bytes, const void * data); + void updateData(GLsizeiptr bytes, const void * data); /// typed version of setData, same functionality but guesses the size from the size /// of the passed vector and size of the type @@ -85,6 +86,13 @@ class ofBufferObject { updateData(offset,data.size()*sizeof(T),&data[0]); } + /// typed version of updateData, same functionality but guesses the size from the size + /// of the passed vector and size of the type + template + void updateData(const vector & data){ + updateData(0,data.size()*sizeof(T),&data[0]); + } + #ifndef TARGET_OPENGLES /// glMapNamedBuffer: https://www.opengl.org/sdk/docs/man4/html/glMapBuffer.xhtml /// before GL 4.5 emulates glMapNamedBuffer by binding to last known target @@ -131,6 +139,7 @@ class ofBufferObject { GLsizeiptr size; GLenum lastTarget; bool useDSA; + bool isBound; }; shared_ptr data; }; diff --git a/libs/openFrameworks/gl/ofFbo.cpp b/libs/openFrameworks/gl/ofFbo.cpp index 629bd082721..06e4e2e670b 100644 --- a/libs/openFrameworks/gl/ofFbo.cpp +++ b/libs/openFrameworks/gl/ofFbo.cpp @@ -90,11 +90,7 @@ ofFbo::Settings::Settings(std::shared_ptr renderer) { minFilter = GL_LINEAR; maxFilter = GL_LINEAR; numSamples = 0; - if(renderer){ - this->renderer = renderer; - }else{ - this->renderer = ofGetGLRenderer(); - } + this->renderer = renderer; } //-------------------------------------------------------------- @@ -296,6 +292,12 @@ ofFbo::ofFbo(const ofFbo & mom){ textures = mom.textures; dirty = mom.dirty; defaultTextureIndex = mom.defaultTextureIndex; + activeDrawBuffers = mom.activeDrawBuffers; + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } } //-------------------------------------------------------------- @@ -310,11 +312,11 @@ ofFbo & ofFbo::operator=(const ofFbo & mom){ fboTextures = mom.fboTextures; if(settings.numSamples){ retainFB(fboTextures); - } - if(mom.settings.depthStencilAsTexture){ - depthBufferTex = mom.depthBufferTex; - }else{ - depthBuffer = mom.depthBuffer; + } + if(mom.settings.depthStencilAsTexture){ + depthBufferTex = mom.depthBufferTex; + }else{ + depthBuffer = mom.depthBuffer; retainRB(depthBuffer); } stencilBuffer = mom.stencilBuffer; @@ -327,9 +329,71 @@ ofFbo & ofFbo::operator=(const ofFbo & mom){ textures = mom.textures; dirty = mom.dirty; defaultTextureIndex = mom.defaultTextureIndex; + activeDrawBuffers = mom.activeDrawBuffers; + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } return *this; } +ofFbo::ofFbo(ofFbo && mom) +:settings(std::move(mom.settings)) +,fbo(mom.fbo) +,fboTextures(mom.fboTextures) +,depthBuffer(mom.depthBuffer) +,stencilBuffer(mom.stencilBuffer) +,colorBuffers(std::move(mom.colorBuffers)) +,textures(std::move(mom.textures)) +,depthBufferTex(std::move(mom.depthBufferTex)) +,activeDrawBuffers(std::move(mom.activeDrawBuffers)) +,dirty(std::move(mom.dirty)) +,defaultTextureIndex(std::move(mom.defaultTextureIndex)) +,bIsAllocated(std::move(mom.bIsAllocated)){ + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } + mom.fbo = 0; + mom.depthBuffer = 0; + mom.fboTextures = 0; + mom.stencilBuffer = 0; +} + +ofFbo & ofFbo::operator=(ofFbo && mom){ + if(&mom==this) return *this; + clear(); + settings = std::move(mom.settings); + bIsAllocated = std::move(mom.bIsAllocated); + + fbo = mom.fbo; + fboTextures = mom.fboTextures; + if(mom.settings.depthStencilAsTexture){ + depthBufferTex = std::move(mom.depthBufferTex); + }else{ + depthBuffer = mom.depthBuffer; + } + stencilBuffer = std::move(mom.stencilBuffer); + + colorBuffers = std::move(mom.colorBuffers); + textures = std::move(mom.textures); + dirty = std::move(mom.dirty); + defaultTextureIndex = std::move(mom.defaultTextureIndex); + + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } + mom.fbo = 0; + mom.depthBuffer = 0; + mom.fboTextures = 0; + mom.stencilBuffer = 0; + return *this; +} + //-------------------------------------------------------------- ofFbo::~ofFbo(){ clear(); @@ -455,7 +519,12 @@ void ofFbo::allocate(Settings _settings) { if(!checkGLSupport()) return; clear(); - settings.renderer = _settings.renderer; + auto renderer = _settings.renderer.lock(); + if(renderer){ + settings.renderer = renderer; + }else{ + settings.renderer = ofGetGLRenderer(); + } // check that passed values are correct if(_settings.width <= 0 || _settings.height <= 0){ @@ -635,7 +704,11 @@ GLuint ofFbo::createAndAttachRenderbuffer(GLenum internalFormat, GLenum attachme glRenderbufferStorageMultisample(GL_RENDERBUFFER, settings.numSamples, internalFormat, settings.width, settings.height); } #else - glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, ofNextPow2(settings.width), ofNextPow2(settings.height)); + if(ofGLSupportsNPOTTextures()){ + glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height); + }else{ + glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, ofNextPow2(settings.width), ofNextPow2(settings.height)); + } #endif glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER, buffer); return buffer; @@ -935,6 +1008,18 @@ void ofFbo::readToPixels(ofFloatPixels & pixels, int attachmentPoint) const{ #endif } +#ifndef TARGET_OPENGLES +//---------------------------------------------------------- +void ofFbo::copyTo(ofBufferObject & buffer) const{ + if(!bIsAllocated) return; + bind(); + buffer.bind(GL_PIXEL_PACK_BUFFER); + glReadPixels(0, 0, settings.width, settings.height, ofGetGLFormatFromInternal(settings.internalformat), ofGetGlTypeFromInternal(settings.internalformat), NULL); + buffer.unbind(GL_PIXEL_PACK_BUFFER); + unbind(); +} +#endif + //---------------------------------------------------------- void ofFbo::updateTexture(int attachmentPoint) { if(!bIsAllocated) return; diff --git a/libs/openFrameworks/gl/ofFbo.h b/libs/openFrameworks/gl/ofFbo.h index 1e1006ea6b0..1e12f7dfdc7 100644 --- a/libs/openFrameworks/gl/ofFbo.h +++ b/libs/openFrameworks/gl/ofFbo.h @@ -10,6 +10,8 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { ofFbo(); ofFbo(const ofFbo & mom); ofFbo & operator=(const ofFbo & fbo); + ofFbo(ofFbo && mom); + ofFbo & operator=(ofFbo && fbo); virtual ~ofFbo(); void allocate(int width, int height, int internalformat = GL_RGBA, int numSamples = 0); @@ -41,7 +43,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { const ofTexture & getTexture() const ; const ofTexture & getTexture(int attachmentPoint) const; const ofTexture & getDepthTexture() const; - void setUseTexture(bool bUseTex){ /*irrelevant*/ }; + void setUseTexture(bool){ /*irrelevant*/ }; bool isUsingTexture() const {return true;} /// \brief Sets up the framebuffer and binds it for rendering. @@ -61,6 +63,12 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { void readToPixels(ofShortPixels & pixels, int attachmentPoint = 0) const; void readToPixels(ofFloatPixels & pixels, int attachmentPoint = 0) const; +#ifndef TARGET_OPENGLES + /// \brief Copy the fbo to an ofBufferObject. + /// \param buffer the target buffer to copy to. + void copyTo(ofBufferObject & buffer) const; +#endif + float getWidth() const; float getHeight() const; diff --git a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp index 554b76d1320..52f4ca9365d 100644 --- a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp +++ b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp @@ -73,11 +73,8 @@ ofGLProgrammableRenderer::ofGLProgrammableRenderer(const ofAppBaseWindow * _wind currentFramebufferId = 0; defaultFramebufferId = 0; - -} - -ofGLProgrammableRenderer::~ofGLProgrammableRenderer() { - + path.setMode(ofPath::POLYLINES); + path.setUseShapeColor(false); } //---------------------------------------------------------- @@ -429,14 +426,14 @@ void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int firs } //---------------------------------------------------------- -void ofGLProgrammableRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt) const{ +void ofGLProgrammableRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const{ if(vbo.getUsingVerts()) { vbo.bind(); const_cast(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals()); #ifdef TARGET_OPENGLES - glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, nullptr); + glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void*)(sizeof(ofIndexType) * offsetelements)); #else - glDrawElements(drawMode, amt, GL_UNSIGNED_INT, nullptr); + glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void*)(sizeof(ofIndexType) * offsetelements)); #endif vbo.unbind(); } @@ -664,8 +661,10 @@ void ofGLProgrammableRenderer::setCircleResolution(int res){ circleMesh.getVertices() = circlePolyline.getVertices(); path.setCircleResolution(res); } + currentStyle.circleResolution = res; } +//---------------------------------------------------------- void ofGLProgrammableRenderer::setPolyMode(ofPolyWindingMode mode){ currentStyle.polyMode = mode; path.setPolyWindingMode(mode); @@ -806,6 +805,7 @@ void ofGLProgrammableRenderer::uploadCurrentMatrix(){ } +//---------------------------------------------------------- ofMatrix4x4 ofGLProgrammableRenderer::getCurrentMatrix(ofMatrixMode matrixMode_) const { switch (matrixMode_) { case OF_MATRIX_MODELVIEW: @@ -847,7 +847,7 @@ void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b){ void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b, int _a){ ofColor newColor(_r,_g,_b,_a); if(newColor!=currentStyle.color){ - currentStyle.color = newColor; + currentStyle.color = newColor; if(currentShader){ currentShader->setUniform4f(COLOR_UNIFORM,_r/255.,_g/255.,_b/255.,_a/255.); } @@ -1127,7 +1127,7 @@ void ofGLProgrammableRenderer::pushStyle(){ void ofGLProgrammableRenderer::popStyle(){ if( styleHistory.size() ){ - setStyle(styleHistory.front()); + setStyle(styleHistory.back()); styleHistory.pop_back(); } } @@ -1218,7 +1218,7 @@ void ofGLProgrammableRenderer::enableTextureTarget(const ofTexture & tex, int te } if((currentTextureTarget!=OF_NO_TEXTURE) && currentShader){ - currentShader->setUniformTexture("src_tex_unit"+ofToString(textureLocation),tex.texData.textureTarget,tex.texData.textureID,textureLocation); + currentShader->setUniformTexture("src_tex_unit"+ofToString(textureLocation),tex,textureLocation); } } @@ -1268,9 +1268,9 @@ void ofGLProgrammableRenderer::disableAlphaMask(){ //---------------------------------------------------------- void ofGLProgrammableRenderer::bind(const ofShader & shader){ - if(currentShader && *currentShader==shader){ + if(currentShader && *currentShader==shader){ return; - } + } glUseProgram(shader.getProgram()); currentShader = &shader; @@ -1315,8 +1315,8 @@ void ofGLProgrammableRenderer::end(const ofFbo & fbo){ //---------------------------------------------------------- void ofGLProgrammableRenderer::bind(const ofFbo & fbo){ if (currentFramebufferId == fbo.getId()){ - ofLogWarning() << "Framebuffer with id:" << " cannot be bound onto itself. \n" << - "Most probably you forgot to end() the current framebuffer before calling begin() again."; + ofLogWarning() << "Framebuffer with id: " << fbo.getId() << " cannot be bound onto itself. \n" << + "Most probably you forgot to end() the current framebuffer before calling begin() again or you forgot to allocate() before calling begin()."; return; } // this method could just as well have been placed in ofBaseGLRenderer @@ -1333,7 +1333,7 @@ void ofGLProgrammableRenderer::bind(const ofFbo & fbo){ //---------------------------------------------------------- void ofGLProgrammableRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint){ if (currentFramebufferId == fboSrc.getId()){ - ofLogWarning() << "Framebuffer with id:" << " cannot be bound onto itself. \n" << + ofLogWarning() << "Framebuffer with id: " << fboSrc.getId() << " cannot be bound onto itself. \n" << "Most probably you forgot to end() the current framebuffer before calling getTexture()."; return; } @@ -1366,12 +1366,41 @@ void ofGLProgrammableRenderer::unbind(const ofFbo & fbo){ //---------------------------------------------------------- void ofGLProgrammableRenderer::bind(const ofBaseMaterial & material){ - currentMaterial = &material; + currentMaterial = &material; + // FIXME: this invalidates the previous shader to avoid that + // when binding 2 materials one after another, the second won't + // get the right parameters. + currentShader = nullptr; + beginDefaultShader(); } //---------------------------------------------------------- -void ofGLProgrammableRenderer::unbind(const ofBaseMaterial & material){ - currentMaterial = nullptr; +void ofGLProgrammableRenderer::unbind(const ofBaseMaterial &){ + currentMaterial = nullptr; +} + +//---------------------------------------------------------- +void ofGLProgrammableRenderer::enableLighting(){ + +} + +//---------------------------------------------------------- +void ofGLProgrammableRenderer::disableLighting(){ +} + +//---------------------------------------------------------- +void ofGLProgrammableRenderer::enableLight(int){ + +} + +//---------------------------------------------------------- +void ofGLProgrammableRenderer::disableLight(int){ + +} + +//---------------------------------------------------------- +bool ofGLProgrammableRenderer::getLightingEnabled(){ + return true; } //---------------------------------------------------------- @@ -1469,9 +1498,9 @@ void ofGLProgrammableRenderer::beginDefaultShader(){ const ofShader * nextShader = nullptr; if(!uniqueShader || currentMaterial){ - if(currentMaterial){ + if(currentMaterial){ nextShader = ¤tMaterial->getShader(currentTextureTarget,*this); - currentMaterial->updateMaterial(*nextShader,*this); + }else if(bitmapStringEnabled){ nextShader = &bitmapStringShader; @@ -1488,6 +1517,11 @@ void ofGLProgrammableRenderer::beginDefaultShader(){ case OF_NO_TEXTURE: nextShader = &defaultNoTexColor; break; + #ifdef TARGET_ANDROID + case GL_TEXTURE_EXTERNAL_OES: + nextShader = &defaultOESTexColor; + break; + #endif } }else if(colorsEnabled){ @@ -1506,6 +1540,11 @@ void ofGLProgrammableRenderer::beginDefaultShader(){ case OF_NO_TEXTURE: nextShader = &defaultNoTexNoColor; break; + #ifdef TARGET_ANDROID + case GL_TEXTURE_EXTERNAL_OES: + nextShader = &defaultOESTexNoColor; + break; + #endif } }else{ @@ -1517,7 +1556,7 @@ void ofGLProgrammableRenderer::beginDefaultShader(){ } if(nextShader){ - if(!currentShader || *currentShader!=*nextShader){ + if(!currentShader || *currentShader!=*nextShader){ settingDefaultShader = true; bind(*nextShader); settingDefaultShader = false; @@ -1794,12 +1833,14 @@ void ofGLProgrammableRenderer::drawString(const ofTrueTypeFont & font, string te #ifdef TARGET_OPENGLES static const string vertex_shader_header = + "%extensions%\n" "precision mediump float;\n" "#define IN attribute\n" "#define OUT varying\n" "#define TEXTURE texture2D\n" "#define TARGET_OPENGLES\n"; static const string fragment_shader_header = + "%extensions%\n" "precision mediump float;\n" "#define IN varying\n" "#define OUT\n" @@ -1947,13 +1988,48 @@ static const string defaultFragmentShaderTex2DNoColor = fragment_shader_header + uniform float usingTexture; uniform float usingColors; uniform vec4 globalColor; + + IN float depth; + IN vec4 colorVarying; + IN vec2 texCoordVarying; + void main(){ + FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor; + } +); + +// ---------------------------------------------------------------------- + +static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header + STRINGIFY( + + uniform samplerExternalOES src_tex_unit0; + uniform float usingTexture; + uniform float usingColors; + uniform vec4 globalColor; + + IN float depth; + IN vec4 colorVarying; + IN vec2 texCoordVarying; + + void main(){ + FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor; + } +); + +// ---------------------------------------------------------------------- + +static const string defaultFragmentShaderOESTexColor = fragment_shader_header + STRINGIFY( + + uniform samplerExternalOES src_tex_unit0; + uniform float usingTexture; + uniform float usingColors; + uniform vec4 globalColor; IN float depth; IN vec4 colorVarying; IN vec2 texCoordVarying; void main(){ - FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor; + FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying; } ); @@ -2058,7 +2134,7 @@ static const string uniqueVertexShader = vertex_shader_header + STRINGIFY( void main(){ gl_Position = modelViewProjectionMatrix * position; if(usingTexture>.5) texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy; - if(usingColors>.5) colorVarying = color*globalColor; + if(usingColors>.5) colorVarying = color; else colorVarying = globalColor; } ); @@ -2192,6 +2268,8 @@ static string defaultShaderHeader(string header, GLenum textureTarget, int major }else{ ofStringReplace(header,"%extensions%",""); } +#else + ofStringReplace(header,"%extensions%",""); #endif if(textureTarget==GL_TEXTURE_2D){ header += "#define SAMPLER sampler2D\n"; @@ -2211,10 +2289,21 @@ static string shaderSource(const string & src, int major, int minor){ }else{ ofStringReplace(shaderSrc,"%extensions%",""); } +#else + ofStringReplace(shaderSrc,"%extensions%",""); #endif return shaderSrc; } +#ifdef TARGET_ANDROID +static string shaderOESSource(const string & src, int major, int minor){ + string shaderSrc = src; + ofStringReplace(shaderSrc,"%glsl_version%",ofGLSLVersionFromGL(major,minor)); + ofStringReplace(shaderSrc,"%extensions%","#extension GL_OES_EGL_image_external : require"); + return shaderSrc; +} +#endif + static string videoFragmentShaderSource(const ofBaseVideoDraws & video, int major, int minor){ string src; switch(video.getPixelFormat()){ @@ -2355,6 +2444,20 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor){ bitmapStringShader.bindDefaults(); bitmapStringShader.linkProgram(); + + +#ifdef TARGET_ANDROID + defaultOESTexNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor)); + defaultOESTexColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor)); + defaultOESTexColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexColor,major, minor)); + defaultOESTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexNoColor,major, minor)); + + defaultOESTexColor.bindDefaults(); + defaultOESTexNoColor.bindDefaults(); + + defaultOESTexColor.linkProgram(); + defaultOESTexNoColor.linkProgram(); +#endif } setupGraphicDefaults(); @@ -2552,6 +2655,7 @@ void ofGLProgrammableRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels.allocate(w, h, OF_PIXELS_RGBA); switch(matrixStack.getOrientation()){ + case OF_ORIENTATION_UNKNOWN: case OF_ORIENTATION_DEFAULT: if(isVFlipped()){ diff --git a/libs/openFrameworks/gl/ofGLProgrammableRenderer.h b/libs/openFrameworks/gl/ofGLProgrammableRenderer.h index a545e43c6ee..2814f6d0dde 100644 --- a/libs/openFrameworks/gl/ofGLProgrammableRenderer.h +++ b/libs/openFrameworks/gl/ofGLProgrammableRenderer.h @@ -8,19 +8,18 @@ #include "of3dGraphics.h" #include "ofBitmapFont.h" #include "ofPath.h" +#include "ofMaterial.h" class ofShapeTessellation; class ofMesh; class ofFbo; class ofVbo; -class ofMaterial; static const int OF_NO_TEXTURE=-1; class ofGLProgrammableRenderer: public ofBaseGLRenderer{ public: - ofGLProgrammableRenderer(const ofAppBaseWindow * window); - ~ofGLProgrammableRenderer(); + ofGLProgrammableRenderer(const ofAppBaseWindow * window); void setup(int glVersionMajor, int glVersionMinor); @@ -43,7 +42,7 @@ class ofGLProgrammableRenderer: public ofBaseGLRenderer{ void draw(const ofTexture & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const; void draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const; void draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const; - void drawElements(const ofVbo & vbo, GLuint drawMode, int amt) const; + void drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements = 0) const; void drawInstanced(const ofVbo & vbo, GLuint drawMode, int first, int total, int primCount) const; void drawElementsInstanced(const ofVbo & vbo, GLuint drawMode, int amt, int primCount) const; void draw(const ofVboMesh & mesh, ofPolyRenderMode renderType) const; @@ -208,15 +207,15 @@ class ofGLProgrammableRenderer: public ofBaseGLRenderer{ const ofShader * getVideoShader(const ofBaseVideoDraws & video) const; void setVideoShaderUniforms(const ofBaseVideoDraws & video, const ofShader & shader) const; - void enableLighting(){}; - void disableLighting(){}; - void enableSeparateSpecularLight(){}; - void disableSeparateSpecularLight(){} - bool getLightingEnabled(){return true;} + void enableLighting(); + void disableLighting(); + bool getLightingEnabled(); + void enableSeparateSpecularLight(){} + void disableSeparateSpecularLight(){} void setSmoothLighting(bool b){} void setGlobalAmbientColor(const ofColor& c){} - void enableLight(int lightIndex){} - void disableLight(int lightIndex){} + void enableLight(int lightIndex); + void disableLight(int lightIndex); void setLightSpotlightCutOff(int lightIndex, float spotCutOff){} void setLightSpotConcentration(int lightIndex, float exponent){} void setLightAttenuation(int lightIndex, float constant, float linear, float quadratic ){} @@ -292,10 +291,17 @@ class ofGLProgrammableRenderer: public ofBaseGLRenderer{ ofShader defaultTex2DNoColor; ofShader defaultNoTexColor; ofShader defaultNoTexNoColor; + ofShader defaultUniqueShader; +#ifdef TARGET_ANDROID + ofShader defaultOESTexColor; + ofShader defaultOESTexNoColor; +#endif + ofShader alphaMaskRectShader; ofShader alphaMask2DShader; + ofShader bitmapStringShader; - ofShader defaultUniqueShader; + ofShader shaderPlanarYUY2; ofShader shaderNV12; ofShader shaderNV21; @@ -315,6 +321,5 @@ class ofGLProgrammableRenderer: public ofBaseGLRenderer{ // framebuffer binding state deque framebufferIdStack; ///< keeps track of currently bound framebuffers GLuint defaultFramebufferId; ///< default GL_FRAMEBUFFER_BINDING, windowing frameworks might want to set this to their MSAA framebuffer, defaults to 0 - GLuint currentFramebufferId; ///< the framebuffer id currently bound to the GL_FRAMEBUFFER target - + GLuint currentFramebufferId; ///< the framebuffer id currently bound to the GL_FRAMEBUFFER target }; diff --git a/libs/openFrameworks/gl/ofGLRenderer.cpp b/libs/openFrameworks/gl/ofGLRenderer.cpp index db4af3d6757..a9efe29789f 100644 --- a/libs/openFrameworks/gl/ofGLRenderer.cpp +++ b/libs/openFrameworks/gl/ofGLRenderer.cpp @@ -26,10 +26,13 @@ ofGLRenderer::ofGLRenderer(const ofAppBaseWindow * _window) triPoints.resize(3); normalsEnabled = false; lightingEnabled = false; + materialBound = false; alphaMaskTextureTarget = GL_TEXTURE_2D; window = _window; currentFramebufferId = 0; defaultFramebufferId = 0; + path.setMode(ofPath::POLYLINES); + path.setUseShapeColor(false); } void ofGLRenderer::setup(){ @@ -91,15 +94,20 @@ void ofGLRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode renderType, } if(vertexData.getNumTexCoords() && useTextures){ - set::iterator textureLocation = textureLocationsEnabled.begin(); - for(;textureLocation!=textureLocationsEnabled.end();textureLocation++){ - glActiveTexture(GL_TEXTURE0+*textureLocation); - glClientActiveTexture(GL_TEXTURE0+*textureLocation); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); - } - glActiveTexture(GL_TEXTURE0); - glClientActiveTexture(GL_TEXTURE0); + if(textureLocationsEnabled.size() == 0){ + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); + }else{ + set::iterator textureLocation = textureLocationsEnabled.begin(); + for(;textureLocation!=textureLocationsEnabled.end();textureLocation++){ + glActiveTexture(GL_TEXTURE0+*textureLocation); + glClientActiveTexture(GL_TEXTURE0+*textureLocation); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); + } + glActiveTexture(GL_TEXTURE0); + glClientActiveTexture(GL_TEXTURE0); + } } if(vertexData.getNumIndices()){ @@ -137,15 +145,20 @@ void ofGLRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode renderType, } if(vertexData.getNumTexCoords() && useTextures){ - set::iterator textureLocation = textureLocationsEnabled.begin(); - for(;textureLocation!=textureLocationsEnabled.end();textureLocation++){ - glActiveTexture(GL_TEXTURE0+*textureLocation); - glClientActiveTexture(GL_TEXTURE0+*textureLocation); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); - } - glActiveTexture(GL_TEXTURE0); - glClientActiveTexture(GL_TEXTURE0); + if(textureLocationsEnabled.size() == 0){ + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); + }else{ + set::iterator textureLocation = textureLocationsEnabled.begin(); + for(;textureLocation!=textureLocationsEnabled.end();textureLocation++){ + glActiveTexture(GL_TEXTURE0+*textureLocation); + glClientActiveTexture(GL_TEXTURE0+*textureLocation); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(ofVec2f), &vertexData.getTexCoordsPointer()->x); + } + glActiveTexture(GL_TEXTURE0); + glClientActiveTexture(GL_TEXTURE0); + } } GLenum drawMode; @@ -363,13 +376,13 @@ void ofGLRenderer::draw(const ofVbo & vbo, GLuint drawMode, int first, int total } //---------------------------------------------------------- -void ofGLRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt) const{ +void ofGLRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const{ if(vbo.getUsingVerts()) { vbo.bind(); #ifdef TARGET_OPENGLES - glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, nullptr); + glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void*)(sizeof(ofIndexType) * offsetelements)); #else - glDrawElements(drawMode, amt, GL_UNSIGNED_INT, nullptr); + glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void*)(sizeof(ofIndexType) * offsetelements)); #endif vbo.unbind(); } @@ -472,8 +485,8 @@ void ofGLRenderer::end(const ofFbo & fbo){ //---------------------------------------------------------- void ofGLRenderer::bind(const ofFbo & fbo){ if (currentFramebufferId == fbo.getId()){ - ofLogWarning() << "Framebuffer with id:" << " cannot be bound onto itself. \n" << - "Most probably you forgot to end() the current framebuffer before calling begin() again."; + ofLogWarning() << "Framebuffer with id: " << fbo.getId() << " cannot be bound onto itself. \n" << + "Most probably you forgot to end() the current framebuffer before calling begin() again or you forgot to allocate() before calling begin()."; return; } // this method could just as well have been placed in ofBaseGLRenderer @@ -490,7 +503,7 @@ void ofGLRenderer::bind(const ofFbo & fbo){ //---------------------------------------------------------- void ofGLRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint){ if (currentFramebufferId == fboSrc.getId()){ - ofLogWarning() << "Framebuffer with id:" << " cannot be bound onto itself. \n" << + ofLogWarning() << "Framebuffer with id: " << fboSrc.getId() << " cannot be bound onto itself. \n" << "Most probably you forgot to end() the current framebuffer before calling getTexture()."; return; } @@ -527,53 +540,59 @@ void ofGLRenderer::bind(const ofBaseMaterial & material){ ofFloatColor specular = material.getSpecularColor(); ofFloatColor ambient = material.getAmbientColor(); ofFloatColor emissive = material.getEmissiveColor(); - float shininess = material.getShininess(); + float shininess = material.getShininess(); + glDisable(GL_COLOR_MATERIAL); #ifndef TARGET_OPENGLES - // Material colors and properties + // Material colors and properties glMaterialfv(GL_FRONT, GL_DIFFUSE, &diffuse.r); glMaterialfv(GL_FRONT, GL_SPECULAR, &specular.r); glMaterialfv(GL_FRONT, GL_AMBIENT, &ambient.r); glMaterialfv(GL_FRONT, GL_EMISSION, &emissive.r); - glMaterialfv(GL_FRONT, GL_SHININESS, &shininess); + glMaterialfv(GL_FRONT, GL_SHININESS, &shininess); glMaterialfv(GL_BACK, GL_DIFFUSE, &diffuse.r); glMaterialfv(GL_BACK, GL_SPECULAR, &specular.r); glMaterialfv(GL_BACK, GL_AMBIENT, &ambient.r); glMaterialfv(GL_BACK, GL_EMISSION, &emissive.r); - glMaterialfv(GL_BACK, GL_SHININESS, &shininess); -#elif !defined(TARGET_PROGRAMMABLE_GL) - + glMaterialfv(GL_BACK, GL_SHININESS, &shininess); +#else glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shininess); #endif + materialBound = true; } //---------------------------------------------------------- -void ofGLRenderer::unbind(const ofBaseMaterial & material){ +void ofGLRenderer::unbind(const ofBaseMaterial &){ // Set default material colors and properties ofMaterial::Data defaultData; #ifndef TARGET_OPENGLES - glMaterialfv(GL_FRONT, GL_DIFFUSE, &defaultData.diffuse.r); + glMaterialfv(GL_FRONT, GL_DIFFUSE, &defaultData.diffuse.r); glMaterialfv(GL_FRONT, GL_SPECULAR, &defaultData.specular.r); - glMaterialfv(GL_FRONT, GL_AMBIENT, &defaultData.ambient.r); + glMaterialfv(GL_FRONT, GL_AMBIENT, &defaultData.ambient.r); glMaterialfv(GL_FRONT, GL_EMISSION, &defaultData.emissive.r); glMaterialfv(GL_FRONT, GL_SHININESS, &defaultData.shininess); - glMaterialfv(GL_BACK, GL_DIFFUSE, &defaultData.diffuse.r); + glMaterialfv(GL_BACK, GL_DIFFUSE, &defaultData.diffuse.r); glMaterialfv(GL_BACK, GL_SPECULAR, &defaultData.specular.r); - glMaterialfv(GL_BACK, GL_AMBIENT, &defaultData.ambient.r); + glMaterialfv(GL_BACK, GL_AMBIENT, &defaultData.ambient.r); glMaterialfv(GL_BACK, GL_EMISSION, &defaultData.emissive.r); - glMaterialfv(GL_BACK, GL_SHININESS, &defaultData.shininess); + glMaterialfv(GL_BACK, GL_SHININESS, &defaultData.shininess); #else glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &defaultData.diffuse.r); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &defaultData.specular.r); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &defaultData.ambient.r); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &defaultData.emissive.r); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &defaultData.shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &defaultData.shininess); #endif + // Re-enable global color as material ambient and diffuse + materialBound = false; + if(lightingEnabled){ + setColor(currentStyle.color); + } } //---------------------------------------------------------- @@ -628,7 +647,7 @@ void ofGLRenderer::bind(const ofCamera & camera, const ofRectangle & _viewport){ viewport(_viewport); setOrientation(matrixStack.getOrientation(),camera.isVFlipped()); matrixMode(OF_MATRIX_PROJECTION); - loadMatrix(camera.getProjectionMatrix(_viewport).getPtr()); + loadMatrix(camera.getProjectionMatrix(_viewport)); matrixMode(OF_MATRIX_MODELVIEW); loadViewMatrix(camera.getModelViewMatrix()); } @@ -825,6 +844,7 @@ void ofGLRenderer::setCircleResolution(int res){ circlePoints.resize(circlePolyline.size()); path.setCircleResolution(res); } + currentStyle.circleResolution = res; } void ofGLRenderer::setPolyMode(ofPolyWindingMode mode){ @@ -984,6 +1004,9 @@ void ofGLRenderer::loadViewMatrix(const ofMatrix4x4 & m){ shared_ptr lightData = ofLightsData()[i].lock(); if(lightData && lightData->isEnabled){ glLightfv(GL_LIGHT0 + lightData->glIndex, GL_POSITION, &lightData->position.x); + if(lightData->lightType == OF_LIGHT_SPOT || lightData->lightType == OF_LIGHT_AREA) { + glLightfv(GL_LIGHT0 + lightData->glIndex, GL_SPOT_DIRECTION, &lightData->direction.x); + } } } } @@ -1016,15 +1039,31 @@ void ofGLRenderer::setColor(const ofColor & color, int _a){ //---------------------------------------------------------- void ofGLRenderer::setColor(int r, int g, int b){ - currentStyle.color.set(r,g,b); - glColor4f(r/255.f,g/255.f,b/255.f,1.f); + currentStyle.color.set(r,g,b); + glColor4f(r/255.f,g/255.f,b/255.f,1.f); + if(lightingEnabled && !materialBound){ + glEnable(GL_COLOR_MATERIAL); + #ifndef TARGET_OPENGLES + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glColorMaterial(GL_BACK, GL_AMBIENT_AND_DIFFUSE); + #endif + glEnable(GL_COLOR_MATERIAL); + } } //---------------------------------------------------------- void ofGLRenderer::setColor(int r, int g, int b, int a){ - currentStyle.color.set(r,g,b,a); - glColor4f(r/255.f,g/255.f,b/255.f,a/255.f); + currentStyle.color.set(r,g,b,a); + glColor4f(r/255.f,g/255.f,b/255.f,a/255.f); + if(lightingEnabled && !materialBound){ + glEnable(GL_COLOR_MATERIAL); + #ifndef TARGET_OPENGLES + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glColorMaterial(GL_BACK, GL_AMBIENT_AND_DIFFUSE); + #endif + glEnable(GL_COLOR_MATERIAL); + } } //---------------------------------------------------------- @@ -1251,14 +1290,17 @@ void ofGLRenderer::setBlendMode(ofBlendMode blendMode){ currentStyle.blendingMode = blendMode; } +//---------------------------------------------------------- void ofGLRenderer::setBitmapTextMode(ofDrawBitmapMode mode){ currentStyle.drawBitmapMode = mode; } +//---------------------------------------------------------- ofStyle ofGLRenderer::getStyle() const{ return currentStyle; } +//---------------------------------------------------------- void ofGLRenderer::pushStyle(){ styleHistory.push_back(currentStyle); //if we are over the max number of styles we have set, then delete the oldest styles. @@ -1269,13 +1311,15 @@ void ofGLRenderer::pushStyle(){ } } +//---------------------------------------------------------- void ofGLRenderer::popStyle(){ if( styleHistory.size() ){ - setStyle(styleHistory.front()); + setStyle(styleHistory.back()); styleHistory.pop_back(); } } +//---------------------------------------------------------- void ofGLRenderer::setStyle(const ofStyle & style){ //color setColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a); @@ -1319,6 +1363,7 @@ void ofGLRenderer::setStyle(const ofStyle & style){ currentStyle = style; } +//---------------------------------------------------------- void ofGLRenderer::setCurveResolution(int resolution){ currentStyle.curveResolution = resolution; path.setCurveResolution(resolution); @@ -1663,6 +1708,11 @@ void ofGLRenderer::enableTextureTarget(const ofTexture & tex, int textureLocatio glClientActiveTexture(GL_TEXTURE0+textureLocation); glEnable( tex.getTextureData().textureTarget); glBindTexture( tex.getTextureData().textureTarget, (GLuint)tex.getTextureData().textureID); +#ifndef TARGET_OPENGLES + if(tex.getTextureData().bufferId!=0){ + glTexBuffer(GL_TEXTURE_BUFFER, tex.getTextureData().glInternalFormat, tex.getTextureData().bufferId); + } +#endif textureLocationsEnabled.insert(textureLocation); } @@ -1675,30 +1725,45 @@ void ofGLRenderer::disableTextureTarget(int textureTarget, int textureLocation){ textureLocationsEnabled.erase(textureLocation); } +//---------------------------------------------------------- void ofGLRenderer::setAlphaMaskTex(const ofTexture & tex){ enableTextureTarget(tex, 1); alphaMaskTextureTarget = tex.getTextureData().textureTarget; } +//---------------------------------------------------------- void ofGLRenderer::disableAlphaMask(){ disableTextureTarget(alphaMaskTextureTarget,1); } //---------------------------------------------------------- void ofGLRenderer::enableLighting(){ - glEnable(GL_LIGHTING); -#ifndef TARGET_OPENGLES //TODO: fix this - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); -#endif - glEnable(GL_COLOR_MATERIAL); - + glEnable(GL_LIGHTING); + lightingEnabled = true; + setColor(currentStyle.color); // FIXME: we do this so the 3d ofDraw* functions work with lighting // but if someone enables it between ofEnableLighting it'll be disabled // on ofDisableLighting. by now it seems the best option to not loose // performance when drawing lots of primitives normalsEnabled = glIsEnabled( GL_NORMALIZE ); - glEnable(GL_NORMALIZE); - lightingEnabled = true; + glEnable(GL_NORMALIZE); + + int matrixMode; + glGetIntegerv(GL_MATRIX_MODE,&matrixMode); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(matrixStack.getViewMatrix().getPtr()); + for(size_t i=0;i lightData = ofLightsData()[i].lock(); + if(lightData && lightData->isEnabled){ + glLightfv(GL_LIGHT0 + lightData->glIndex, GL_POSITION, &lightData->position.x); + if(lightData->lightType == OF_LIGHT_SPOT || lightData->lightType == OF_LIGHT_AREA) { + glLightfv(GL_LIGHT0 + lightData->glIndex, GL_SPOT_DIRECTION, &lightData->direction.x); + } + } + } + glPopMatrix(); + glMatrixMode(matrixMode); } //---------------------------------------------------------- @@ -1806,9 +1871,17 @@ void ofGLRenderer::setLightPosition(int lightIndex, const ofVec4f & position){ //---------------------------------------------------------- void ofGLRenderer::setLightSpotDirection(int lightIndex, const ofVec4f & direction){ if(lightIndex==-1) return; + int matrixMode; + glGetIntegerv(GL_MATRIX_MODE,&matrixMode); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(matrixStack.getViewMatrix().getPtr()); glLightfv(GL_LIGHT0 + lightIndex, GL_SPOT_DIRECTION, &direction.x); + glPopMatrix(); + glMatrixMode(matrixMode); } +//---------------------------------------------------------- int ofGLRenderer::getGLVersionMajor(){ #ifdef TARGET_OPENGLES return 1; @@ -1817,6 +1890,7 @@ int ofGLRenderer::getGLVersionMajor(){ #endif } +//---------------------------------------------------------- int ofGLRenderer::getGLVersionMinor(){ #ifdef TARGET_OPENGLES return 0; @@ -1825,12 +1899,13 @@ int ofGLRenderer::getGLVersionMinor(){ #endif } - +//---------------------------------------------------------- void ofGLRenderer::saveFullViewport(ofPixels & pixels){ ofRectangle v = getCurrentViewport(); saveScreen(v.x,v.y,v.width,v.height,pixels); } +//---------------------------------------------------------- void ofGLRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels){ int sh = getViewportHeight(); @@ -1865,6 +1940,7 @@ void ofGLRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels){ pixels.allocate(w, h, OF_PIXELS_RGBA); switch(matrixStack.getOrientation()){ + case OF_ORIENTATION_UNKNOWN: case OF_ORIENTATION_DEFAULT: if(isVFlipped()){ @@ -1922,10 +1998,12 @@ void ofGLRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels){ #endif } +//---------------------------------------------------------- const of3dGraphics & ofGLRenderer::get3dGraphics() const{ return graphics3d; } +//---------------------------------------------------------- of3dGraphics & ofGLRenderer::get3dGraphics(){ return graphics3d; } diff --git a/libs/openFrameworks/gl/ofGLRenderer.h b/libs/openFrameworks/gl/ofGLRenderer.h index c9aa4812de0..cf6babd9654 100644 --- a/libs/openFrameworks/gl/ofGLRenderer.h +++ b/libs/openFrameworks/gl/ofGLRenderer.h @@ -40,7 +40,7 @@ class ofGLRenderer: public ofBaseGLRenderer{ void draw(const ofTexture & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const; void draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const; void draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const; - void drawElements(const ofVbo & vbo, GLuint drawMode, int amt) const; + void drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements = 0) const; void drawInstanced(const ofVbo & vbo, GLuint drawMode, int first, int total, int primCount) const; void drawElementsInstanced(const ofVbo & vbo, GLuint drawMode, int amt, int primCount) const; void draw(const ofVboMesh & mesh, ofPolyRenderMode renderType) const; @@ -232,6 +232,7 @@ class ofGLRenderer: public ofBaseGLRenderer{ ofMatrixStack matrixStack; bool normalsEnabled; bool lightingEnabled; + bool materialBound; set textureLocationsEnabled; int alphaMaskTextureTarget; diff --git a/libs/openFrameworks/gl/ofGLUtils.cpp b/libs/openFrameworks/gl/ofGLUtils.cpp index 2ce901e6ca4..51dffe6fce7 100644 --- a/libs/openFrameworks/gl/ofGLUtils.cpp +++ b/libs/openFrameworks/gl/ofGLUtils.cpp @@ -683,6 +683,7 @@ void ofSetPixelStoreiAlignment(GLenum pname, int stride){ vector ofGLSupportedExtensions(){ +#ifdef TARGET_OPENGLES char* extensions = (char*)glGetString(GL_EXTENSIONS); if(extensions){ string extensions_str = extensions; @@ -690,10 +691,22 @@ vector ofGLSupportedExtensions(){ }else{ return vector(); } +#else + int numExtensions=0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + std::vector extensions; + for(int i=0;i extensionsList = ofGLSupportedExtensions(); set extensionsSet; extensionsSet.insert(extensionsList.begin(),extensionsList.end()); diff --git a/libs/openFrameworks/gl/ofGLUtils.h b/libs/openFrameworks/gl/ofGLUtils.h index 4c5939096c7..8e57b406eb7 100644 --- a/libs/openFrameworks/gl/ofGLUtils.h +++ b/libs/openFrameworks/gl/ofGLUtils.h @@ -75,7 +75,7 @@ int ofGetNumChannelsFromGLFormat(int glFormat); void ofSetPixelStoreiAlignment(GLenum pname, int w, int bpc, int numChannels); void ofSetPixelStoreiAlignment(GLenum panme, int stride); -//vector ofGLSupportedExtensions(); +vector ofGLSupportedExtensions(); bool ofGLCheckExtension(string searchName); bool ofGLSupportsNPOTTextures(); diff --git a/libs/openFrameworks/gl/ofLight.cpp b/libs/openFrameworks/gl/ofLight.cpp index 70ad784d162..3e13e09d25b 100644 --- a/libs/openFrameworks/gl/ofLight.cpp +++ b/libs/openFrameworks/gl/ofLight.cpp @@ -327,18 +327,15 @@ void ofLight::onPositionChanged() { //---------------------------------------- void ofLight::onOrientationChanged() { if(data->glIndex==-1) return; - // if we are a directional light and not positional, update light position (direction) if(getIsDirectional()) { - // (tig) takes into account global orientation should node be parented. - ofVec3f lookAtDir = ( getGlobalTransformMatrix().getInverse() * ofVec4f(0,0,-1, 1) ).getNormalized(); + // if we are a directional light and not positional, update light position (direction) + ofVec3f lookAtDir = ( ofVec4f(0,0,-1, 1) * getGlobalOrientation() ).getNormalized(); data->position = ofVec4f(lookAtDir.x,lookAtDir.y,lookAtDir.z,0); ofGetGLRenderer()->setLightPosition(data->glIndex,data->position); }else if(getIsSpotlight() || getIsAreaLight()) { - // determines the axis of the cone light // - - // (tig) takes into account global orientation should node be parented. - ofVec3f lookAtDir = ( getGlobalTransformMatrix().getInverse() * ofVec4f(0,0,-1, 1) ).getNormalized(); - data->direction = ofVec3f(lookAtDir.x,lookAtDir.y,lookAtDir.z); + // determines the axis of the cone light + ofVec3f lookAtDir = ( ofVec4f(0,0,-1, 1) * getGlobalOrientation() ).getNormalized(); + data->direction = lookAtDir; ofGetGLRenderer()->setLightSpotDirection(data->glIndex,data->direction); } if(getIsAreaLight()){ diff --git a/libs/openFrameworks/gl/ofMaterial.cpp b/libs/openFrameworks/gl/ofMaterial.cpp index ef3be0dccff..7617a8513ec 100644 --- a/libs/openFrameworks/gl/ofMaterial.cpp +++ b/libs/openFrameworks/gl/ofMaterial.cpp @@ -150,20 +150,20 @@ void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer void ofMaterial::updateLights(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{ for(size_t i=0;iisEnabled){ + shared_ptr light = ofLightsData()[i].lock(); + if(!light || !light->isEnabled){ shader.setUniform1f("lights["+idx+"].enabled",0); continue; } - shared_ptr light = ofLightsData()[i].lock(); ofVec4f lightEyePosition = light->position * renderer.getCurrentViewMatrix(); shader.setUniform1f("lights["+idx+"].enabled",1); shader.setUniform1f("lights["+idx+"].type", light->lightType); - shader.setUniform4fv("lights["+idx+"].position", &lightEyePosition.x); - shader.setUniform4fv("lights["+idx+"].ambient", &light->ambientColor.r); - shader.setUniform4fv("lights["+idx+"].specular", &light->specularColor.r); - shader.setUniform4fv("lights["+idx+"].diffuse", &light->diffuseColor.r); + shader.setUniform4f("lights["+idx+"].position", lightEyePosition); + shader.setUniform4f("lights["+idx+"].ambient", light->ambientColor); + shader.setUniform4f("lights["+idx+"].specular", light->specularColor); + shader.setUniform4f("lights["+idx+"].diffuse", light->diffuseColor); - if(light->lightType==OF_LIGHT_POINT || light->lightType==OF_LIGHT_AREA){ + if(light->lightType!=OF_LIGHT_DIRECTIONAL){ shader.setUniform1f("lights["+idx+"].constantAttenuation", light->attenuation_constant); shader.setUniform1f("lights["+idx+"].linearAttenuation", light->attenuation_linear); shader.setUniform1f("lights["+idx+"].quadraticAttenuation", light->attenuation_quadratic); @@ -173,34 +173,31 @@ void ofMaterial::updateLights(const ofShader & shader,ofGLProgrammableRenderer & ofVec3f direction = light->position + light->direction; direction = direction * renderer.getCurrentViewMatrix(); direction = direction - lightEyePosition; - shader.setUniform3fv("lights["+idx+"].spotDirection", &direction.x); + shader.setUniform3f("lights["+idx+"].spotDirection", direction.normalize()); shader.setUniform1f("lights["+idx+"].spotExponent", light->exponent); shader.setUniform1f("lights["+idx+"].spotCutoff", light->spotCutOff); shader.setUniform1f("lights["+idx+"].spotCosCutoff", cos(ofDegToRad(light->spotCutOff))); }else if(light->lightType==OF_LIGHT_DIRECTIONAL){ ofVec3f halfVector = (ofVec3f(0,0,1) + lightEyePosition).getNormalized(); - shader.setUniform3fv("lights["+idx+"].halfVector", &halfVector.x); + shader.setUniform3f("lights["+idx+"].halfVector", halfVector); }else if(light->lightType==OF_LIGHT_AREA){ shader.setUniform1f("lights["+idx+"].width", light->width); shader.setUniform1f("lights["+idx+"].height", light->height); ofVec3f direction = light->position + light->direction; direction = direction * renderer.getCurrentViewMatrix(); direction = direction - lightEyePosition; + shader.setUniform3f("lights["+idx+"].spotDirection", direction.normalize()); ofVec3f right = light->position + light->right; right = right * renderer.getCurrentViewMatrix(); right = right - lightEyePosition; ofVec3f up = right.getCrossed(direction); - shader.setUniform3fv("lights["+idx+"].spotDirection", &direction.x); - shader.setUniform3fv("lights["+idx+"].right", &right.x); - shader.setUniform3fv("lights["+idx+"].up", &up.x); + shader.setUniform3f("lights["+idx+"].right", right.normalize()); + shader.setUniform3f("lights["+idx+"].up", up.normalize()); } } } -#define STRINGIFY(x) #x - -static const string vertexShader = STRINGIFY( - OUT vec4 outColor; // this is the ultimate color for this vertex +static const string vertexShader = R"( OUT vec2 outtexcoord; // pass the texCoord if needed OUT vec3 transformedNormal; OUT vec3 eyePosition3; @@ -219,7 +216,6 @@ static const string vertexShader = STRINGIFY( void main (void){ - float alphaFade = 1.0; vec4 eyePosition = modelViewMatrix * position; vec3 tempNormal = (normalMatrix * normal).xyz; transformedNormal = normalize(tempNormal); @@ -228,15 +224,13 @@ static const string vertexShader = STRINGIFY( outtexcoord = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy; gl_Position = modelViewProjectionMatrix * position; } -); +)"; -static const string fragmentShader = STRINGIFY( - IN vec4 outColor; // this is the ultimate color for this vertex +static const string fragmentShader = R"( IN vec2 outtexcoord; // pass the texCoord if needed IN vec3 transformedNormal; // Eye-coordinate position of vertex - IN vec4 eyePosition; IN vec3 eyePosition3; @@ -308,23 +302,28 @@ static const string fragmentShader = STRINGIFY( // Normalize the vector from surface to light position VP = normalize(VP); halfVector = normalize(VP + eye); - - nDotVP = max(0.0, dot(normal, VP)); nDotHV = max(0.0, dot(normal, halfVector)); + nDotVP = max(0.0, dot(normal, VP)); + + ambient += light.ambient.rgb * attenuation; + diffuse += light.diffuse.rgb * nDotVP * attenuation; +#ifndef TARGET_OPENGLES +#define SPECULAR_REFLECTION +#endif +#ifndef SPECULAR_REFLECTION // ha! no branching :) - // fresnel factor, produces artifacts on spot lights + pf = mix(0.0, pow(nDotHV, mat_shininess), step(0.0000001, nDotVP)); + specular += light.specular.rgb * pf * nDotVP * attenuation; +#else + // fresnel factor // http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Specular_Highlights_at_Silhouettes - /*float w = pow(1.0 - max(0.0, dot(halfVector, VP)), 5.0); + float w = pow(1.0 - max(0.0, dot(halfVector, VP)), 5.0); vec3 specularReflection = attenuation * vec3(light.specular.rgb) * mix(vec3(mat_specular.rgb), vec3(1.0), w) * pow(nDotHV, mat_shininess); - specular += mix(vec3(0.0), specularReflection, step(0.0000001, nDotVP));*/ - pf = mix(0.0, pow(nDotHV, mat_shininess), step(0.0000001, nDotVP)); - - ambient += light.ambient.rgb * attenuation; - diffuse += light.diffuse.rgb * nDotVP * attenuation; - specular += light.specular.rgb * pf * nDotVP * attenuation; + specular += mix(vec3(0.0), specularReflection, step(0.0000001, nDotVP)); +#endif } void directionalLight(in lightData light, in vec3 normal, inout vec3 ambient, inout vec3 diffuse, inout vec3 specular){ @@ -343,25 +342,26 @@ static const string fragmentShader = STRINGIFY( } void spotLight(in lightData light, in vec3 normal, in vec3 ecPosition3, inout vec3 ambient, inout vec3 diffuse, inout vec3 specular){ - float nDotVP;// = max(dot(normal,normalize(vec3(light.position))),0.0); + float nDotVP; // = max(dot(normal,normalize(vec3(light.position))),0.0); float nDotHV; // normal . light half vector float pf; float d; // distance from surface to light source vec3 VP; // direction from surface to light position vec3 eye = vec3 (0.0, 0.0, 1.0); float spotEffect; - float attenuation; + float attenuation=1.0; vec3 halfVector; // direction of maximum highlights // Compute vector from surface to light position - VP = vec3 (light.position.xyz) - ecPosition3; - spotEffect = dot(normalize(light.spotDirection), -normalize(VP)); + VP = light.position.xyz - ecPosition3; + spotEffect = dot(light.spotDirection, -normalize(VP)); if (spotEffect > light.spotCosCutoff) { // Compute distance between surface and light position d = length(VP); spotEffect = pow(spotEffect, light.spotExponent); - attenuation = spotEffect / d; + attenuation = spotEffect / (light.constantAttenuation + light.linearAttenuation * d + light.quadraticAttenuation * d * d); + VP = normalize(VP); halfVector = normalize(VP + eye); nDotHV = max(0.0, dot(normal, halfVector)); nDotVP = max(0.0, dot(normal, VP)); @@ -370,9 +370,11 @@ static const string fragmentShader = STRINGIFY( diffuse += light.diffuse.rgb * nDotVP * attenuation; specular += light.specular.rgb * pf * nDotVP * attenuation; + } ambient += light.ambient.rgb * attenuation; + } @@ -385,9 +387,9 @@ static const string fragmentShader = STRINGIFY( } void areaLight(in lightData light, in vec3 N, in vec3 V, inout vec3 ambient, inout vec3 diffuse, inout vec3 specular){ - vec3 right = normalize(light.right); - vec3 pnormal = normalize(light.spotDirection); - vec3 up = normalize(light.up); + vec3 right = light.right; + vec3 pnormal = light.spotDirection; + vec3 up = light.up; //width and height of the area light: float width = light.width*0.5; @@ -455,15 +457,15 @@ static const string fragmentShader = STRINGIFY( //////////////////////////////////////////////////////////// // now add the material info - \n#ifdef HAS_TEXTURE\n + #ifdef HAS_TEXTURE vec4 tex = TEXTURE(tex0, outtexcoord); vec4 localColor = vec4(ambient,1.0) * mat_ambient + vec4(diffuse,1.0) * tex + vec4(specular,1.0) * mat_specular + mat_emissive; - \n#else\n + #else vec4 localColor = vec4(ambient,1.0) * mat_ambient + vec4(diffuse,1.0) * mat_diffuse + vec4(specular,1.0) * mat_specular + mat_emissive; - \n#endif\n + #endif FRAG_COLOR = clamp( localColor, 0.0, 1.0 ); } -); +)"; static string shaderHeader(string header, int maxLights, bool hasTexture){ diff --git a/libs/openFrameworks/gl/ofShader.cpp b/libs/openFrameworks/gl/ofShader.cpp index b27c95823f1..0a9ef059144 100644 --- a/libs/openFrameworks/gl/ofShader.cpp +++ b/libs/openFrameworks/gl/ofShader.cpp @@ -11,7 +11,11 @@ #include "ofVec4f.h" #include "ofParameterGroup.h" #include "ofParameter.h" +#include "ofBufferObject.h" #include +#ifdef TARGET_ANDROID +#include "ofxAndroidUtils.h" +#endif static const string COLOR_ATTRIBUTE="color"; static const string POSITION_ATTRIBUTE="position"; @@ -94,13 +98,18 @@ ofShader::~ofShader() { ofShader::ofShader(const ofShader & mom) : program(mom.program), bLoaded(mom.bLoaded), -shaders(mom.shaders){ +shaders(mom.shaders), +uniformsCache(mom.uniformsCache), +attributesBindingsCache(mom.attributesBindingsCache){ if(mom.bLoaded){ retainProgram(program); - for(unordered_map::const_iterator it = shaders.begin(); it != shaders.end(); ++it){ - GLuint shader = it->second; - retainShader(shader); + for(auto it: shaders){ + auto shader = it.second; + retainShader(shader.id); } +#ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); +#endif } } @@ -115,16 +124,56 @@ ofShader & ofShader::operator=(const ofShader & mom){ program = mom.program; bLoaded = mom.bLoaded; shaders = mom.shaders; + attributesBindingsCache = mom.attributesBindingsCache; + uniformsCache = mom.uniformsCache; if(mom.bLoaded){ retainProgram(program); - for(unordered_map::const_iterator it = shaders.begin(); it != shaders.end(); ++it){ - GLuint shader = it->second; - retainShader(shader); + for(auto it: shaders){ + auto shader = it.second; + retainShader(shader.id); } +#ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); +#endif } return *this; } +ofShader::ofShader(ofShader && mom) +:program(std::move(mom.program)) +,bLoaded(std::move(mom.bLoaded)) +,shaders(std::move(mom.shaders)) +,uniformsCache(std::move(mom.uniformsCache)) +,attributesBindingsCache(std::move(mom.attributesBindingsCache)){ + if(mom.bLoaded){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); + #endif + } + mom.bLoaded = false; +} + +ofShader & ofShader::operator=(ofShader && mom){ + if(this == &mom) { + return *this; + } + if(bLoaded){ + unload(); + } + program = std::move(mom.program); + bLoaded = std::move(mom.bLoaded); + shaders = std::move(mom.shaders); + attributesBindingsCache = std::move(mom.attributesBindingsCache); + uniformsCache = std::move(mom.uniformsCache); + if(mom.bLoaded){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); + #endif + } + mom.bLoaded = false; + return *this; +} + //-------------------------------------------------------------- bool ofShader::load(string shaderName) { return load(shaderName + ".vert", shaderName + ".frag"); @@ -174,14 +223,24 @@ bool ofShader::setupShaderFromSource(GLenum type, string source, string sourceDi if(shader == 0) { ofLogError("ofShader") << "setupShaderFromSource(): failed creating " << nameForType(type) << " shader"; return false; + } else { + // if the shader object has been allocated successfully on the GPU + // we must retain it so that it can be de-allocated again, once + // this ofShader object has been discarded, or re-allocated. + // we need to do this at this point in the code path, since early + // return statements might prevent us from retaining later. + retainShader(shader); } // parse for includes string src = parseForIncludes( source , sourceDirectoryPath); - + // store source code (that's the expanded source with all includes copied in) - shaderSource[type] = src; - + // we need to store this here, and before shader compilation, + // so that any shader compilation errors can be + // traced down to the correct shader source code line. + shaders[type] = { type, shader, source, src, sourceDirectoryPath }; + // compile shader const char* sptr = src.c_str(); int ssize = src.size(); @@ -209,10 +268,6 @@ bool ofShader::setupShaderFromSource(GLenum type, string source, string sourceDi checkShaderInfoLog(shader, type, OF_LOG_ERROR); return false; } - - shaders[type] = shader; - retainShader(shader); - return true; } @@ -236,18 +291,55 @@ string ofShader::parseForIncludes( const string& source, vector& include stringstream output; stringstream input; input << source; + + auto match_pragma_include = [](const std::string& s_, std::string& filename_) -> bool { + filename_ = ""; + std::istringstream s(s_); + s >> std::ws; // eat up any leading whitespace. + + if (s.peek() != '#') return false; + // -----| invariant: found '#' + s.seekg(1, std::ios::cur); // move forward one character + + std::string p, i, f; + + // while skipping whitespace, read in tokens for: pragma, include, and filename + s >> std::skipws >> p >> i >> f; + + if (p.empty() || i.empty() || (f.size() < 2) ) return false; + // -----| invariant: all tokens have values + + if (p != "pragma") return false; + if (i != "include") return false; + + // first and last character of filename token must match and be either + // '<' and '>', or '" + + if (f[0] == '<' && f[f.size()-1] != '>') return false; //< mismatching brackets + + if ((f[0] == '"' || f[0] == '\'') && (f[0] != f[f.size()-1])) return false; // mismatching quotes + + // invariant: filename properly quoted. + + filename_ = f.substr(1,f.size()-2); + + return true; + }; + + // once std::regex is available across the board, use this regex in favour of the above lambda: + // std::regex re("^\\s*#\\s*pragma\\s+include\\s+[\"<](.*)[\">].*"); - std::regex re("^\\s*#\\s*pragma\\s+include\\s+[\"<](.*)[\">].*"); - std::smatch matches; string line; while( std::getline( input, line ) ) { - std::regex_match( line, matches, re ); - if ( matches.size() < 2 ) { + + string include; + + if (!match_pragma_include(line, include)){ output << line << endl; continue; - } + }; - string include = matches[1]; + // --------| invariant: '#pragma include' has been requested if ( std::find( included.begin(), included.end(), include ) != included.end() ) { ofLogVerbose("ofShader") << include << " already included"; @@ -259,7 +351,6 @@ string ofShader::parseForIncludes( const string& source, vector& include include = ofFile(ofFilePath::join(sourceDirectoryPath, include)).getAbsolutePath(); included.push_back( include ); - ofBuffer buffer = ofBufferFromFile( include ); if ( !buffer.size() ) { ofLogError("ofShader") <<"Could not open glsl include file " << include; @@ -275,9 +366,9 @@ string ofShader::parseForIncludes( const string& source, vector& include //-------------------------------------------------------------- string ofShader::getShaderSource(GLenum type) const{ - unordered_map::const_iterator source = shaderSource.find(type); - if ( source != shaderSource.end()) { - return source->second; + auto source = shaders.find(type); + if ( source != shaders.end()) { + return source->second.expandedSource; } else { ofLogError("ofShader") << "No shader source for shader of type: " << nameForType(type); return ""; @@ -334,7 +425,7 @@ bool ofShader::checkProgramLinkStatus(GLuint program) { ofLogError("ofShader") << "checkProgramLinkStatus(): program failed to link"; checkProgramInfoLog(program); return false; - } + } return true; } @@ -343,18 +434,20 @@ void ofShader::checkShaderInfoLog(GLuint shader, GLenum type, ofLogLevel logLeve GLsizei infoLength; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength); if (infoLength > 1) { - GLchar* infoBuffer = new GLchar[infoLength]; - glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer); - ofLog(logLevel, "ofShader: %s shader reports:\n%s", nameForType(type).c_str(), infoBuffer); - if (shaderSource.find(type) != shaderSource.end()) { + ofBuffer infoBuffer; + infoBuffer.allocate(infoLength); + glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer.getData()); + ofLog(logLevel, "ofShader: %s shader reports:\n%s", nameForType(type).c_str(), infoBuffer.getText().c_str()); +#if (!defined(TARGET_LINUX) || defined(GCC_HAS_REGEX)) + if (shaders.find(type) != shaders.end()) { // The following regexp should match shader compiler error messages by Nvidia and ATI. // Unfortunately, each vendor's driver formats error messages slightly different. std::regex nvidia_ati("^.*[(:]{1}(\\d+)[:)]{1}.*"); std::regex intel("^[0-9]+:([0-9]+)\\([0-9]+\\):.*$"); std::smatch matches; - string infoString = (infoBuffer != nullptr) ? ofTrim(infoBuffer): ""; + string infoString = ofTrim(infoBuffer); if (std::regex_search(infoString, matches, intel) || std::regex_search(infoString, matches, nvidia_ati)){ - ofBuffer buf = shaderSource[type]; + ofBuffer buf = shaders[type].expandedSource; ofBuffer::Line line = buf.getLines().begin(); int offendingLineNumber = ofToInt(matches[1]); ostringstream msg; @@ -367,10 +460,10 @@ void ofShader::checkShaderInfoLog(GLuint shader, GLenum type, ofLogLevel logLeve } ofLog(logLevel) << msg.str(); }else{ - ofLog(logLevel) << shaderSource[type]; + ofLog(logLevel) << shaders[type].expandedSource; } } - delete [] infoBuffer; +#endif } } @@ -379,33 +472,22 @@ void ofShader::checkProgramInfoLog(GLuint program) { GLsizei infoLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength); if (infoLength > 1) { - GLchar* infoBuffer = new GLchar[infoLength]; - glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer); + ofBuffer infoBuffer; + infoBuffer.allocate(infoLength); + glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer.getData()); + // TODO: it appears that Raspberry Pi only reports shader errors whilst linking, + // but then it becomes hard to figure out whether the fragment or the + // vertex shader caused the error. + // We need to find a robust way of extracing this information from + // the log, and unfortunately can't use regex whilst gcc on RPi is assumed to + // be < 4.9, which is the first version fully supporting this c++11 feature. string msg = "ofShader: program reports:\n"; -#ifdef TARGET_RASPBERRYPI - if (shaderSource.find(GL_FRAGMENT_SHADER) != shaderSource.end()) { - std::regex re(",.line.([^\\)]*)"); - std::smatch matches; - string infoString = (infoBuffer != nullptr) ? string(infoBuffer): ""; - std::regex_match(infoString, matches, re); - ofBuffer buf = shaderSource[GL_FRAGMENT_SHADER]; - ofBuffer::Line line = buf.getLines().begin(); - if (!matches.empty()){ - int offendingLineNumber = ofToInt(infoString.substr(matches[1].offset, matches[1].length)); - ostringstream msg; - msg << "ofShader: " + nameForType(GL_FRAGMENT_SHADER) + ", offending line " << offendingLineNumber << " :"<< endl; - for(int i=0; line != buf.getLines().end(); line++, i++ ){ - string s = *line; - if ( i >= offendingLineNumber -3 && i < offendingLineNumber + 2 ){ - msg << "\t" << setw(5) << (i+1) << "\t" << s << endl; - } - } - ofLogError("ofShader") << msg.str(); - } + ofLogError("ofShader") << msg + infoBuffer.getText(); +#ifdef TARGET_RAPSBERRY_PI + for(auto it: shaders){ + ofLogNotice("ofShader") << it.second.expandedSource; } #endif - ofLogError("ofShader", msg + infoBuffer); - delete [] infoBuffer; } } @@ -436,11 +518,11 @@ bool ofShader::linkProgram() { } else { checkAndCreateProgram(); - for(unordered_map::const_iterator it = shaders.begin(); it != shaders.end(); ++it){ - GLuint shader = it->second; - if(shader) { - ofLogVerbose("ofShader") << "linkProgram(): attaching " << nameForType(it->first) << " shader to program " << program; - glAttachShader(program, shader); + for(auto it: shaders){ + auto shader = it.second; + if(shader.id>0) { + ofLogVerbose("ofShader") << "linkProgram(): attaching " << nameForType(it.first) << " shader to program " << program; + glAttachShader(program, shader.id); } } @@ -448,6 +530,35 @@ bool ofShader::linkProgram() { checkProgramLinkStatus(program); + + // Pre-cache all active uniforms + GLint numUniforms = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms); + + GLint uniformMaxLength = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxLength); + + GLint count = -1; + GLenum type = 0; + GLsizei length; + vector uniformName(uniformMaxLength); + for(GLint i = 0; i < numUniforms; i++) { + glGetActiveUniform(program, i, uniformMaxLength, &length, &count, &type, uniformName.data()); + string name(uniformName.begin(), uniformName.begin()+length); + // some drivers return uniform_name[0] for array uniforms + // instead of the real uniform name + uniformsCache[name] = glGetUniformLocation(program, name.c_str()); + auto arrayPos = name.find('['); + if(arrayPos!=std::string::npos){ + name = name.substr(0, arrayPos); + uniformsCache[name] = glGetUniformLocation(program, name.c_str()); + } + } + +#ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); +#endif + // bLoaded means we have loaded shaders onto the graphics card; // it doesn't necessarily mean that these shaders have compiled and linked successfully. bLoaded = true; @@ -455,7 +566,46 @@ bool ofShader::linkProgram() { return bLoaded; } + +//-------------------------------------------------------------- +#ifdef TARGET_ANDROID +void ofShader::unloadGL(){ + for(auto it: shaders) { + auto shader = it.second; + if(shader.id) { + releaseShader(program,shader.id); + } + } + + if (program) { + releaseProgram(program); + program = 0; + } + bLoaded = false; + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofShader::reloadGL); +} + +void ofShader::reloadGL(){ + auto source = shaders; + auto bindings = attributesBindingsCache; + shaders.clear(); + uniformsCache.clear(); + attributesBindingsCache.clear(); + for(auto & shader: source){ + auto type = shader.second.type; + auto source = shader.second.expandedSource; + setupShaderFromSource(type,source); + } + for(auto binding: bindings){ + bindAttribute(binding.second, binding.first); + } + linkProgram(); +} +#endif + +//-------------------------------------------------------------- void ofShader::bindAttribute(GLuint location, const string & name) const{ + attributesBindingsCache[name] = location; glBindAttribLocation(program,location,name.c_str()); } @@ -477,11 +627,11 @@ bool ofShader::bindDefaults() const{ //-------------------------------------------------------------- void ofShader::unload() { if(bLoaded) { - for(unordered_map::const_iterator it = shaders.begin(); it != shaders.end(); ++it) { - GLuint shader = it->second; - if(shader) { - ofLogVerbose("ofShader") << "unload(): detaching and deleting " << nameForType(it->first) << " shader from program " << program; - releaseShader(program,shader); + for(auto it: shaders) { + auto shader = it.second; + if(shader.id) { + ofLogVerbose("ofShader") << "unload(): detaching and deleting " << nameForType(shader.type) << " shader from program " << program; + releaseShader(program,shader.id); } } @@ -491,7 +641,12 @@ void ofShader::unload() { } shaders.clear(); - uniformLocations.clear(); + uniformsCache.clear(); + attributesBindingsCache.clear(); +#ifdef TARGET_ANDROID + ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofShader::reloadGL); + ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL); +#endif } bLoaded = false; } @@ -547,9 +702,19 @@ void ofShader::setUniformTexture(const string & name, const ofTexture& tex, int if (!ofIsGLProgrammableRenderer()){ glEnable(texData.textureTarget); glBindTexture(texData.textureTarget, texData.textureID); +#ifndef TARGET_OPENGLES + if (texData.bufferId != 0) { + glTexBuffer(GL_TEXTURE_BUFFER, texData.glInternalFormat, texData.bufferId); + } +#endif glDisable(texData.textureTarget); } else { glBindTexture(texData.textureTarget, texData.textureID); +#ifndef TARGET_OPENGLES + if (texData.bufferId != 0) { + glTexBuffer(GL_TEXTURE_BUFFER, texData.glInternalFormat, texData.bufferId); + } +#endif } setUniform1i(name, textureLocation); glActiveTexture(GL_TEXTURE0); @@ -636,6 +801,11 @@ void ofShader::setUniform4f(const string & name, const ofVec4f & v) const{ setUniform4f(name,v.x,v.y,v.z,v.w); } +//-------------------------------------------------------------- +void ofShader::setUniform4f(const string & name, const ofFloatColor & v) const{ + setUniform4f(name,v.r,v.g,v.b,v.a); +} + //-------------------------------------------------------------- void ofShader::setUniform1iv(const string & name, const int* v, int count) const{ if(bLoaded) { @@ -702,7 +872,7 @@ void ofShader::setUniform4fv(const string & name, const float* v, int count) co //-------------------------------------------------------------- void ofShader::setUniforms(const ofParameterGroup & parameters) const{ - for(int i=0;i).name()){ setUniform1i(parameters[i].getEscapedName(),parameters[i].cast()); }else if(parameters[i].type()==typeid(ofParameter).name()){ @@ -860,17 +1030,12 @@ GLint ofShader::getAttributeLocation(const string & name) const{ //-------------------------------------------------------------- GLint ofShader::getUniformLocation(const string & name) const{ if(!bLoaded) return -1; - GLint loc = -1; - - // tig: caching uniform locations gives the RPi a 17% boost on average - unordered_map::iterator it = uniformLocations.find(name); - if (it == uniformLocations.end()){ - loc = glGetUniformLocation(program, name.c_str()); - uniformLocations[name] = loc; + auto it = uniformsCache.find(name); + if (it == uniformsCache.end()){ + return -1; } else { - loc = it->second; + return it->second; } - return loc; } //-------------------------------------------------------------- @@ -885,19 +1050,17 @@ void ofShader::printActiveUniforms() const{ GLint count = -1; GLenum type = 0; GLchar* uniformName = new GLchar[uniformMaxLength]; - stringstream line; for(GLint i = 0; i < numUniforms; i++) { + stringstream line; GLsizei length; glGetActiveUniform(program, i, uniformMaxLength, &length, &count, &type, uniformName); line << "[" << i << "] "; for(int j = 0; j < length; j++) { line << uniformName[j]; } - line << " @ index " << getUniformLocation(uniformName); + line << " @ index " << glGetUniformLocation(program, uniformName); ofLogNotice("ofShader") << line.str(); - line.str(""); } - delete [] uniformName; } //-------------------------------------------------------------- @@ -934,9 +1097,9 @@ GLuint ofShader::getProgram() const{ //-------------------------------------------------------------- GLuint ofShader::getShader(GLenum type) const{ - unordered_map::const_iterator shader = shaders.find(type); + auto shader = shaders.find(type); if(shader!=shaders.end()){ - return shader->second; + return shader->second.id; }else{ return 0; } diff --git a/libs/openFrameworks/gl/ofShader.h b/libs/openFrameworks/gl/ofShader.h index 6b9fa8c05d7..6ccdf4cdaa2 100644 --- a/libs/openFrameworks/gl/ofShader.h +++ b/libs/openFrameworks/gl/ofShader.h @@ -17,6 +17,7 @@ class ofParameterGroup; class ofVec2f; class ofVec3f; class ofVec4f; +class ofBufferObject; class ofShader { public: @@ -24,6 +25,8 @@ class ofShader { ~ofShader(); ofShader(const ofShader & shader); ofShader & operator=(const ofShader & shader); + ofShader(ofShader && shader); + ofShader & operator=(ofShader && shader); bool load(string shaderName); bool load(string vertName, string fragName, string geomName=""); @@ -68,6 +71,7 @@ class ofShader { void setUniform2f(const string & name, const ofVec2f & v) const; void setUniform3f(const string & name, const ofVec3f & v) const; void setUniform4f(const string & name, const ofVec4f & v) const; + void setUniform4f(const string & name, const ofFloatColor & v) const; // set an array of uniform values void setUniform1iv(const string & name, const int* v, int count = 1) const; @@ -161,9 +165,17 @@ class ofShader { GLuint program; bool bLoaded; - unordered_map shaders; - unordered_map shaderSource; - mutable unordered_map uniformLocations; + struct Shader{ + GLenum type; + GLuint id; + std::string source; + std::string expandedSource; + std::string sourcePath; + }; + + unordered_map shaders; + unordered_map uniformsCache; + mutable unordered_map attributesBindingsCache; void checkProgramInfoLog(GLuint program); bool checkProgramLinkStatus(GLuint program); @@ -181,7 +193,9 @@ class ofShader { static string parseForIncludes( const string& source, vector& included, int level = 0, const string& sourceDirectoryPath = ""); void checkAndCreateProgram(); - - +#ifdef TARGET_ANDROID + void unloadGL(); + void reloadGL(); +#endif }; diff --git a/libs/openFrameworks/gl/ofTexture.cpp b/libs/openFrameworks/gl/ofTexture.cpp index d91f1940f0b..9dd451edaa8 100644 --- a/libs/openFrameworks/gl/ofTexture.cpp +++ b/libs/openFrameworks/gl/ofTexture.cpp @@ -186,6 +186,18 @@ ofTexture::ofTexture(const ofTexture & mom){ #endif } +ofTexture::ofTexture(ofTexture && mom){ + anchor = mom.anchor; + bAnchorIsPct = mom.bAnchorIsPct; + texData = mom.texData; + bWantsMipmap = mom.bWantsMipmap; + mom.texData.bAllocated = 0; + mom.texData.textureID = 0; +#ifdef TARGET_ANDROID + registerTexture(this); +#endif +} + //---------------------------------------------------------- ofTexture& ofTexture::operator=(const ofTexture & mom){ if(!texData.bUseExternalTextureID){ @@ -202,6 +214,23 @@ ofTexture& ofTexture::operator=(const ofTexture & mom){ return *this; } +//---------------------------------------------------------- +ofTexture& ofTexture::operator=(ofTexture && mom){ + if(!texData.bUseExternalTextureID){ + release(texData.textureID); + } + anchor = mom.anchor; + bAnchorIsPct = mom.bAnchorIsPct; + texData = mom.texData; + bWantsMipmap = mom.bWantsMipmap; + mom.texData.bAllocated = 0; + mom.texData.textureID = 0; +#ifdef TARGET_ANDROID + unregisterTexture(this); +#endif + return *this; +} + //---------------------------------------------------------- bool ofTexture::bAllocated() const { return texData.bAllocated; @@ -276,38 +305,56 @@ void ofTexture::allocate(int w, int h, int glInternalFormat, int glFormat, int p //---------------------------------------------------------- void ofTexture::allocate(const ofPixels& pix){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } //---------------------------------------------------------- void ofTexture::allocate(const ofPixels& pix, bool bUseARBExtention){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), bUseARBExtention, ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } //---------------------------------------------------------- void ofTexture::allocate(const ofShortPixels& pix){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } //---------------------------------------------------------- void ofTexture::allocate(const ofShortPixels& pix, bool bUseARBExtention){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), bUseARBExtention, ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } //---------------------------------------------------------- void ofTexture::allocate(const ofFloatPixels& pix){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } //---------------------------------------------------------- void ofTexture::allocate(const ofFloatPixels& pix, bool bUseARBExtention){ allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), bUseARBExtention, ofGetGlFormat(pix), ofGetGlType(pix)); - loadData(pix); + if((pix.getPixelFormat()==OF_PIXELS_GRAY || pix.getPixelFormat()==OF_PIXELS_GRAY_ALPHA) && ofIsGLProgrammableRenderer()){ + setRGToRGBASwizzles(true); + } + if(texData.bAllocated) loadData(pix); } #ifndef TARGET_OPENGLES @@ -315,10 +362,9 @@ void ofTexture::allocate(const ofFloatPixels& pix, bool bUseARBExtention){ void ofTexture::allocateAsBufferTexture(const ofBufferObject & buffer, int glInternalFormat){ texData.glInternalFormat = glInternalFormat; texData.textureTarget = GL_TEXTURE_BUFFER; - allocate(texData); - glBindTexture(texData.textureTarget,texData.textureID); - glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat,buffer.getId()); - glBindTexture(texData.textureTarget,0); + texData.bufferId = buffer.getId(); + allocate(texData,0,0); + buffer.bind(GL_TEXTURE_BUFFER); } #endif @@ -489,36 +535,57 @@ void ofTexture::loadData(const float * data, int w, int h, int glFormat){ //---------------------------------------------------------- void ofTexture::loadData(const ofPixels & pix){ - ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); - loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + if(!isAllocated()){ + allocate(pix); + }else{ + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); + loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + } } //---------------------------------------------------------- void ofTexture::loadData(const ofShortPixels & pix){ - ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); - loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + if(!isAllocated()){ + allocate(pix); + }else{ + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); + loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + } } //---------------------------------------------------------- void ofTexture::loadData(const ofFloatPixels & pix){ - ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); - loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + if(!isAllocated()){ + allocate(pix); + }else{ + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getBytesStride()); + loadData(pix.getData(), pix.getWidth(), pix.getHeight(), ofGetGlFormat(pix), ofGetGlType(pix)); + } } //---------------------------------------------------------- void ofTexture::loadData(const ofPixels & pix, int glFormat){ + if(!isAllocated()){ + allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), glFormat, ofGetGlType(pix)); + } ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getWidth(),pix.getBytesPerChannel(),ofGetNumChannelsFromGLFormat(glFormat)); loadData(pix.getData(), pix.getWidth(), pix.getHeight(), glFormat, ofGetGlType(pix)); } //---------------------------------------------------------- void ofTexture::loadData(const ofShortPixels & pix, int glFormat){ + if(!isAllocated()){ + allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), glFormat, ofGetGlType(pix)); + } ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getWidth(),pix.getBytesPerChannel(),ofGetNumChannelsFromGLFormat(glFormat)); loadData(pix.getData(), pix.getWidth(), pix.getHeight(), glFormat, ofGetGlType(pix)); } //---------------------------------------------------------- void ofTexture::loadData(const ofFloatPixels & pix, int glFormat){ + if(!isAllocated()){ + allocate(pix.getWidth(), pix.getHeight(), ofGetGlInternalFormat(pix), ofGetUsingArbTex(), glFormat, ofGetGlType(pix)); + } ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,pix.getWidth(),pix.getBytesPerChannel(),ofGetNumChannelsFromGLFormat(glFormat)); loadData(pix.getData(), pix.getWidth(), pix.getHeight(), glFormat, ofGetGlType(pix)); } @@ -892,6 +959,11 @@ void ofTexture::disableMipmap(){ texData.minFilter = GL_LINEAR; } +//------------------------------------ +bool ofTexture::hasMipmap() const{ + return texData.hasMipmap; +} + //------------------------------------ void ofTexture::draw(float x, float y) const{ draw(x,y,0,getWidth(),getHeight()); diff --git a/libs/openFrameworks/gl/ofTexture.h b/libs/openFrameworks/gl/ofTexture.h index d3b47f127bc..d7765ffaa23 100644 --- a/libs/openFrameworks/gl/ofTexture.h +++ b/libs/openFrameworks/gl/ofTexture.h @@ -185,6 +185,7 @@ class ofTextureData { wrapModeHorizontal = GL_CLAMP_TO_EDGE; wrapModeVertical = GL_CLAMP_TO_EDGE; hasMipmap = false; + bufferId = 0; } @@ -210,6 +211,7 @@ class ofTextureData { GLint wrapModeHorizontal; ///< How will the texture wrap around horizontally? GLint wrapModeVertical; ///< How will the texture wrap around vertically? + unsigned int bufferId; ///< Optionally if the texture is backed by a buffer so we can bind it private: shared_ptr alphaMask; ///< Optional alpha mask to bind bool bUseExternalTextureID; ///< Are we using an external texture ID? @@ -255,6 +257,7 @@ class ofTexture : public ofBaseDraws { /// \brief Construct an ofTexture from an existing ofTexture. /// \param mom The ofTexture to copy. Reuses internal GL texture ID. ofTexture(const ofTexture & mom); + ofTexture(ofTexture && mom); /// \brief Allocate the texture using the given settings. /// @@ -297,8 +300,8 @@ class ofTexture : public ofBaseDraws { /// \sa allocate(int w, int h, int glInternalFormat) /// \param w Desired width in pixels. /// \param h Desired height in pixels. - /// \param glInternalFormat - /// \param glFormat + /// \param glInternalFormat The internal openGL format. + /// \param glFormat The openGL format. /// \param pixelType GL pixel type: GL_UNSIGNED_BYTE, GL_FLOAT, etc. virtual void allocate(int w, int h, int glInternalFormat, int glFormat, int pixelType); @@ -313,7 +316,7 @@ class ofTexture : public ofBaseDraws { /// \sa allocate(int w, int h, int glInternalFormat) /// \param w Desired width in pixels. /// \param h Desired height in pixels. - /// \param glInternalFormat + /// \param glInternalFormat The internal openGL format. /// \param bUseARBExtension Set to true to use rectangular textures. virtual void allocate(int w, int h, int glInternalFormat, bool bUseARBExtension); @@ -435,6 +438,7 @@ class ofTexture : public ofBaseDraws { /// \brief Copy a given ofTexture into this texture. /// \param mom The ofTexture to copy from. Reuses internal GL texture ID. ofTexture& operator=(const ofTexture & mom); + ofTexture& operator=(ofTexture && mom); /// \brief Clears the texture. @@ -647,7 +651,6 @@ class ofTexture : public ofBaseDraws { /// \param sh Subsection height within the texture. void drawSubsection(float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const; - ofMesh getMeshForSubsection(float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh, bool vflipped, ofRectMode rectMode) const; ofMesh getQuad(const ofPoint & p1, const ofPoint & p2, const ofPoint & p3, const ofPoint & p4) const; /// \brief Get a mesh that has the texture coordinates set. @@ -662,7 +665,9 @@ class ofTexture : public ofBaseDraws { /// \param sy Subsection y axis offset within the texture. /// \param sw Subsection width within the texture. /// \param sh Subsection height within the texture. - ofMesh getMeshForSubsection(float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const; + /// \param vflipped Takes into account the flipped state in OF. + /// \param rectMode rectMode Taking x,y as the center or the top left corner. + ofMesh getMeshForSubsection(float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh, bool vflipped, ofRectMode rectMode) const; /// \brief Bind the texture. /// @@ -922,6 +927,12 @@ class ofTexture : public ofBaseDraws { /// \sa ofEnableArbTex() /// \sa ofDisableArbTex() void generateMipmap(); + + /// \brief Find out if a mipmap has been generated for the current texture. + /// + /// \sa generateMipmap() + /// \sa enableMipmap() + bool hasMipmap() const; /// \} diff --git a/libs/openFrameworks/gl/ofVbo.cpp b/libs/openFrameworks/gl/ofVbo.cpp index 408d28471e2..3e23a94ee5f 100644 --- a/libs/openFrameworks/gl/ofVbo.cpp +++ b/libs/openFrameworks/gl/ofVbo.cpp @@ -906,8 +906,8 @@ void ofVbo::draw(int drawMode, int first, int total) const{ } //-------------------------------------------------------------- -void ofVbo::drawElements(int drawMode, int amt) const{ - ofGetGLRenderer()->drawElements(*this,drawMode,amt); +void ofVbo::drawElements(int drawMode, int amt, int offsetelements) const{ + ofGetGLRenderer()->drawElements(*this,drawMode,amt,offsetelements); } //-------------------------------------------------------------- diff --git a/libs/openFrameworks/gl/ofVbo.h b/libs/openFrameworks/gl/ofVbo.h index 8913886f439..dec6e432855 100644 --- a/libs/openFrameworks/gl/ofVbo.h +++ b/libs/openFrameworks/gl/ofVbo.h @@ -112,7 +112,7 @@ class ofVbo { bool getUsingIndices() const; void draw(int drawMode, int first, int total) const; - void drawElements(int drawMode, int amt) const; + void drawElements(int drawMode, int amt, int offsetelements = 0) const; void drawInstanced(int drawMode, int first, int total, int primCount) const; void drawElementsInstanced(int drawMode, int amt, int primCount) const; diff --git a/libs/openFrameworks/gl/ofVboMesh.cpp b/libs/openFrameworks/gl/ofVboMesh.cpp index 8101dff3455..761fd0bf43e 100644 --- a/libs/openFrameworks/gl/ofVboMesh.cpp +++ b/libs/openFrameworks/gl/ofVboMesh.cpp @@ -27,7 +27,12 @@ ofVboMesh::ofVboMesh(const ofMesh & mom) void ofVboMesh::operator=(const ofMesh & mom) { - ((ofMesh&)(*this)) = mom; + (*(ofMesh*)this) = mom; + getVertices(); + getColors(); + getTexCoords(); + getNormals(); + getIndices(); } ofVboMesh::~ofVboMesh(){ diff --git a/libs/openFrameworks/gl/ofVboMesh.h b/libs/openFrameworks/gl/ofVboMesh.h index d19ed77d797..e0e6102f4f7 100644 --- a/libs/openFrameworks/gl/ofVboMesh.h +++ b/libs/openFrameworks/gl/ofVboMesh.h @@ -8,7 +8,7 @@ class ofVboMesh: public ofMesh{ using ofMesh::draw; ofVboMesh(); ofVboMesh(const ofMesh & mom); - void operator=(const ofMesh & mom); + void operator=(const ofMesh & mom); virtual ~ofVboMesh(); void setUsage(int usage); diff --git a/libs/openFrameworks/graphics/of3dGraphics.cpp b/libs/openFrameworks/graphics/of3dGraphics.cpp index 1571573041d..2ac1dbfe907 100644 --- a/libs/openFrameworks/graphics/of3dGraphics.cpp +++ b/libs/openFrameworks/graphics/of3dGraphics.cpp @@ -505,7 +505,7 @@ void of3dGraphics::drawArrow(const ofVec3f& start, const ofVec3f& end, float hea //draw cone ofMatrix4x4 mat; mat.makeRotationMatrix( ofVec3f(0,1,0), start - end ); - mat.translate(end + ofVec3f(0,headSize*0.5,0)); + mat.translate(end); renderer->pushMatrix(); renderer->multMatrix(mat.getPtr()); drawCone(headSize, headSize*2.); diff --git a/libs/openFrameworks/graphics/of3dGraphics.h b/libs/openFrameworks/graphics/of3dGraphics.h index 7f2038edfd1..293464ced23 100644 --- a/libs/openFrameworks/graphics/of3dGraphics.h +++ b/libs/openFrameworks/graphics/of3dGraphics.h @@ -107,7 +107,7 @@ ofVec3f ofGetBoxResolution(); /// \param z The z-coordinate of the box's origin. /// \param width The width of the box. /// \param height The height of the box. -/// \param height The depth of the box. +/// \param depth The depth of the box. void ofDrawBox( float x, float y, float z, float width, float height, float depth); /// \brief Draws a cube with the specified size, starting from the specified coordinates. @@ -137,7 +137,7 @@ void ofDrawBox(float x, float y, float z, float size); /// \param position an ofPoint which contains the (x,y,z) coordinates for the box's reference corner. /// \param width The width of the box. /// \param height The height of the box. -/// \param height The depth of the box. +/// \param depth The depth of the box. void ofDrawBox(const ofPoint& position, float width, float height, float depth); /// \brief Draws a cube with the specified size, starting from the specified position. @@ -168,7 +168,7 @@ void ofDrawBox(float size); /// /// \param width The width of the box. /// \param height The height of the box. -/// \param height The depth of the box. +/// \param depth The depth of the box. void ofDrawBox( float width, float height, float depth ); // deprecated methods // @@ -258,7 +258,7 @@ class of3dGraphics{ /// \param z The z-coordinate of the box's origin. /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. void drawBox( float x, float y, float z, float width, float height, float depth) const; /// \brief Draws a cube with the specified size, starting from the specified coordinates. @@ -288,7 +288,7 @@ class of3dGraphics{ /// \param position an ofPoint which contains the (x,y,z) coordinates for the box's reference corner. /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. void drawBox(const ofPoint& position, float width, float height, float depth) const; /// \brief Draws a cube with the specified size, starting from the specified position. @@ -319,7 +319,7 @@ class of3dGraphics{ /// /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. void drawBox( float width, float height, float depth ) const; void drawAxis(float size) const; diff --git a/libs/openFrameworks/graphics/ofBitmapFont.cpp b/libs/openFrameworks/graphics/ofBitmapFont.cpp index d13969c56da..c0bfe38e578 100644 --- a/libs/openFrameworks/graphics/ofBitmapFont.cpp +++ b/libs/openFrameworks/graphics/ofBitmapFont.cpp @@ -469,13 +469,16 @@ const ofTexture & ofBitmapFont::getTexture() const{ ofBitmapFont::init(); texture.allocate(pixels,false); texture.setTextureMinMagFilter(GL_LINEAR,GL_NEAREST); - texture.setRGToRGBASwizzles(true); } return texture; } ofRectangle ofBitmapFont::getBoundingBox(const string & text, int x, int y) const{ + if(text.empty()){ + return ofRectangle(x,y,0,0); + } + const ofMesh & mesh = getMesh(text,x,y); ofVec2f max(numeric_limits::min(),numeric_limits::min()); ofVec2f min(numeric_limits::max(),numeric_limits::max()); diff --git a/libs/openFrameworks/graphics/ofCairoRenderer.cpp b/libs/openFrameworks/graphics/ofCairoRenderer.cpp index 6185cc63cfb..48f75d86e2c 100644 --- a/libs/openFrameworks/graphics/ofCairoRenderer.cpp +++ b/libs/openFrameworks/graphics/ofCairoRenderer.cpp @@ -31,9 +31,9 @@ ofCairoRenderer::~ofCairoRenderer(){ close(); } -void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle _viewport){ - if( _viewport.width == 0 || _viewport.height == 0 ){ - _viewport.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight()); +void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){ + if( outputsize.width == 0 || outputsize.height == 0 ){ + outputsize.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight()); } filename = _filename; @@ -65,22 +65,22 @@ void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool switch(type){ case PDF: if(filename==""){ - surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); + surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,outputsize.width, outputsize.height); }else{ - surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); + surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height); } break; case SVG: if(filename==""){ - surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height); + surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,outputsize.width, outputsize.height); }else{ - surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height); + surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height); } break; case IMAGE: - imageBuffer.allocate(_viewport.width, _viewport.height, OF_PIXELS_BGRA); + imageBuffer.allocate(outputsize.width, outputsize.height, OF_PIXELS_BGRA); imageBuffer.set(0); - surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,_viewport.width, _viewport.height,_viewport.width*4); + surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,outputsize.width, outputsize.height,outputsize.width*4); break; case FROM_FILE_EXTENSION: ofLogFatalError("ofCairoRenderer") << "setup(): couldn't determine type from extension for filename: \"" << _filename << "\"!"; @@ -92,16 +92,16 @@ void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool cr = cairo_create(surface); cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL); - viewportRect = _viewport; - originalViewport = _viewport; + viewportRect = outputsize; + originalViewport = outputsize; viewport(viewportRect); page = 0; b3D = b3D_; multiPage = multiPage_; } -void ofCairoRenderer::setupMemoryOnly(Type _type, bool multiPage_, bool b3D_, ofRectangle _viewport){ - setup("",_type,multiPage_,b3D_,_viewport); +void ofCairoRenderer::setupMemoryOnly(Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){ + setup("",_type,multiPage_,b3D_,outputsize); } void ofCairoRenderer::flush(){ @@ -128,8 +128,7 @@ void ofCairoRenderer::close(){ void ofCairoRenderer::startRender(){ - if(!surface || !cr) - setStyle(currentStyle); + setStyle(currentStyle); if(page==0 || !multiPage){ page=1; }else{ @@ -709,6 +708,7 @@ void ofCairoRenderer::setColor(int r, int g, int b){ //-------------------------------------------- void ofCairoRenderer::setColor(int r, int g, int b, int a){ cairo_set_source_rgba(cr, (float)r/255.0, (float)g/255.0, (float)b/255.0, (float)a/255.0); + currentStyle.color.set(r,g,b,a); }; //-------------------------------------------- @@ -928,6 +928,7 @@ void ofCairoRenderer::viewport(ofRectangle v){ void ofCairoRenderer::viewport(float x, float y, float width, float height, bool invertY){ if(width < 0) width = originalViewport.width; if(height < 0) height = originalViewport.height; + cout << "setting viewport to:" << width << ", " << height << endl; if (invertY){ y = -y; @@ -948,12 +949,12 @@ void ofCairoRenderer::viewport(float x, float y, float width, float height, bool //---------------------------------------------------------- void ofCairoRenderer::setupScreenPerspective(float width, float height, float fov, float nearDist, float farDist){ if(!b3D) return; - if(width < 0) width = viewportRect.width; - if(height < 0) height = viewportRect.height; + if(width < 0) width = originalViewport.width; + if(height < 0) height = originalViewport.height; ofOrientation orientation = ofGetOrientation(); - float viewW = viewportRect.width; - float viewH = viewportRect.height; + float viewW = originalViewport.width; + float viewH = originalViewport.height; float eyeX = viewW / 2; float eyeY = viewH / 2; @@ -1169,6 +1170,7 @@ void ofCairoRenderer::clear(){ if(!surface || ! cr) return; cairo_set_source_rgba(cr,currentStyle.bgColor.r/255., currentStyle.bgColor.g/255., currentStyle.bgColor.b/255., currentStyle.bgColor.a/255.); cairo_paint(cr); + setColor(currentStyle.color); } //---------------------------------------------------------- @@ -1176,6 +1178,7 @@ void ofCairoRenderer::clear(float r, float g, float b, float a) { if(!surface || ! cr) return; cairo_set_source_rgba(cr,r/255., g/255., b/255., a/255.); cairo_paint(cr); + setColor(currentStyle.color); } @@ -1209,7 +1212,7 @@ void ofCairoRenderer::pushStyle(){ void ofCairoRenderer::popStyle(){ if( styleHistory.size() ){ - setStyle(styleHistory.front()); + setStyle(styleHistory.back()); styleHistory.pop_back(); } } diff --git a/libs/openFrameworks/graphics/ofCairoRenderer.h b/libs/openFrameworks/graphics/ofCairoRenderer.h index 88dc37a232d..d21a85d2c3d 100644 --- a/libs/openFrameworks/graphics/ofCairoRenderer.h +++ b/libs/openFrameworks/graphics/ofCairoRenderer.h @@ -26,7 +26,7 @@ class ofCairoRenderer: public ofBaseRenderer{ IMAGE, FROM_FILE_EXTENSION }; - void setup(string filename, Type type=ofCairoRenderer::FROM_FILE_EXTENSION, bool multiPage=true, bool b3D=false, ofRectangle viewport = ofRectangle(0,0,0,0)); + void setup(string filename, Type type=ofCairoRenderer::FROM_FILE_EXTENSION, bool multiPage=true, bool b3D=false, ofRectangle outputsize = ofRectangle(0,0,0,0)); void setupMemoryOnly(Type _type, bool multiPage=true, bool b3D=false, ofRectangle viewport = ofRectangle(0,0,0,0)); void close(); void flush(); diff --git a/libs/openFrameworks/graphics/ofGraphics.cpp b/libs/openFrameworks/graphics/ofGraphics.cpp index ce950db68bb..db691766d40 100644 --- a/libs/openFrameworks/graphics/ofGraphics.cpp +++ b/libs/openFrameworks/graphics/ofGraphics.cpp @@ -7,6 +7,7 @@ #if !defined(TARGET_OF_IOS) && !defined(TARGET_ANDROID) && !defined(TARGET_EMSCRIPTEN) #include "ofCairoRenderer.h" #endif +#include "ofGLRenderer.h" #ifndef TARGET_WIN32 @@ -26,13 +27,7 @@ void ofSetCurrentRenderer(shared_ptr renderer,bool setDefaults){ ofGetCurrentRenderer() = renderer; } -#if !defined(TARGET_ANDROID) && !defined(TARGET_OF_IOS) - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- -#include "ofCairoRenderer.h" -#include "ofGLRenderer.h" - +#if !defined(TARGET_OF_IOS) && !defined(TARGET_ANDROID) && !defined(TARGET_EMSCRIPTEN) static shared_ptr cairoScreenshot; static shared_ptr storedRenderer; static shared_ptr rendererCollection; @@ -57,13 +52,13 @@ static void ofEndSaveScreen(){ } -static void ofBeginSaveScreen(string filename, ofCairoRenderer::Type type, bool bMultipage, bool b3D, ofRectangle viewport){ +static void ofBeginSaveScreen(string filename, ofCairoRenderer::Type type, bool bMultipage, bool b3D, ofRectangle outputsize){ if( bScreenShotStarted ) ofEndSaveScreen(); storedRenderer = ofGetCurrentRenderer(); cairoScreenshot = shared_ptr(new ofCairoRenderer); - cairoScreenshot->setup(filename, type, bMultipage, b3D, viewport); + cairoScreenshot->setup(filename, type, bMultipage, b3D, outputsize); rendererCollection = shared_ptr(new ofRendererCollection); rendererCollection->renderers.push_back(storedRenderer); @@ -75,8 +70,8 @@ static void ofBeginSaveScreen(string filename, ofCairoRenderer::Type type, bool } //----------------------------------------------------------------------------------- -void ofBeginSaveScreenAsPDF(string filename, bool bMultipage, bool b3D, ofRectangle viewport){ - ofBeginSaveScreen(filename, ofCairoRenderer::PDF, bMultipage, b3D, viewport); +void ofBeginSaveScreenAsPDF(string filename, bool bMultipage, bool b3D, ofRectangle outputsize){ + ofBeginSaveScreen(filename, ofCairoRenderer::PDF, bMultipage, b3D, outputsize); } //----------------------------------------------------------------------------------- @@ -85,8 +80,8 @@ void ofEndSaveScreenAsPDF(){ } //----------------------------------------------------------------------------------- -void ofBeginSaveScreenAsSVG(string filename, bool bMultipage, bool b3D, ofRectangle viewport){ - ofBeginSaveScreen(filename, ofCairoRenderer::SVG, bMultipage, b3D, viewport); +void ofBeginSaveScreenAsSVG(string filename, bool bMultipage, bool b3D, ofRectangle outputsize){ + ofBeginSaveScreen(filename, ofCairoRenderer::SVG, bMultipage, b3D, outputsize); } //----------------------------------------------------------------------------------- @@ -238,7 +233,6 @@ void ofTranslate(const ofPoint& p){ ofGetCurrentRenderer()->translate(p); } - //---------------------------------------------------------- void ofTranslate(float x, float y, float z){ ofGetCurrentRenderer()->translate(x, y, z); @@ -249,6 +243,14 @@ void ofScale(float xAmnt, float yAmnt, float zAmnt){ ofGetCurrentRenderer()->scale(xAmnt, yAmnt, zAmnt); } +void ofScale(float amount){ + ofScale(amount, amount, amount); +} + +void ofScale(const ofPoint & p) { + ofScale(p.x, p.y, p.z); +} + //---------------------------------------------------------- void ofRotate(float degrees, float vecX, float vecY, float vecZ){ ofGetCurrentRenderer()->rotate(degrees, vecX, vecY, vecZ); diff --git a/libs/openFrameworks/graphics/ofGraphics.h b/libs/openFrameworks/graphics/ofGraphics.h index ffc7534fc3f..14a7d132dc6 100644 --- a/libs/openFrameworks/graphics/ofGraphics.h +++ b/libs/openFrameworks/graphics/ofGraphics.h @@ -121,12 +121,12 @@ void ofBackgroundHex(int hexColor, int alpha = 255); /// /// Accepted modes are: /// -/// Circular: `OF_GRADIENT_CIRCULAR` -/// Linear: `OF_GRADIENT_LINEAR` -/// Bar: `OF_GRADIENT_BAR` +/// - Circular: `OF_GRADIENT_CIRCULAR` +/// - Linear: `OF_GRADIENT_LINEAR` +/// - Bar: `OF_GRADIENT_BAR` /// /// **Background Gradient: Circular:** -/// ![Background Gradient Circular](graphics/bkgGradient_circular.png) +/// ![Background Gradient Circular](bkgGradient_circular.png) /// ~~~~{.cpp} /// void ofApp::draw(){ /// @@ -139,7 +139,7 @@ void ofBackgroundHex(int hexColor, int alpha = 255); /// ~~~~ /// /// **Background Gradient: Linear:** -/// ![Background Gradient Linear](graphics/bkgGradient_linear.png) +/// ![Background Gradient Linear](bkgGradient_linear.png) /// ~~~~{.cpp} /// void ofApp::draw(){ /// @@ -152,7 +152,7 @@ void ofBackgroundHex(int hexColor, int alpha = 255); /// ~~~~ /// /// **Background Gradient: Bar:** -/// ![Background Gradient Bar](graphics/bkgGradient_bar.png) +/// ![Background Gradient Bar](bkgGradient_bar.png) /// ~~~~{.cpp} /// void ofApp::draw(){ /// @@ -933,6 +933,11 @@ void ofTranslate(const ofPoint & p); void ofScale(float xAmnt, float yAmnt, float zAmnt = 1); +/// \brief Scale along the X, Y and Z axis with the same amount. +void ofScale(float amount); + +void ofScale(const ofPoint & p); + /// \brief Produces a rotation around the vector (vecX,vecY,vecZ). /// /// All graphics drawn after ofRotate is called are rotated. Use ofPushMatrix() @@ -958,17 +963,17 @@ void ofRotate(float degrees); /// ~~~~{.cpp} /// void ofApp::draw(){ /// ofRotateX(45); //rotates the coordinate system 45 degrees around the x-axis -/// ofDrawRea20,20,100,100); +/// ofDrawRectangle(20,20,100,100); /// } /// ~~~~ /// \param degrees Specifies the angle of rotation, in degrees. void ofRotateX(float degrees); /// \brief Produces a rotation around the Y-axis of our coordinate -/// system represented by the vector (1,0,0). +/// system represented by the vector (0,1,0). /// ~~~~{.cpp} /// void ofApp::draw(){ -/// ofRotateY(45); //rotates the coordinate system 45 degrees around the x-axis +/// ofRotateY(45); //rotates the coordinate system 45 degrees around the y-axis /// ofDrawRectangle(20,20,100,100); /// } /// ~~~~ @@ -976,11 +981,11 @@ void ofRotateX(float degrees); void ofRotateY(float degrees); /// \brief Produces a rotation around the Z-axis of our coordinate -/// system represented by the vector (1,0,0). +/// system represented by the vector (0,0,1). /// ~~~~{.cpp} /// void ofApp::draw(){ -/// ofRotateZ(45); //rotates the coordinate system 45 degrees around the x-axis -/// ofDrawRea20,20,100,100); +/// ofRotateZ(45); //rotates the coordinate system 45 degrees around the z-axis +/// ofDrawRectangle(20,20,100,100); /// } /// ~~~~ /// \param degrees Specifies the angle of rotation, in degrees. @@ -1003,12 +1008,13 @@ ofMatrix4x4 ofGetCurrentViewMatrix(); /// \} -/// \name View Setup +/// \name Viewport Setup /// \{ -// push and pop all matrices and viewport +/// \brief Stores the current viewport and matrix settings void ofPushView(); +/// \brief Restores the viewport and matrix settings set by ofPushView() void ofPopView(); /// \brief Get if view is flipped vertically @@ -1021,7 +1027,7 @@ bool ofIsVFlipped(); void ofViewport(ofRectangle viewport); /// \brief Setup the drawing viewport -/// \param x The x position of the viewport +/// \param x The x position of the viewport /// \param y The y position of the viewport /// \param width The width of the viewport, defaults to ofGetWidth() /// \param height The height of the viewport, defaults to ofGetHeight() @@ -1079,7 +1085,7 @@ ofHandednessType ofGetCoordHandedness(); /// } /// ~~~~ /// \sa End drawing with ofEndSaveScreenAsPDF() -void ofBeginSaveScreenAsPDF(string filename, bool bMultipage = false, bool b3D = false, ofRectangle viewport = ofRectangle(0,0,0,0)); +void ofBeginSaveScreenAsPDF(string filename, bool bMultipage = false, bool b3D = false, ofRectangle outputsize = ofRectangle(0,0,0,0)); /// \brief Terminates draw to PDF through ofCairoRenderer and outputs the file. /// \sa ofBeginSaveScreenAsPDF() @@ -1087,7 +1093,7 @@ void ofEndSaveScreenAsPDF(); /// \brief Begin rendering to a SVG file. /// \sa ofEndSaveScreenAsSVG(), ofBeginSaveScreenAsPDF() -void ofBeginSaveScreenAsSVG(string filename, bool bMultipage = false, bool b3D = false, ofRectangle viewport = ofRectangle(0,0,0,0)); +void ofBeginSaveScreenAsSVG(string filename, bool bMultipage = false, bool b3D = false, ofRectangle outputsize = ofRectangle(0,0,0,0)); /// \brief Terminates draw to SVG and outputs the file. /// \sa ofBeginSaveScreenAsSVG() diff --git a/libs/openFrameworks/graphics/ofImage.cpp b/libs/openFrameworks/graphics/ofImage.cpp index c9483f1fed2..310c10ee39a 100644 --- a/libs/openFrameworks/graphics/ofImage.cpp +++ b/libs/openFrameworks/graphics/ofImage.cpp @@ -12,6 +12,8 @@ #include "ofxAndroidUtils.h" #endif +ofImageLoadSettings ofImageLoadSettings::defaultSetting; + //---------------------------------------------------------- // static variable for freeImage initialization: @@ -65,7 +67,7 @@ FIBITMAP* getBmpFromPixels(ofPixels_ &pix){ PixelType* pixels = pix.getData(); unsigned int width = pix.getWidth(); unsigned int height = pix.getHeight(); - unsigned int bpp = pix.getBitsPerPixel(); + unsigned int bpp = pix.getBitsPerPixel(); FREE_IMAGE_TYPE freeImageType = getFreeImageType(pix); FIBITMAP* bmp = FreeImage_AllocateT(freeImageType, width, height, bpp); @@ -96,7 +98,7 @@ FIBITMAP* getBmpFromPixels(ofPixels_ &pix){ //---------------------------------------------------- template -void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_ &pix, bool swapForLittleEndian = true) { +void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_ &pix, bool swapOnLittleEndian = true) { // convert to correct type depending on type of input bmp and PixelType FIBITMAP* bmpConverted = nullptr; FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(bmp); @@ -129,22 +131,23 @@ void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_ &pix, bool swapForLit unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); unsigned int channels = (bpp / sizeof(PixelType)) / 8; - unsigned int pitch = FreeImage_GetPitch(bmp); + unsigned int pitch = FreeImage_GetPitch(bmp); +#ifdef TARGET_LITTLE_ENDIAN + bool swapRG = channels && swapOnLittleEndian && (bpp/channels == 8); +#else + bool swapRG = false; +#endif + ofPixelFormat pixFormat; - if(channels==1) pixFormat=OF_PIXELS_GRAY; -#ifdef TARGET_LITTLE_ENDIAN - if(swapForLittleEndian){ + if(channels==1) pixFormat=OF_PIXELS_GRAY; + if(swapRG){ if(channels==3) pixFormat=OF_PIXELS_BGR; if(channels==4) pixFormat=OF_PIXELS_BGRA; }else{ if(channels==3) pixFormat=OF_PIXELS_RGB; if(channels==4) pixFormat=OF_PIXELS_RGBA; - } -#else - if(channels==3) pixFormat=OF_PIXELS_RGB; - if(channels==4) pixFormat=OF_PIXELS_RGBA; -#endif + } // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); @@ -160,15 +163,23 @@ void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_ &pix, bool swapForLit FreeImage_Unload(bmpConverted); } -#ifdef TARGET_LITTLE_ENDIAN - if(swapForLittleEndian && sizeof(PixelType) == 1 && channels >=3 ) { + if(swapRG && channels >=3 ) { pix.swapRgb(); - } -#endif + } +} + +/// internal +static int getJpegOptionFromImageLoadSetting(const ofImageLoadSettings &settings) { + int option = 0; + if(settings.accurate) option |= JPEG_ACCURATE; + if(settings.exifRotate) option |= JPEG_EXIFROTATE; + if(settings.grayscale) option |= JPEG_GREYSCALE; + if(settings.separateCMYK) option |= JPEG_CMYK; + return option; } template -static bool loadImage(ofPixels_ & pix, string fileName){ +static bool loadImage(ofPixels_ & pix, std::string fileName, const ofImageLoadSettings &settings){ ofInitFreeImage(); #ifndef TARGET_EMSCRIPTEN @@ -195,7 +206,12 @@ static bool loadImage(ofPixels_ & pix, string fileName){ fif = FreeImage_GetFIFFromFilename(fileName.c_str()); } if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { - bmp = FreeImage_Load(fif, fileName.c_str(), 0); + if(fif == FIF_JPEG) { + int option = getJpegOptionFromImageLoadSetting(settings); + bmp = FreeImage_Load(fif, fileName.c_str(), option); + } else { + bmp = FreeImage_Load(fif, fileName.c_str(), 0); + } if (bmp != nullptr){ bLoaded = true; @@ -216,7 +232,7 @@ static bool loadImage(ofPixels_ & pix, string fileName){ } template -static bool loadImage(ofPixels_ & pix, const ofBuffer & buffer){ +static bool loadImage(ofPixels_ & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings){ ofInitFreeImage(); bool bLoaded = false; FIBITMAP* bmp = nullptr; @@ -238,7 +254,12 @@ static bool loadImage(ofPixels_ & pix, const ofBuffer & buffer){ //make the image!! - bmp = FreeImage_LoadFromMemory(fif, hmem, 0); + if(fif == FIF_JPEG) { + int option = getJpegOptionFromImageLoadSetting(settings); + bmp = FreeImage_LoadFromMemory(fif, hmem, option); + } else { + bmp = FreeImage_LoadFromMemory(fif, hmem, 0); + } if( bmp != nullptr ){ bLoaded = true; @@ -261,42 +282,40 @@ static bool loadImage(ofPixels_ & pix, const ofBuffer & buffer){ return bLoaded; } - -//---------------------------------------------------- -bool ofLoadImage(ofPixels & pix, string fileName) { - return loadImage(pix,fileName); +//---------------------------------------------------------------- +bool ofLoadImage(ofPixels & pix, std::string path, const ofImageLoadSettings &settings) { + return loadImage(pix, path, settings); } -//---------------------------------------------------- -bool ofLoadImage(ofPixels & pix, const ofBuffer & buffer) { - return loadImage(pix,buffer); +//---------------------------------------------------------------- +bool ofLoadImage(ofPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) { + return loadImage(pix, buffer, settings); } -//---------------------------------------------------- -bool ofLoadImage(ofFloatPixels & pix, string path){ - return loadImage(pix,path); +//---------------------------------------------------------------- +bool ofLoadImage(ofShortPixels & pix, std::string path, const ofImageLoadSettings &settings) { + return loadImage(pix, path, settings); } -//---------------------------------------------------- -bool ofLoadImage(ofFloatPixels & pix, const ofBuffer & buffer){ - return loadImage(pix,buffer); +//---------------------------------------------------------------- +bool ofLoadImage(ofShortPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) { + return loadImage(pix, buffer, settings); } -//---------------------------------------------------- -bool ofLoadImage(ofShortPixels & pix, string path){ - return loadImage(pix,path); +//---------------------------------------------------------------- +bool ofLoadImage(ofFloatPixels & pix, std::string path, const ofImageLoadSettings &settings) { + return loadImage(pix, path, settings); } -//---------------------------------------------------- -bool ofLoadImage(ofShortPixels & pix, const ofBuffer & buffer){ - return loadImage(pix,buffer); +//---------------------------------------------------------------- +bool ofLoadImage(ofFloatPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) { + return loadImage(pix, buffer, settings); } - //---------------------------------------------------------------- -bool ofLoadImage(ofTexture & tex, string path){ +bool ofLoadImage(ofTexture & tex, std::string path, const ofImageLoadSettings &settings){ ofPixels pixels; - bool loaded = ofLoadImage(pixels,path); + bool loaded = ofLoadImage(pixels, path, settings); if(loaded){ tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); tex.loadData(pixels); @@ -305,9 +324,9 @@ bool ofLoadImage(ofTexture & tex, string path){ } //---------------------------------------------------------------- -bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer){ +bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer, const ofImageLoadSettings &settings){ ofPixels pixels; - bool loaded = ofLoadImage(pixels,buffer); + bool loaded = ofLoadImage(pixels, buffer, settings); if(loaded){ tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); tex.loadData(pixels); @@ -317,7 +336,7 @@ bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer){ //---------------------------------------------------------------- template -static void saveImage(ofPixels_ & pix, string fileName, ofImageQualityType qualityLevel) { +static void saveImage(ofPixels_ & pix, std::string fileName, ofImageQualityType qualityLevel) { ofInitFreeImage(); if (pix.isAllocated() == false){ ofLogError("ofImage") << "saveImage(): couldn't save \"" << fileName << "\", pixels are not allocated"; @@ -388,17 +407,17 @@ static void saveImage(ofPixels_ & pix, string fileName, ofImageQualit } //---------------------------------------------------------------- -void ofSaveImage(ofPixels & pix, string fileName, ofImageQualityType qualityLevel){ +void ofSaveImage(ofPixels & pix, std::string fileName, ofImageQualityType qualityLevel){ saveImage(pix,fileName,qualityLevel); } //---------------------------------------------------------------- -void ofSaveImage(ofFloatPixels & pix, string fileName, ofImageQualityType qualityLevel) { +void ofSaveImage(ofFloatPixels & pix, std::string fileName, ofImageQualityType qualityLevel) { saveImage(pix,fileName,qualityLevel); } //---------------------------------------------------------------- -void ofSaveImage(ofShortPixels & pix, string fileName, ofImageQualityType qualityLevel) { +void ofSaveImage(ofShortPixels & pix, std::string fileName, ofImageQualityType qualityLevel) { saveImage(pix,fileName,qualityLevel); } @@ -467,7 +486,7 @@ static void saveImage(ofPixels_ & pix, ofBuffer & buffer, ofImageForm #ifdef TARGET_WIN32 DWORD size_in_bytes = 0; #else - uint32_t size_in_bytes = 0; + std::uint32_t size_in_bytes = 0; #endif // Save compressed data on mem_buffer // note: FreeImage_AquireMemory allocates space for aux_mem_buffer): @@ -545,7 +564,7 @@ ofImage_::ofImage_(const ofPixels_ & pix){ } template -ofImage_::ofImage_(const ofFile & file){ +ofImage_::ofImage_(const ofFile & file, const ofImageLoadSettings &settings){ width = 0; height = 0; bpp = 0; @@ -556,11 +575,11 @@ ofImage_::ofImage_(const ofFile & file){ ofInitFreeImage(); - load(file); + load(file, settings); } template -ofImage_::ofImage_(const string & filename){ +ofImage_::ofImage_(const std::string & fileName, const ofImageLoadSettings &settings){ width = 0; height = 0; bpp = 0; @@ -571,7 +590,7 @@ ofImage_::ofImage_(const string & filename){ ofInitFreeImage(); - load(filename); + load(fileName, settings); } //---------------------------------------------------------- @@ -579,7 +598,6 @@ template ofImage_& ofImage_::operator=(const ofImage_& mom) { if(&mom==this) return *this; clone(mom); - update(); #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_::unloadTexture); @@ -593,13 +611,25 @@ template ofImage_::ofImage_(const ofImage_& mom) { clear(); clone(mom); - update(); + #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_::update); #endif } +//---------------------------------------------------------- +template +ofImage_::ofImage_(ofImage_&& mom){ + clear(); + clone(mom); + + #if defined(TARGET_ANDROID) + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_::unloadTexture); + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_::update); + #endif +} + //---------------------------------------------------------- template ofImage_::~ofImage_(){ @@ -608,8 +638,8 @@ ofImage_::~ofImage_(){ //---------------------------------------------------------- template -bool ofImage_::load(const ofFile & file){ - return load(file.getAbsolutePath()); +bool ofImage_::load(const ofFile & file, const ofImageLoadSettings &settings){ + return load(file.getAbsolutePath(), settings); } //---------------------------------------------------------- @@ -620,12 +650,12 @@ bool ofImage_::loadImage(const ofFile & file){ //---------------------------------------------------------- template -bool ofImage_::load(const string& fileName){ +bool ofImage_::load(const std::string& fileName, const ofImageLoadSettings &settings){ #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_::update); #endif - bool bLoadedOk = ofLoadImage(pixels, fileName); + bool bLoadedOk = ofLoadImage(pixels, fileName, settings); if (!bLoadedOk) { ofLogError("ofImage") << "loadImage(): couldn't load image from \"" << fileName << "\""; clear(); @@ -637,18 +667,18 @@ bool ofImage_::load(const string& fileName){ //---------------------------------------------------------- template -bool ofImage_::loadImage(string fileName){ +bool ofImage_::loadImage(std::string fileName){ return load(fileName); } //---------------------------------------------------------- template -bool ofImage_::load(const ofBuffer & buffer){ +bool ofImage_::load(const ofBuffer & buffer, const ofImageLoadSettings &settings){ #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_::update); #endif - bool bLoadedOk = ofLoadImage(pixels, buffer); + bool bLoadedOk = ofLoadImage(pixels, buffer, settings); if (!bLoadedOk) { ofLogError("ofImage") << "loadImage(): couldn't load image from ofBuffer"; clear(); @@ -666,7 +696,7 @@ bool ofImage_::loadImage(const ofBuffer & buffer){ //---------------------------------------------------------- template -void ofImage_::save(string fileName, ofImageQualityType qualityLevel){ +void ofImage_::save(std::string fileName, ofImageQualityType qualityLevel){ ofSaveImage(pixels, fileName, qualityLevel); } @@ -684,7 +714,7 @@ void ofImage_::save(const ofFile & file, ofImageQualityType compressi //---------------------------------------------------------- template -void ofImage_::saveImage(string fileName, ofImageQualityType qualityLevel){ +void ofImage_::saveImage(std::string fileName, ofImageQualityType qualityLevel){ save(fileName, qualityLevel); } @@ -784,10 +814,7 @@ void ofImage_::allocate(int w, int h, ofImageType newType){ // take care of texture allocation -- if (pixels.isAllocated() && bUseTexture){ - tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); - if(ofIsGLProgrammableRenderer() && (pixels.getPixelFormat()==OF_PIXELS_GRAY || pixels.getPixelFormat()==OF_PIXELS_GRAY_ALPHA)){ - tex.setRGToRGBASwizzles(true); - } + tex.allocate(pixels); } width = pixels.getWidth(); @@ -957,9 +984,6 @@ void ofImage_::update(){ int glInternalFormat = ofGetGlInternalFormat(pixels); if(!tex.isAllocated() || tex.getWidth() != width || tex.getHeight() != height || tex.getTextureData().glInternalFormat != glInternalFormat){ tex.allocate(pixels); - if(ofIsGLProgrammableRenderer() && (pixels.getPixelFormat()==OF_PIXELS_GRAY || pixels.getPixelFormat()==OF_PIXELS_GRAY_ALPHA)){ - tex.setRGToRGBASwizzles(true); - } }else{ tex.loadData(pixels); } @@ -981,7 +1005,7 @@ bool ofImage_::isUsingTexture() const{ //------------------------------------ template<> void ofImage_::grabScreen(int x, int y, int w, int h){ - shared_ptr renderer = ofGetGLRenderer(); + std::shared_ptr renderer = ofGetGLRenderer(); if(renderer){ renderer->saveScreen(x,y,w,h,pixels); update(); @@ -992,7 +1016,7 @@ void ofImage_::grabScreen(int x, int y, int w, int h){ template void ofGrabScreen(ofPixels_ & pixels, int x, int y, int w, int h){ ofPixels p; - shared_ptr renderer = ofGetGLRenderer(); + std::shared_ptr renderer = ofGetGLRenderer(); if(renderer){ renderer->saveScreen(x,y,w,h,p); pixels = p; @@ -1002,7 +1026,7 @@ void ofGrabScreen(ofPixels_ & pixels, int x, int y, int w, int h){ //------------------------------------ template<> void ofGrabScreen(ofPixels & p, int x, int y, int w, int h){ - shared_ptr renderer = ofGetGLRenderer(); + std::shared_ptr renderer = ofGetGLRenderer(); if(renderer){ renderer->saveScreen(x,y,w,h,p); } @@ -1091,7 +1115,7 @@ void ofImage_::resizePixels(ofPixels_ &pix, int newWidth, FIBITMAP * convertedBmp = nullptr; convertedBmp = FreeImage_Rescale(bmp, newWidth, newHeight, FILTER_BICUBIC); - putBmpIntoPixels(convertedBmp, pix, false); + putBmpIntoPixels(convertedBmp, pix, false); if (bmp != nullptr) FreeImage_Unload(bmp); if (convertedBmp != nullptr) FreeImage_Unload(convertedBmp); @@ -1124,7 +1148,7 @@ void ofImage_::changeTypeOfPixels(ofPixels_ &pix, ofImageT break; } - putBmpIntoPixels(convertedBmp, pix, false); + putBmpIntoPixels(convertedBmp, pix, false); if (bmp != nullptr) { FreeImage_Unload(bmp); diff --git a/libs/openFrameworks/graphics/ofImage.h b/libs/openFrameworks/graphics/ofImage.h index 5c801492269..60adf1ea7af 100644 --- a/libs/openFrameworks/graphics/ofImage.h +++ b/libs/openFrameworks/graphics/ofImage.h @@ -16,7 +16,7 @@ /// the pixels. /// -/// \todo +/// \todo Needs documentation. enum ofImageQualityType { OF_IMAGE_QUALITY_BEST, OF_IMAGE_QUALITY_HIGH, @@ -25,7 +25,7 @@ enum ofImageQualityType { OF_IMAGE_QUALITY_WORST }; -/// \todo +/// \todo Needs documentation. enum ofImageFormat { OF_IMAGE_FORMAT_BMP = 0, OF_IMAGE_FORMAT_ICO = 1, @@ -65,64 +65,74 @@ enum ofImageFormat { OF_IMAGE_FORMAT_RAW = 34 }; +/// \todo Needs documentation. +struct ofImageLoadSettings { + ofImageLoadSettings(bool accurate = false, bool exifRotate = false, bool grayscale = false, bool separateCMYK = false) + : accurate(accurate) + , exifRotate(exifRotate) + , grayscale(grayscale) + , separateCMYK(separateCMYK) {} + bool accurate; + bool exifRotate; + bool grayscale; + bool separateCMYK; + static ofImageLoadSettings defaultSetting; +}; + //---------------------------------------------------- // FreeImage based stuff -/// \todo -bool ofLoadImage(ofPixels & pix, string path); -bool ofLoadImage(ofPixels & pix, const ofBuffer & buffer); -/// \todo -bool ofLoadImage(ofFloatPixels & pix, string path); -bool ofLoadImage(ofFloatPixels & pix, const ofBuffer & buffer); +/// \todo Needs documentation. +bool ofLoadImage(ofPixels & pix, std::string path, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofFloatPixels & pix, std::string path, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofFloatPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofShortPixels & pix, std::string path, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofShortPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); -/// \todo -bool ofLoadImage(ofShortPixels & pix, string path); -bool ofLoadImage(ofShortPixels & pix, const ofBuffer & buffer); +/// \todo Needs documentation. +bool ofLoadImage(ofTexture & tex, std::string path, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); +bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); -/// \todo -bool ofLoadImage(ofTexture & tex, string path); -bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer); - -/// \todo -void ofSaveImage(ofPixels & pix, string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); +/// \todo Needs documentation. +void ofSaveImage(ofPixels & pix, std::string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); void ofSaveImage(ofPixels & pix, ofBuffer & buffer, ofImageFormat format = OF_IMAGE_FORMAT_PNG, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); -/// \todo -void ofSaveImage(ofFloatPixels & pix, string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); +/// \todo Needs documentation. +void ofSaveImage(ofFloatPixels & pix, std::string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); void ofSaveImage(ofFloatPixels & pix, ofBuffer & buffer, ofImageFormat format = OF_IMAGE_FORMAT_PNG, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); -/// \todo -void ofSaveImage(ofShortPixels & pix, string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); +/// \todo Needs documentation. +void ofSaveImage(ofShortPixels & pix, std::string path, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); void ofSaveImage(ofShortPixels & pix, ofBuffer & buffer, ofImageFormat format = OF_IMAGE_FORMAT_PNG, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); -// when we exit, we shut down ofImage -/// \todo +/// \brief Deallocates FreeImage resources. +/// +/// Used internally during shutdown. void ofCloseFreeImage(); - /// \brief A class representing an image using memory and gpu based pixels. /// \tparam PixelType The data type used to represent a single pixel value. template class ofImage_ : public ofBaseImage_{ public: - - /// \name Image Construction /// \{ ofImage_(); ofImage_(const ofPixels_ & pix); - ofImage_(const ofFile & file); - ofImage_(const string & filename); + ofImage_(const ofFile & file, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); + ofImage_(const std::string & fileName, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); ofImage_(const ofImage_& mom); + ofImage_(ofImage_&& mom); template ofImage_(const ofImage_& mom); - /// \brief This allocates space in the ofImage, both the ofPixels and the + /// This allocates space in the ofImage, both the ofPixels and the /// ofTexture that the ofImage contains. /// /// You don't need to call this before loading an image, but for when you @@ -142,7 +152,7 @@ class ofImage_ : public ofBaseImage_{ /// \brief Whether the image has been allocated either by a call to /// allocate or by loading pixel data into the image. /// \returns true if the image has been allocated. - bool isAllocated() const {return pixels.isAllocated();}; + bool isAllocated() const {return pixels.isAllocated();} /// \brief Whether the image has been allocated either by a call to /// allocate or by loading pixel data into the image. @@ -163,24 +173,25 @@ class ofImage_ : public ofBaseImage_{ /// \brief Loads an image given by fileName. /// \param fileName Program looks for image given by fileName, relative to /// the data folder. + /// \param settings Load options /// \returns true if image loaded correctly. - bool load(const string& fileName); + bool load(const std::string& fileName, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); /// \brief Loads an image from an ofBuffer instance created by, for /// instance, ofFile::readToBuffer(). /// /// This actually loads the image data into an ofPixels object and then /// into the texture. - bool load(const ofBuffer & buffer); + bool load(const ofBuffer & buffer, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); /// \brief Loads an image from an ofFile instance created by, for /// instance, ofDirectory::getFiles(). /// /// This actually loads the image data into an ofPixels object and then /// into the texture. - bool load(const ofFile & file); + bool load(const ofFile & file, const ofImageLoadSettings &settings = ofImageLoadSettings::defaultSetting); - OF_DEPRECATED_MSG("Use load instead",bool loadImage(string fileName)); + OF_DEPRECATED_MSG("Use load instead",bool loadImage(std::string fileName)); OF_DEPRECATED_MSG("Use load instead",bool loadImage(const ofBuffer & buffer)); OF_DEPRECATED_MSG("Use load instead",bool loadImage(const ofFile & file)); @@ -300,16 +311,16 @@ class ofImage_ : public ofBaseImage_{ /// \brief Returns whether the ofImage has a texture or not. /// /// If the ofImage doesn't have a texture, nothing will be drawn to the screen. - /// \returns Returns whether the ofImage has a texture or not. + /// \returns true if the ofImage is using a texture. bool isUsingTexture() const; - /// \brief Returns the texture that the ofImage contains. + /// \brief Returns a reference to the texture that the ofImage contains. /// /// You can use this to directly manipulate the texture itself, but keep in /// mind that if you manipulate the texture directly, there is no simple way /// to copy the data from the texture back to the pixels and keep the ofImage in sync. /// - /// \returns Returns the texture that the ofImage contains. + /// \returns A reference to the texture that the ofImage contains. ofTexture & getTexture(); const ofTexture & getTexture() const; OF_DEPRECATED_MSG("Use getTexture",ofTexture & getTextureReference()); @@ -545,7 +556,7 @@ class ofImage_ : public ofBaseImage_{ /// /// \param fileName Saves image to this path, relative to the data folder. /// \param compressionLevel The ofImageQualityType. - void save(string fileName, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST); + void save(std::string fileName, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST); /// \brief This saves the image to the ofBuffer passed with the image /// quality specified by compressionLevel. @@ -560,7 +571,7 @@ class ofImage_ : public ofBaseImage_{ /// `OF_IMAGE_QUALITY_MEDIUM`, `OF_IMAGE_QUALITY_LOW`, `OF_IMAGE_QUALITY_WORST` void save(const ofFile & file, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST); - OF_DEPRECATED_MSG("Use save instead",void saveImage(string fileName, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST)); + OF_DEPRECATED_MSG("Use save instead",void saveImage(std::string fileName, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST)); OF_DEPRECATED_MSG("Use save instead",void saveImage(ofBuffer & buffer, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST)); OF_DEPRECATED_MSG("Use save instead",void saveImage(const ofFile & file, ofImageQualityType compressionLevel = OF_IMAGE_QUALITY_BEST)); @@ -578,6 +589,7 @@ class ofImage_ : public ofBaseImage_{ /// \} ///< \sa ofImageType + protected: /// \cond INTERNAL void changeTypeOfPixels(ofPixels_ &pix, ofImageType type); diff --git a/libs/openFrameworks/graphics/ofPath.cpp b/libs/openFrameworks/graphics/ofPath.cpp index c0766ebd326..9aca5e8943c 100644 --- a/libs/openFrameworks/graphics/ofPath.cpp +++ b/libs/openFrameworks/graphics/ofPath.cpp @@ -5,7 +5,7 @@ #if defined(TARGET_EMSCRIPTEN) ofTessellator ofPath::tessellator; #elif HAS_TLS - thread_local ofTessellator ofPath::tessellator; + thread_local ofTessellator ofPath::tessellator; #endif ofPath::Command::Command(Type type) @@ -454,6 +454,8 @@ ofPolyline & ofPath::lastPolyline(){ vector & ofPath::getCommands(){ if(mode==POLYLINES){ ofLogWarning("ofPath") << "getCommands(): trying to get path commands from shape with polylines only"; + }else{ + flagShapeChanged(); } return commands; } @@ -551,17 +553,6 @@ void ofPath::tessellate(){ bNeedsTessellation = false; } -//---------------------------------------------------------- -vector & ofPath::getOutline() { - if(windingMode!=OF_POLY_WINDING_ODD){ - tessellate(); - return tessellatedContour; - }else{ - generatePolylinesFromCommands(); - return polylines; - } -} - //---------------------------------------------------------- const vector & ofPath::getOutline() const{ if(windingMode!=OF_POLY_WINDING_ODD){ @@ -573,12 +564,6 @@ const vector & ofPath::getOutline() const{ } } -//---------------------------------------------------------- -ofMesh & ofPath::getTessellation(){ - tessellate(); - return cachedTessellation; -} - //---------------------------------------------------------- const ofMesh & ofPath::getTessellation() const{ const_cast(this)->tessellate(); @@ -779,6 +764,19 @@ void ofPath::scale(float x, float y){ flagShapeChanged(); } +void ofPath::append(const ofPath & path){ + if(mode==COMMANDS){ + for(auto & command: path.getCommands()){ + addCommand(command); + } + }else{ + for(auto & poly: path.getOutline()){ + polylines.push_back(poly); + } + } + flagShapeChanged(); +} + void ofPath::addCommand(const ofPath::Command & command){ if((commands.empty() || commands.back().type==Command::close) && command.type!=Command::moveTo){ commands.push_back(Command(Command::moveTo,command.to)); diff --git a/libs/openFrameworks/graphics/ofPath.h b/libs/openFrameworks/graphics/ofPath.h index 0829c4dab7e..908a4cd6b1a 100644 --- a/libs/openFrameworks/graphics/ofPath.h +++ b/libs/openFrameworks/graphics/ofPath.h @@ -300,19 +300,13 @@ class ofPath{ /// \{ /// \brief Get an ofPolyline representing the outline of the ofPath. - vector & getOutline(); const vector & getOutline() const; void tessellate(); - ofMesh & getTessellation(); const ofMesh & getTessellation() const; - void simplify(float tolerance=0.3); - - // only needs to be called when path is modified externally - void flagShapeChanged(); - bool hasChanged(); + void simplify(float tolerance=0.3f); void translate(const ofPoint & p); void rotate(float az, const ofVec3f& axis ); @@ -322,6 +316,8 @@ class ofPath{ /// scaling by 0,0 zeros out all data. void scale(float x, float y); + void append(const ofPath & path); + /// \} /// \name Path Mode /// \{ @@ -380,6 +376,10 @@ class ofPath{ void addCommand(const Command & command); void generatePolylinesFromCommands(); + // only needs to be called when path is modified externally + void flagShapeChanged(); + bool hasChanged(); + // path description //vector paths; vector commands; diff --git a/libs/openFrameworks/graphics/ofPixels.cpp b/libs/openFrameworks/graphics/ofPixels.cpp index 62e22df7731..32aa2600477 100644 --- a/libs/openFrameworks/graphics/ofPixels.cpp +++ b/libs/openFrameworks/graphics/ofPixels.cpp @@ -16,37 +16,37 @@ static ofImageType getImageTypeFromChannels(int channels){ } template -static float pixelBytesFromPixelFormat(ofPixelFormat format){ +static int pixelBitsFromPixelFormat(ofPixelFormat format){ switch(format){ case OF_PIXELS_RGB: case OF_PIXELS_BGR: - return 3 * sizeof(PixelType); + return 3 * sizeof(PixelType) * 8; case OF_PIXELS_RGBA: case OF_PIXELS_BGRA: - return 4 * sizeof(PixelType); + return 4 * sizeof(PixelType) * 8; case OF_PIXELS_GRAY: case OF_PIXELS_Y: case OF_PIXELS_U: case OF_PIXELS_V: - return 1 * sizeof(PixelType); + return 1 * sizeof(PixelType) * 8; case OF_PIXELS_NV12: case OF_PIXELS_NV21: case OF_PIXELS_YV12: case OF_PIXELS_I420: - return 1.5; + return 12; case OF_PIXELS_UV: case OF_PIXELS_VU: case OF_PIXELS_GRAY_ALPHA: - return 2 * sizeof(PixelType); + return 2 * sizeof(PixelType) * 8; case OF_PIXELS_YUY2: case OF_PIXELS_UYVY: case OF_PIXELS_RGB565: - return 2; + return 16; break; default: return 0; @@ -56,7 +56,7 @@ static float pixelBytesFromPixelFormat(ofPixelFormat format){ template static int bytesFromPixelFormat(int w, int h, ofPixelFormat format){ - return w*h*pixelBytesFromPixelFormat(format); + return w*h*pixelBitsFromPixelFormat(format)/8; } static int channelsFromPixelFormat(ofPixelFormat format){ @@ -125,6 +125,7 @@ static ofImageType ofImageTypeFromPixelFormat(ofPixelFormat pixelFormat){ break; case OF_PIXELS_BGR: case OF_PIXELS_RGB: + case OF_PIXELS_RGB565: return OF_IMAGE_COLOR; break; case OF_PIXELS_BGRA: @@ -209,6 +210,18 @@ ofPixels_::ofPixels_(const ofPixels_ & mom){ copyFrom( mom ); } +template +ofPixels_::ofPixels_(ofPixels_ && mom) +:pixels(mom.pixels) +,width(mom.width) +,height(mom.height) +,pixelsSize(mom.pixelsSize) +,bAllocated(mom.bAllocated) +,pixelsOwner(mom.pixelsOwner) +,pixelFormat(mom.pixelFormat){ + mom.pixelsOwner = false; +} + template ofPixels_& ofPixels_::operator=(const ofPixels_ & mom){ if(this==&mom) { @@ -218,6 +231,26 @@ ofPixels_& ofPixels_::operator=(const ofPixels_ return *this; } +template +ofPixels_& ofPixels_::operator=(ofPixels_ && mom){ + if(this==&mom) { + return * this; + } + if(pixelsOwner || !bAllocated || !mom.bAllocated || width!=mom.width || height!=mom.height || pixelFormat != mom.pixelFormat){ + clear(); + pixels = mom.pixels; + width = mom.width; + height = mom.height; + pixelsSize = mom.pixelsSize; + bAllocated = mom.bAllocated; + pixelsOwner = mom.pixelsOwner; + mom.pixelsOwner = false; + }else{ + memcpy(pixels, mom.pixels, getTotalBytes()); + } + return *this; +} + template void ofPixels_::copyFrom(const ofPixels_ & mom){ if(mom.isAllocated()) { @@ -242,10 +275,10 @@ void ofPixels_::set(int channel,PixelType val){ case OF_PIXELS_RGBA: case OF_PIXELS_BGRA: case OF_PIXELS_GRAY: - case OF_PIXELS_GRAY_ALPHA:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_UV: + case OF_PIXELS_VU:{ + for(auto pixel: getPixelsIter()){ pixel[channel] = val; } } @@ -259,9 +292,7 @@ void ofPixels_::set(int channel,PixelType val){ case OF_PIXELS_UYVY: case OF_PIXELS_Y: case OF_PIXELS_U: - case OF_PIXELS_V: - case OF_PIXELS_UV: - case OF_PIXELS_VU: + case OF_PIXELS_V: case OF_PIXELS_UNKNOWN: default: ofLogWarning() << "setting channels not supported for " << ofToString(pixelFormat) << " format"; @@ -322,7 +353,7 @@ void ofPixels_::setFromAlignedPixels(const PixelType * newPixels, int return; } allocate(width, height, _pixelFormat); - int dstStride = width * pixelBytesFromPixelFormat(_pixelFormat); + int dstStride = width * pixelBitsFromPixelFormat(_pixelFormat)/8; const unsigned char* src = (unsigned char*) newPixels; unsigned char* dst = (unsigned char*) pixels; for(int i = 0; i < height; i++) { @@ -332,6 +363,60 @@ void ofPixels_::setFromAlignedPixels(const PixelType * newPixels, int } } +template +void ofPixels_::setFromAlignedPixels(const PixelType * newPixels, int width, int height, ofPixelFormat _pixelFormat, std::vector strides) { + int channels = channelsFromPixelFormat(_pixelFormat); + if(channels==0) return; + + switch(pixelFormat){ + case OF_PIXELS_I420: { + if(strides.size() != 3){ + ofLogError("ofPixels") << "number of planes for I420 should be 3"; + break; + } + + if(width==strides[0] && width/2==strides[1] && width/2==strides[2]){ + setFromPixels(newPixels,width,height,_pixelFormat); + return; + } + + allocate(width, height, _pixelFormat); + + const unsigned char* src = (unsigned char*) newPixels; + unsigned char* dst = (unsigned char*) pixels; + // Y Plane + for(int i = 0; i < height; i++) { + memcpy(dst, src, width); + src += strides[0]; + dst += width; + } + // U Plane + for(int i = 0; i < height /2; i++){ + memcpy(dst,src,width/2); + src += strides[1]; + dst += width/2; + } + // V Plane + for(int i = 0; i < height /2; i++){ + memcpy(dst,src,width/2); + src += strides[2]; + dst += width/2; + } + break; + } + case OF_PIXELS_RGB: + case OF_PIXELS_RGBA: + case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: + setFromAlignedPixels(newPixels,width,height,_pixelFormat,strides[0]); + return; + default: + ofLogError("ofPixels") << "setFromAlignedPixels with planes strides: pixel format not supported yet"; + break; + } + return; +} + template void ofPixels_::swap(ofPixels_ & pix){ std::swap(pixels,pix.pixels); @@ -385,8 +470,9 @@ void ofPixels_::allocate(int w, int h, ofPixelFormat format){ } int newSize = bytesFromPixelFormat(w,h,format); + int oldSize = getTotalBytes(); //we check if we are already allocated at the right size - if(bAllocated && newSize==getTotalBytes()){ + if(bAllocated && newSize==oldSize){ pixelFormat = format; width = w; height = h; @@ -419,9 +505,7 @@ void ofPixels_::swapRgb(){ case OF_PIXELS_BGR: case OF_PIXELS_RGBA: case OF_PIXELS_BGRA:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ std::swap(pixel[0],pixel[2]); } } @@ -480,10 +564,17 @@ int ofPixels_::getPixelIndex(int x, int y) const { return ( x + y * width ) * pixelStride; break; case OF_PIXELS_GRAY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: pixelStride = 1; return ( x + y * width ) * pixelStride; break; case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: pixelStride = 2; return ( x + y * width ) * pixelStride; break; @@ -493,14 +584,7 @@ int ofPixels_::getPixelIndex(int x, int y) const { break; case OF_PIXELS_NV12: case OF_PIXELS_YV12: - case OF_PIXELS_I420: - case OF_PIXELS_YUY2: - case OF_PIXELS_UYVY: - case OF_PIXELS_Y: - case OF_PIXELS_U: - case OF_PIXELS_V: - case OF_PIXELS_UV: - case OF_PIXELS_VU: + case OF_PIXELS_I420: case OF_PIXELS_UNKNOWN: default: ofLogWarning() << "getting pixel index not supported for " << ofToString(pixelFormat) << " format"; @@ -581,9 +665,7 @@ template void ofPixels_::setColor(const ofColor_& color) { switch(pixelFormat){ case OF_PIXELS_RGB:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ pixel[0] = color.r; pixel[1] = color.g; pixel[2] = color.b; @@ -591,9 +673,7 @@ void ofPixels_::setColor(const ofColor_& color) { } break; case OF_PIXELS_BGR:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ pixel[0] = color.b; pixel[1] = color.g; pixel[2] = color.r; @@ -601,9 +681,7 @@ void ofPixels_::setColor(const ofColor_& color) { } break; case OF_PIXELS_RGBA:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ pixel[0] = color.r; pixel[1] = color.g; pixel[2] = color.b; @@ -612,9 +690,7 @@ void ofPixels_::setColor(const ofColor_& color) { } break; case OF_PIXELS_BGRA:{ - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ pixel[0] = color.b; pixel[1] = color.g; pixel[2] = color.r; @@ -631,9 +707,7 @@ void ofPixels_::setColor(const ofColor_& color) { break; case OF_PIXELS_GRAY_ALPHA:{ PixelType b = color.getBrightness(); - Pixels pixels = getPixelsIter(); - Pixel _end = pixels.end(); - for(Pixel pixel=pixels.begin();pixel!=_end;pixel++){ + for(auto pixel: getPixelsIter()){ pixel[0] = b; pixel[1] = color.a; } @@ -685,12 +759,12 @@ int ofPixels_::getHeight() const{ template int ofPixels_::getBytesPerPixel() const{ - return pixelBytesFromPixelFormat(pixelFormat); + return pixelBitsFromPixelFormat(pixelFormat)/8; } template int ofPixels_::getBitsPerPixel() const{ - return pixelBytesFromPixelFormat(pixelFormat)*8; + return pixelBitsFromPixelFormat(pixelFormat); } template @@ -705,7 +779,7 @@ int ofPixels_::getBitsPerChannel() const{ template int ofPixels_::getBytesStride() const{ - return pixelBytesFromPixelFormat(pixelFormat) * width; + return pixelBitsFromPixelFormat(pixelFormat) * width / 8; } template @@ -727,6 +801,7 @@ int ofPixels_::getNumPlanes() const{ case OF_PIXELS_RGBA: case OF_PIXELS_BGRA: case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: case OF_PIXELS_YUY2: case OF_PIXELS_UYVY: case OF_PIXELS_Y: @@ -735,18 +810,18 @@ int ofPixels_::getNumPlanes() const{ case OF_PIXELS_UV: case OF_PIXELS_VU: return 1; - break; case OF_PIXELS_NV12: case OF_PIXELS_NV21: return 2; - break; case OF_PIXELS_YV12: case OF_PIXELS_I420: return 3; - break; - default: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: return 0; } + return 0; } template @@ -760,8 +835,14 @@ ofPixels_ ofPixels_::getPlane(int planeIdx){ case OF_PIXELS_RGBA: case OF_PIXELS_BGRA: case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: case OF_PIXELS_YUY2: case OF_PIXELS_UYVY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: plane.setFromExternalPixels(pixels,width,height,pixelFormat); break; case OF_PIXELS_NV12: @@ -810,10 +891,12 @@ ofPixels_ ofPixels_::getPlane(int planeIdx){ break; } break; - default: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: break; } - return plane; + return std::move(plane); } template @@ -828,14 +911,16 @@ void ofPixels_::setImageType(ofImageType imageType){ dst.allocate(width,height,imageType); PixelType * dstPtr = &dst[0]; PixelType * srcPtr = &pixels[0]; + int dstNumChannels = dst.getNumChannels(); + int srcNumChannels = getNumChannels(); int diffNumChannels = 0; - if(dst.getNumChannels() ofPixels_::getChannel(int channel) const{ channelPixels.allocate(width,height,1); channel = ofClamp(channel,0,channels-1); iterator channelPixel = channelPixels.begin(); - const_iterator _end = end(); - for(const_iterator i=begin()+channel;i<_end;i+=channels,++channelPixel){ - *channelPixel = *i; + for(auto p: getConstPixelsIter()){ + *channelPixel++ = p[channel]; } - return channelPixels; + return std::move(channelPixels); } template void ofPixels_::setChannel(int channel, const ofPixels_ channelPixels){ int channels = channelsFromPixelFormat(pixelFormat); - if(channels==0) return; + if(channels==0) return; - channel = ofClamp(channel,0,channels-1); + channel = ofClamp(channel,0,channels-1); const_iterator channelPixel = channelPixels.begin(); - iterator _end = end(); - for(iterator i=begin()+channel;i<_end;i+=channels,++channelPixel){ - *i = *channelPixel; + for(auto p: getPixelsIter()){ + p[channel] = *channelPixel++; } } @@ -923,16 +1006,16 @@ void ofPixels_::cropTo(ofPixels_ &toPix, int x, int y, int } // this prevents having to do a check for bounds in the for loop; - int minX = MAX(x, 0) * getNumChannels(); - int maxX = MIN(x+_width, width) * getNumChannels(); + int minX = MAX(x, 0); + int maxX = MIN(x+_width, width); int minY = MAX(y, 0); int maxY = MIN(y+_height, height); - iterator newPixel = toPix.begin(); - for(ConstLine line = getConstLines().begin()+minY; line!=getConstLines().begin()+maxY; ++line ){ - for(const_iterator pixel = line.begin()+minX; pixel::mirrorTo(ofPixels_ & dst, bool vertically, } int bytesPerPixel = getNumChannels(); + dst.allocate(width, height, getPixelFormat()); if(vertically && !horizontal){ - ofPixels_::Lines dstLines = dst.getLines(); - ofPixels_::ConstLine lineSrc = getConstLines().begin(); - ofPixels_::Line line = --dstLines.end(); + auto dstLines = dst.getLines(); + auto lineSrc = getConstLines().begin(); + auto line = --dstLines.end(); + auto stride = line.getStride(); for(; line>=dstLines.begin(); --line, ++lineSrc){ - memcpy(line.begin(),lineSrc.begin(),line.getStride()); + memcpy(line.begin(), lineSrc.begin(), stride); } }else if (!vertically && horizontal){ int wToDo = width/2; @@ -1131,7 +1216,7 @@ bool ofPixels_::resize(int dstWidth, int dstHeight, ofInterpolationMe if ((dstWidth<=0) || (dstHeight<=0) || !(isAllocated())) return false; ofPixels_ dstPixels; - dstPixels.allocate(dstWidth, dstHeight,getImageType()); + dstPixels.allocate(dstWidth, dstHeight, getPixelFormat()); if(!resizeTo(dstPixels,interpMethod)) return false; diff --git a/libs/openFrameworks/graphics/ofPixels.h b/libs/openFrameworks/graphics/ofPixels.h index e18fc79e20e..bbdf5aa937d 100644 --- a/libs/openFrameworks/graphics/ofPixels.h +++ b/libs/openFrameworks/graphics/ofPixels.h @@ -65,6 +65,7 @@ class ofPixels_ { ofPixels_(); ~ofPixels_(); ofPixels_(const ofPixels_ & mom); + ofPixels_(ofPixels_ && mom); template ofPixels_(const ofPixels_ & mom); @@ -115,6 +116,7 @@ class ofPixels_ { void clear(); ofPixels_& operator=(const ofPixels_ & mom); + ofPixels_& operator=(ofPixels_ && mom); template ofPixels_& operator=(const ofPixels_ & mom); @@ -132,6 +134,8 @@ class ofPixels_ { void setFromExternalPixels(PixelType * newPixels,int w, int h, ofPixelFormat pixelFormat); void setFromAlignedPixels(const PixelType * newPixels, int width, int height, int channels, int stride); void setFromAlignedPixels(const PixelType * newPixels, int width, int height, ofPixelFormat pixelFormat, int stride); + /// \brief used to copy i420 pixels from gstreamer when (width % 4) != 0 + void setFromAlignedPixels(const PixelType * newPixels, int width, int height, ofPixelFormat pixelFormat, std::vector strides); void swap(ofPixels_ & pix); @@ -253,8 +257,8 @@ class ofPixels_ { /// \brief Get number of bits per pixel /// - /// If you have RGB pixel data, this will return 3, if you have RGBA, - /// you'll have 4, if you have grayscale, this will return 1. + /// If you have RGB pixel data, this will return 24, if you have RGBA, + /// you'll have 32, if you have grayscale, this will return 8. int getBitsPerPixel() const; /// \brief Get how large each channel of a pixel is @@ -351,6 +355,28 @@ class ofPixels_ { /// \cond INTERNAL + struct ConstPixel: public std::iterator{ + ConstPixel(const PixelType * pixel, int bytesPerPixel, ofPixelFormat pixelFormat); + const ConstPixel& operator*() const; + const ConstPixel* operator->() const; + ConstPixel& operator++(); + ConstPixel operator++(int); + ConstPixel operator+(int) const; + ConstPixel operator-(int) const; + ConstPixel operator+=(int); + bool operator!=(ConstPixel const& rhs) const; + bool operator<(ConstPixel const& rhs) const; + const PixelType & operator[](int idx) const; + int getComponentsPerPixel() const; + ofPixelFormat getPixelFormat() const; + ofColor_ getColor() const; + + private: + const PixelType * pixel; + int componentsPerPixel; + ofPixelFormat pixelFormat; + }; + struct Pixel: public std::iterator{ Pixel(PixelType * pixel, int bytesPerPixel, ofPixelFormat pixelFormat); const Pixel& operator*() const; @@ -364,6 +390,8 @@ class ofPixels_ { Pixel operator+=(int); bool operator!=(Pixel const& rhs) const; bool operator<(Pixel const& rhs) const; + Pixel & operator=(Pixel const& rhs); + Pixel & operator=(ConstPixel const& rhs); PixelType & operator[](int idx); const PixelType & operator[](int idx) const; int getComponentsPerPixel() const; @@ -410,7 +438,9 @@ class ofPixels_ { ofPixels_ asPixels(); const ofPixels_ asPixels() const; int getStride() const; + Pixel getPixel(int pixel); Pixels getPixels(); + Pixels getPixels(int first, int numPixels); private: PixelType * _begin; @@ -438,28 +468,6 @@ class ofPixels_ { ofPixelFormat pixelFormat; }; - struct ConstPixel: public std::iterator{ - ConstPixel(const PixelType * pixel, int bytesPerPixel, ofPixelFormat pixelFormat); - const ConstPixel& operator*() const; - const ConstPixel* operator->() const; - ConstPixel& operator++(); - ConstPixel operator++(int); - ConstPixel operator+(int) const; - ConstPixel operator-(int) const; - ConstPixel operator+=(int); - bool operator!=(ConstPixel const& rhs) const; - bool operator<(ConstPixel const& rhs) const; - const PixelType & operator[](int idx) const; - int getComponentsPerPixel() const; - ofPixelFormat getPixelFormat() const; - ofColor_ getColor() const; - - private: - const PixelType * pixel; - int componentsPerPixel; - ofPixelFormat pixelFormat; - }; - struct ConstPixels{ ConstPixels(const PixelType * begin, const PixelType * end, int componentsPerPixel, ofPixelFormat pixelFormat); ConstPixels(const ConstPixel & begin, const ConstPixel & end); @@ -486,7 +494,9 @@ class ofPixels_ { const PixelType * end() const; int getLineNum() const; int getStride() const; + ConstPixel getPixel(int pixel) const; ConstPixels getPixels() const; + ConstPixels getPixels(int first, int numPixels) const; private: const PixelType * _begin; @@ -515,9 +525,11 @@ class ofPixels_ { Line getLine(int line); Lines getLines(); + Lines getLines(int first, int numLines); Pixels getPixelsIter(); ConstLine getConstLine(int line) const; ConstLines getConstLines() const; + ConstLines getConstLines(int first, int numLines) const; ConstPixels getConstPixelsIter() const; /// \endcond @@ -605,49 +617,49 @@ void ofPixels_::copyFrom(const ofPixels_ & mom){ //---------------------------------------------------------------------- template inline typename ofPixels_::iterator ofPixels_::begin(){ - return &pixels[0]; + return pixels; } //---------------------------------------------------------------------- template inline typename ofPixels_::iterator ofPixels_::end(){ - return &pixels[size()]; + return pixels + size(); } //---------------------------------------------------------------------- template inline typename ofPixels_::const_iterator ofPixels_::begin() const{ - return &pixels[0]; + return pixels; } //---------------------------------------------------------------------- template inline typename ofPixels_::const_iterator ofPixels_::end() const{ - return &pixels[size()]; + return pixels + size(); } //---------------------------------------------------------------------- template inline typename ofPixels_::reverse_iterator ofPixels_::rbegin(){ - return &pixels[size()]; + return pixels + (size() - 1); } //---------------------------------------------------------------------- template inline typename ofPixels_::reverse_iterator ofPixels_::rend(){ - return &pixels[-1]; + return pixels - 1; } //---------------------------------------------------------------------- template inline typename ofPixels_::const_reverse_iterator ofPixels_::rbegin() const{ - return &pixels[size()]; + return pixels + (size() - 1); } //---------------------------------------------------------------------- template inline typename ofPixels_::const_reverse_iterator ofPixels_::rend() const{ - return &pixels[-1]; + return pixels - 1; } //---------------------------------------------------------------------- @@ -732,6 +744,24 @@ inline bool ofPixels_::Pixel::operator<(Pixel const& rhs) const{ return pixel < rhs.pixel; } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::Pixel & ofPixels_::Pixel::operator=(Pixel const& rhs){ + for(int i=0;i +inline typename ofPixels_::Pixel & ofPixels_::Pixel::operator=(ConstPixel const& rhs){ + for(int i=0;i inline PixelType & ofPixels_::Pixel::operator[](int idx){ @@ -959,16 +989,16 @@ inline int ofPixels_::Line::getLineNum() const{ template inline ofPixels_ ofPixels_::Line::asPixels(){ ofPixels_ pixels; - pixels.setFromExternalPixels(_begin,stride,pixelFormat,1); - return pixels; + pixels.setFromExternalPixels(_begin,stride/componentsPerPixel,1,pixelFormat); + return std::move(pixels); } //---------------------------------------------------------------------- template inline const ofPixels_ ofPixels_::Line::asPixels() const{ ofPixels_ pixels; - pixels.setFromExternalPixels(_begin,stride,pixelFormat,1); - return pixels; + pixels.setFromExternalPixels(_begin,stride/componentsPerPixel,1,pixelFormat); + return std::move(pixels); } //---------------------------------------------------------------------- @@ -977,12 +1007,24 @@ inline int ofPixels_::Line::getStride() const{ return stride; } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::Pixel ofPixels_::Line::getPixel(int pixel){ + return Pixel(_begin + (pixel*componentsPerPixel), componentsPerPixel, pixelFormat); +} + //---------------------------------------------------------------------- template inline typename ofPixels_::Pixels ofPixels_::Line::getPixels(){ return Pixels(_begin,_end,componentsPerPixel,pixelFormat); } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::Pixels ofPixels_::Line::getPixels(int first, int numPixels){ + return Pixels(&getPixel(first)[0], &getPixel(first+numPixels)[0], componentsPerPixel, pixelFormat); +} + //---------------------------------------------------------------------- template inline ofPixels_::Lines::Lines(PixelType * _begin, PixelType * _end, int stride, int componentsPerPixel, int lines, ofPixelFormat pixelFormat) @@ -1018,6 +1060,12 @@ inline typename ofPixels_::Lines ofPixels_::getLines(){ return Lines(begin(),end(),width*getNumChannels(),getNumChannels(),getHeight(),pixelFormat); } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::Lines ofPixels_::getLines(int first, int numLines){ + return Lines(getLine(first).begin(),getLine(first+numLines).begin(),width*getNumChannels(),getNumChannels(),numLines,pixelFormat); +} + //---------------------------------------------------------------------- template inline typename ofPixels_::Pixels ofPixels_::getPixelsIter(){ @@ -1272,12 +1320,24 @@ inline int ofPixels_::ConstLine::getStride() const{ return stride; } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::ConstPixel ofPixels_::ConstLine::getPixel(int pixel) const{ + return ConstPixel(_begin + (pixel*componentsPerPixel), componentsPerPixel, pixelFormat); +} + //---------------------------------------------------------------------- template inline typename ofPixels_::ConstPixels ofPixels_::ConstLine::getPixels() const{ return ConstPixels(_begin,_end,componentsPerPixel,pixelFormat); } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::ConstPixels ofPixels_::ConstLine::getPixels(int first, int numPixels) const{ + return ConstPixels(&getPixel(first)[0], &getPixel(first+numPixels)[0], componentsPerPixel, pixelFormat); +} + //---------------------------------------------------------------------- template inline ofPixels_::ConstLines::ConstLines(const PixelType * _begin, const PixelType * _end, int stride, int componentsPerPixel, int lines, ofPixelFormat pixelFormat) @@ -1313,6 +1373,12 @@ inline typename ofPixels_::ConstLines ofPixels_::getConstL return ConstLines(begin(),end(),width*getNumChannels(),getNumChannels(),getHeight(),pixelFormat); } +//---------------------------------------------------------------------- +template +inline typename ofPixels_::ConstLines ofPixels_::getConstLines(int first, int numLines) const{ + return ConstLines(getConstLine(first).begin(),getConstLine(first+numLines).begin(),width*getNumChannels(),getNumChannels(),numLines,pixelFormat); +} + //---------------------------------------------------------------------- template inline typename ofPixels_::ConstPixels ofPixels_::getConstPixelsIter() const{ diff --git a/libs/openFrameworks/graphics/ofTessellator.cpp b/libs/openFrameworks/graphics/ofTessellator.cpp index 974a40372ec..a5aea61c7d5 100644 --- a/libs/openFrameworks/graphics/ofTessellator.cpp +++ b/libs/openFrameworks/graphics/ofTessellator.cpp @@ -111,9 +111,11 @@ void ofTessellator::tessellateToMesh( const vector& src, ofPolyWindi // pass vertex pointers to GLU tessellator for ( int i=0; i<(int)src.size(); ++i ) { - ofPolyline& polyline = const_cast(src[i]); + if (src[i].size() > 0) { + ofPolyline& polyline = const_cast(src[i]); - tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0].x, sizeof(ofPoint), polyline.size()); + tessAddContour(cacheTess, bIs2D ? 2 : 3, &polyline.getVertices()[0].x, sizeof(ofPoint), polyline.size()); + } } performTessellation( polyWindingMode, dstmesh, bIs2D ); @@ -122,9 +124,10 @@ void ofTessellator::tessellateToMesh( const vector& src, ofPolyWindi //---------------------------------------------------------- void ofTessellator::tessellateToPolylines( const ofPolyline& src, ofPolyWindingMode polyWindingMode, vector& dstpoly, bool bIs2D){ - ofPolyline& polyline = const_cast(src); - tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0], sizeof(ofPoint), polyline.size()); - + if (src.size() > 0) { + ofPolyline& polyline = const_cast(src); + tessAddContour(cacheTess, bIs2D ? 2 : 3, &polyline.getVertices()[0], sizeof(ofPoint), polyline.size()); + } performTessellation( polyWindingMode, dstpoly, bIs2D ); } @@ -134,9 +137,11 @@ void ofTessellator::tessellateToPolylines( const vector& src, ofPoly // pass vertex pointers to GLU tessellator for ( int i=0; i<(int)src.size(); ++i ) { - ofPolyline& polyline = const_cast(src[i]); + if (src[i].size() > 0) { + ofPolyline& polyline = const_cast(src[i]); - tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0].x, sizeof(ofPoint), polyline.size()); + tessAddContour(cacheTess, bIs2D ? 2 : 3, &polyline.getVertices()[0].x, sizeof(ofPoint), polyline.size()); + } } performTessellation( polyWindingMode, dstpoly, bIs2D ); diff --git a/libs/openFrameworks/graphics/ofTrueTypeFont.cpp b/libs/openFrameworks/graphics/ofTrueTypeFont.cpp index 44a11a10c03..0262ab41e6b 100644 --- a/libs/openFrameworks/graphics/ofTrueTypeFont.cpp +++ b/libs/openFrameworks/graphics/ofTrueTypeFont.cpp @@ -13,10 +13,136 @@ #include FT_TRIGONOMETRY_H #include +#include #include "ofUtils.h" #include "ofGraphics.h" #include "ofAppRunner.h" +#include "utf8.h" + + +const ofUnicode::range ofUnicode::Space {32, 32}; +const ofUnicode::range ofUnicode::Latin {32, 0x007F}; +const ofUnicode::range ofUnicode::Latin1Supplement {32,0x00FF}; +const ofUnicode::range ofUnicode::Greek {0x0370, 0x03FF}; +const ofUnicode::range ofUnicode::Cyrillic {0x0400, 0x04FF}; +const ofUnicode::range ofUnicode::Arabic {0x0600, 0x077F}; +const ofUnicode::range ofUnicode::ArabicSupplement {0x0750, 0x077F}; +const ofUnicode::range ofUnicode::ArabicExtendedA {0x08A0, 0x08FF}; +const ofUnicode::range ofUnicode::Devanagari {0x0900, 0x097F}; +const ofUnicode::range ofUnicode::HangulJamo {0x1100, 0x11FF}; +const ofUnicode::range ofUnicode::VedicExtensions {0x1CD0, 0x1CFF}; +const ofUnicode::range ofUnicode::LatinExtendedAdditional {0x1E00, 0x1EFF}; +const ofUnicode::range ofUnicode::GreekExtended {0x1F00, 0x1FFF}; +const ofUnicode::range ofUnicode::GeneralPunctuation {0x2000, 0x206F}; +const ofUnicode::range ofUnicode::SuperAndSubScripts {0x2070, 0x209F}; +const ofUnicode::range ofUnicode::CurrencySymbols {0x20A0, 0x20CF}; +const ofUnicode::range ofUnicode::LetterLikeSymbols {0x2100, 0x214F}; +const ofUnicode::range ofUnicode::NumberForms {0x2150, 0x218F}; +const ofUnicode::range ofUnicode::Arrows {0x2190, 0x21FF}; +const ofUnicode::range ofUnicode::MathOperators {0x2200, 0x22FF}; +const ofUnicode::range ofUnicode::MiscTechnical {0x2300, 0x23FF}; +const ofUnicode::range ofUnicode::BoxDrawing {0x2500, 0x257F}; +const ofUnicode::range ofUnicode::BlockElement {0x2580, 0x259F}; +const ofUnicode::range ofUnicode::GeometricShapes {0x25A0, 0x25FF}; +const ofUnicode::range ofUnicode::MiscSymbols {0x2600, 0x26FF}; +const ofUnicode::range ofUnicode::Dingbats {0x2700, 0x27BF}; +const ofUnicode::range ofUnicode::Hiragana {0x3040, 0x309F}; +const ofUnicode::range ofUnicode::Katakana {0x30A0, 0x30FF}; +const ofUnicode::range ofUnicode::HangulCompatJamo {0x3130, 0x318F}; +const ofUnicode::range ofUnicode::KatakanaPhoneticExtensions {0x31F0, 0x31FF}; +const ofUnicode::range ofUnicode::CJKLettersAndMonths {0x3200, 0x32FF}; +const ofUnicode::range ofUnicode::CJKUnified {0x4E00, 0x9FD5}; +const ofUnicode::range ofUnicode::DevanagariExtended {0xA8E0, 0xA8FF}; +const ofUnicode::range ofUnicode::HangulExtendedA {0xA960, 0xA97F}; +const ofUnicode::range ofUnicode::HangulSyllables {0xAC00, 0xD7AF}; +const ofUnicode::range ofUnicode::HangulExtendedB {0xD7B0, 0xD7FF}; +const ofUnicode::range ofUnicode::AlphabeticPresentationForms {0xFB00, 0xFB4F}; +const ofUnicode::range ofUnicode::ArabicPresFormsA {0xFB50, 0xFDFF}; +const ofUnicode::range ofUnicode::ArabicPresFormsB {0xFE70, 0xFEFF}; +const ofUnicode::range ofUnicode::KatakanaHalfAndFullwidthForms {0xFF00, 0xFFEF}; +const ofUnicode::range ofUnicode::KanaSupplement {0x1B000, 0x1B0FF}; +const ofUnicode::range ofUnicode::RumiNumericalSymbols {0x10E60, 0x10E7F}; +const ofUnicode::range ofUnicode::ArabicMath {0x1EE00, 0x1EEFF}; +const ofUnicode::range ofUnicode::MiscSymbolsAndPictographs {0x1F300, 0x1F5FF}; +const ofUnicode::range ofUnicode::Emoticons {0x1F600, 0x1F64F}; +const ofUnicode::range ofUnicode::TransportAndMap {0x1F680, 0x1F6FF}; + +const std::initializer_list ofAlphabet::Emoji { + ofUnicode::Space, + ofUnicode::Hiragana, + ofUnicode::Katakana, + ofUnicode::KatakanaPhoneticExtensions, + ofUnicode::CJKLettersAndMonths, + ofUnicode::CJKUnified +}; + +const std::initializer_list ofAlphabet::Japanese { + ofUnicode::Space, + ofUnicode::Hiragana, + ofUnicode::Katakana, + ofUnicode::KatakanaPhoneticExtensions, + ofUnicode::CJKLettersAndMonths, + ofUnicode::CJKUnified +}; + +const std::initializer_list ofAlphabet::Chinese { + ofUnicode::Space, + ofUnicode::CJKLettersAndMonths, + ofUnicode::CJKUnified +}; + +const std::initializer_list ofAlphabet::Korean { + ofUnicode::Space, + ofUnicode::HangulJamo, + ofUnicode::HangulCompatJamo, + ofUnicode::HangulExtendedA, + ofUnicode::HangulExtendedB, + ofUnicode::HangulSyllables +}; + +const std::initializer_list ofAlphabet::Arabic { + ofUnicode::Space, + ofUnicode::Arabic, + ofUnicode::ArabicExtendedA, + ofUnicode::ArabicMath, + ofUnicode::ArabicPresFormsA, + ofUnicode::ArabicPresFormsB +}; + +const std::initializer_list ofAlphabet::Devanagari { + ofUnicode::Devanagari, + ofUnicode::DevanagariExtended, + ofUnicode::VedicExtensions +}; + +const std::initializer_list ofAlphabet::Latin { + ofUnicode::Latin1Supplement, + ofUnicode::LatinExtendedAdditional +}; + +const std::initializer_list ofAlphabet::Greek { + ofUnicode::Space, + ofUnicode::Greek, + ofUnicode::GreekExtended +}; + +const std::initializer_list ofAlphabet::Cyrillic { + ofUnicode::Space, + ofUnicode::Cyrillic +}; + +const ofTrueTypeFont::glyphProps ofTrueTypeFont::invalidProps{ + 0, + 0, + 0, + 0, + 0,0, + 0,0,0,0, + 0, + 0.0f,0.0f, + 0.0f,0.0f,0.0f,0.0f +}; static bool printVectorInfo = false; static int ttfGlobalDpi = 96; @@ -31,12 +157,7 @@ void ofTrueTypeShutdown(){ } //-------------------------------------------------------- -void ofTrueTypeFont::setGlobalDpi(int newDpi){ - ttfGlobalDpi = newDpi; -} - -//-------------------------------------------------------- -static ofTTFCharacter makeContoursForCharacter(FT_Face &face){ +static ofTTFCharacter makeContoursForCharacter(FT_Face face){ //int num = face->glyph->outline.n_points; int nContours = face->glyph->outline.n_contours; @@ -171,32 +292,21 @@ static ofTTFCharacter makeContoursForCharacter(FT_Face &face){ return charOutlines; } -#if defined(TARGET_ANDROID) -#include "ofxAndroidUtils.h" -#endif - -//------------------------------------------------------------------ -bool compare_cps(const charProps & c1, const charProps & c2){ - if(c1.tH == c2.tH) return c1.tW > c2.tW; - else return c1.tH > c2.tH; -} - - #ifdef TARGET_OSX //------------------------------------------------------------------ -static string osxFontPathByName( string fontname ){ +static std::string osxFontPathByName(const std::string& fontname){ CFStringRef targetName = CFStringCreateWithCString(nullptr, fontname.c_str(), kCFStringEncodingUTF8); CTFontDescriptorRef targetDescriptor = CTFontDescriptorCreateWithNameAndSize(targetName, 0.0); CFURLRef targetURL = (CFURLRef) CTFontDescriptorCopyAttribute(targetDescriptor, kCTFontURLAttribute); string fontPath = ""; - + if(targetURL) { UInt8 buffer[PATH_MAX]; CFURLGetFileSystemRepresentation(targetURL, true, buffer, PATH_MAX); - fontPath = string((char *)buffer); + fontPath = std::string((char *)buffer); CFRelease(targetURL); } - + CFRelease(targetName); CFRelease(targetDescriptor); @@ -207,7 +317,7 @@ static string osxFontPathByName( string fontname ){ #ifdef TARGET_WIN32 #include // font font face -> file name name mapping -static map fonts_table; +static map fonts_table; // read font linking information from registry, and store in std::map //------------------------------------------------------------------ void initWindows(){ @@ -252,7 +362,7 @@ void initWindows(){ char fontsPath[2048]; SHGetKnownFolderIDList(FOLDERID_Fonts, 0, nullptr, &ppidl); SHGetPathFromIDList(ppidl,&fontsPath);*/ - string fontsDir = getenv ("windir"); + std::string fontsDir = getenv ("windir"); fontsDir += "\\Fonts\\"; for (DWORD i = 0; i < value_count; ++i) { @@ -267,8 +377,8 @@ void initWindows(){ wcstombs(value_name_char,value_name,2048); wcstombs(value_data_char,reinterpret_cast(value_data),2048); - string curr_face = value_name_char; - string font_file = value_data_char; + std::string curr_face = value_name_char; + std::string font_file = value_data_char; curr_face = curr_face.substr(0, curr_face.find('(') - 1); fonts_table[curr_face] = fontsDir + font_file; } @@ -280,11 +390,11 @@ void initWindows(){ } -static string winFontPathByName( string fontname ){ +static std::string winFontPathByName(const std::string& fontname ){ if(fonts_table.find(fontname)!=fonts_table.end()){ return fonts_table[fontname]; } - for(map::iterator it = fonts_table.begin(); it!=fonts_table.end(); it++){ + for(map::iterator it = fonts_table.begin(); it!=fonts_table.end(); it++){ if(ofIsStringInString(ofToLower(it->first),ofToLower(fontname))) return it->second; } return ""; @@ -293,8 +403,8 @@ static string winFontPathByName( string fontname ){ #ifdef TARGET_LINUX //------------------------------------------------------------------ -static string linuxFontPathByName(string fontname){ - string filename; +static std::string linuxFontPathByName(const std::string& fontname){ + std::string filename; FcPattern * pattern = FcNameParse((const FcChar8*)fontname.c_str()); FcBool ret = FcConfigSubstitute(0,pattern,FcMatchPattern); if(!ret){ @@ -327,6 +437,63 @@ static string linuxFontPathByName(string fontname){ } #endif +//----------------------------------------------------------- +static bool loadFontFace(string fontname, int _fontSize, FT_Face & face, string & filename){ + filename = ofToDataPath(fontname,true); + ofFile fontFile(filename,ofFile::Reference); + int fontID = 0; + if(!fontFile.exists()){ +#ifdef TARGET_LINUX + filename = linuxFontPathByName(fontname); +#elif defined(TARGET_OSX) + if(fontname==OF_TTF_SANS){ + fontname = "Helvetica Neue"; + fontID = 4; + }else if(fontname==OF_TTF_SERIF){ + fontname = "Times New Roman"; + }else if(fontname==OF_TTF_MONO){ + fontname = "Menlo Regular"; + } + filename = osxFontPathByName(fontname); +#elif defined(TARGET_WIN32) + if(fontname==OF_TTF_SANS){ + fontname = "Arial"; + }else if(fontname==OF_TTF_SERIF){ + fontname = "Times New Roman"; + }else if(fontname==OF_TTF_MONO){ + fontname = "Courier New"; + } + filename = winFontPathByName(fontname); +#endif + if(filename == "" ){ + ofLogError("ofTrueTypeFont") << "loadFontFace(): couldn't find font \"" << fontname << "\""; + return false; + } + ofLogVerbose("ofTrueTypeFont") << "loadFontFace(): \"" << fontname << "\" not a file in data loading system font from \"" << filename << "\""; + } + FT_Error err; + err = FT_New_Face( library, filename.c_str(), fontID, &face ); + if (err) { + // simple error table in lieu of full table (see fterrors.h) + string errorString = "unknown freetype"; + if(err == 1) errorString = "INVALID FILENAME"; + ofLogError("ofTrueTypeFont") << "loadFontFace(): couldn't create new face for \"" << fontname << "\": FT_Error " << err << " " << errorString; + return false; + } + + return true; +} + +//-------------------------------------------------------- +void ofTrueTypeFont::setGlobalDpi(int newDpi){ + ttfGlobalDpi = newDpi; +} + + +#if defined(TARGET_ANDROID) +#include "ofxAndroidUtils.h" +#endif + //------------------------------------------------------------------ bool ofTrueTypeFont::initLibraries(){ if(!librariesInitialized){ @@ -353,303 +520,376 @@ bool ofTrueTypeFont::initLibraries(){ //------------------------------------------------------------------ -ofTrueTypeFont::ofTrueTypeFont(){ +ofTrueTypeFont::ofTrueTypeFont() +:settings("",0){ bLoadedOk = false; - bMakeContours = false; letterSpacing = 1; - spaceSize = 1; - + spaceSize = 0; + fontUnitScale = 1; stringQuads.setMode(OF_PRIMITIVE_TRIANGLES); - face = nullptr; ascenderHeight = 0; - bAntiAliased = 0; - bFullCharacterSet = 0; descenderHeight = 0; - dpi = 96; - fontSize = 0; lineHeight = 0; - nCharacters = 0; - simplifyAmt = 0; } //------------------------------------------------------------------ ofTrueTypeFont::~ofTrueTypeFont(){ - - if(face) FT_Done_Face(face); #if defined(TARGET_ANDROID) ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); #endif } +//------------------------------------------------------------------ +ofTrueTypeFont::ofTrueTypeFont(const ofTrueTypeFont& mom) +:settings(mom.settings){ +#if defined(TARGET_ANDROID) + if(mom.isLoaded()){ + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); + } +#endif + bLoadedOk = mom.bLoadedOk; + + charOutlines = mom.charOutlines; + charOutlinesNonVFlipped = mom.charOutlinesNonVFlipped; + charOutlinesContour = mom.charOutlinesContour; + charOutlinesNonVFlippedContour = mom.charOutlinesNonVFlippedContour; + + lineHeight = mom.lineHeight; + ascenderHeight = mom.ascenderHeight; + descenderHeight = mom.descenderHeight; + glyphBBox = mom.glyphBBox; + letterSpacing = mom.letterSpacing; + spaceSize = mom.spaceSize; + + cps = mom.cps; // properties for each character + texAtlas = mom.texAtlas; + face = mom.face; +} + +//------------------------------------------------------------------ +ofTrueTypeFont & ofTrueTypeFont::operator=(const ofTrueTypeFont& mom){ + if(this == &mom) return *this; +#if defined(TARGET_ANDROID) + if(mom.isLoaded()){ + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); + } +#endif + settings = mom.settings; + bLoadedOk = mom.bLoadedOk; + charOutlines = mom.charOutlines; + charOutlinesNonVFlipped = mom.charOutlinesNonVFlipped; + charOutlinesContour = mom.charOutlinesContour; + charOutlinesNonVFlippedContour = mom.charOutlinesNonVFlippedContour; + + lineHeight = mom.lineHeight; + ascenderHeight = mom.ascenderHeight; + descenderHeight = mom.descenderHeight; + glyphBBox = mom.glyphBBox; + letterSpacing = mom.letterSpacing; + spaceSize = mom.spaceSize; + + cps = mom.cps; // properties for each character + + texAtlas = mom.texAtlas; + face = mom.face; + return *this; +} + +//------------------------------------------------------------------ +ofTrueTypeFont::ofTrueTypeFont(ofTrueTypeFont&& mom) +:settings(std::move(mom.settings)){ +#if defined(TARGET_ANDROID) + if(mom.isLoaded()){ + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); + } +#endif + bLoadedOk = mom.bLoadedOk; + + charOutlines = std::move(mom.charOutlines); + charOutlinesNonVFlipped = std::move(mom.charOutlinesNonVFlipped); + charOutlinesContour = std::move(mom.charOutlinesContour); + charOutlinesNonVFlippedContour = std::move(mom.charOutlinesNonVFlippedContour); + + lineHeight = mom.lineHeight; + ascenderHeight = mom.ascenderHeight; + descenderHeight = mom.descenderHeight; + glyphBBox = mom.glyphBBox; + letterSpacing = mom.letterSpacing; + spaceSize = mom.spaceSize; + + cps = mom.cps; // properties for each character + texAtlas = mom.texAtlas; + face = mom.face; +} + +//------------------------------------------------------------------ +ofTrueTypeFont & ofTrueTypeFont::operator=(ofTrueTypeFont&& mom){ + if(this == &mom) return *this; +#if defined(TARGET_ANDROID) + if(mom.isLoaded()){ + ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); + } +#endif + settings = mom.settings; + bLoadedOk = mom.bLoadedOk; + + charOutlines = std::move(mom.charOutlines); + charOutlinesNonVFlipped = std::move(mom.charOutlinesNonVFlipped); + charOutlinesContour = std::move(mom.charOutlinesContour); + charOutlinesNonVFlippedContour = std::move(mom.charOutlinesNonVFlippedContour); + + lineHeight = mom.lineHeight; + ascenderHeight = mom.ascenderHeight; + descenderHeight = mom.descenderHeight; + glyphBBox = mom.glyphBBox; + letterSpacing = mom.letterSpacing; + spaceSize = mom.spaceSize; + + cps = mom.cps; // properties for each character + + texAtlas = mom.texAtlas; + face = mom.face; + return *this; +} + +//----------------------------------------------------------- void ofTrueTypeFont::unloadTextures(){ if(!bLoadedOk) return; texAtlas.clear(); } +//----------------------------------------------------------- void ofTrueTypeFont::reloadTextures(){ - if(bLoadedOk) load(filename, fontSize, bAntiAliased, bFullCharacterSet, bMakeContours, simplifyAmt, dpi); + if(bLoadedOk) load(settings); } -static bool loadFontFace(string fontname, int _fontSize, FT_Face & face, string & filename){ - filename = ofToDataPath(fontname,true); - ofFile fontFile(filename,ofFile::Reference); - int fontID = 0; - if(!fontFile.exists()){ -#ifdef TARGET_LINUX - filename = linuxFontPathByName(fontname); -#elif defined(TARGET_OSX) - if(fontname==OF_TTF_SANS){ - fontname = "Helvetica Neue"; - fontID = 4; - }else if(fontname==OF_TTF_SERIF){ - fontname = "Times New Roman"; - }else if(fontname==OF_TTF_MONO){ - fontname = "Menlo Regular"; - } - filename = osxFontPathByName(fontname); -#elif defined(TARGET_WIN32) - if(fontname==OF_TTF_SANS){ - fontname = "Arial"; - }else if(fontname==OF_TTF_SERIF){ - fontname = "Times New Roman"; - }else if(fontname==OF_TTF_MONO){ - fontname = "Courier New"; - } - filename = winFontPathByName(fontname); -#endif - if(filename == "" ){ - ofLogError("ofTrueTypeFont") << "loadFontFace(): couldn't find font \"" << fontname << "\""; - return false; - } - ofLogVerbose("ofTrueTypeFont") << "loadFontFace(): \"" << fontname << "\" not a file in data loading system font from \"" << filename << "\""; +//----------------------------------------------------------- +bool ofTrueTypeFont::loadFont(string filename, int fontSize, bool bAntiAliased, bool bFullCharacterSet, bool makeContours, float simplifyAmt, int dpi) { + return load(filename, fontSize, bAntiAliased, bFullCharacterSet, makeContours, simplifyAmt, dpi); +} + +//----------------------------------------------------------- +ofTrueTypeFont::glyph ofTrueTypeFont::loadGlyph(uint32_t utf8) const{ + glyph aGlyph; + auto err = FT_Load_Glyph( face.get(), FT_Get_Char_Index( face.get(), utf8 ), settings.antialiased ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT ); + if(err){ + ofLogError("ofTrueTypeFont") << "loadFont(): FT_Load_Glyph failed for utf8 code " << utf8 << ": FT_Error " << err; + return aGlyph; } - FT_Error err; - err = FT_New_Face( library, filename.c_str(), fontID, &face ); - if (err) { - // simple error table in lieu of full table (see fterrors.h) - string errorString = "unknown freetype"; - if(err == 1) errorString = "INVALID FILENAME"; - ofLogError("ofTrueTypeFont") << "loadFontFace(): couldn't create new face for \"" << fontname << "\": FT_Error " << err << " " << errorString; - return false; + + if (settings.antialiased) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); + + + // ------------------------- + // info about the character: + aGlyph.props.glyph = utf8; + aGlyph.props.height = face->glyph->metrics.height>>6; + aGlyph.props.width = face->glyph->metrics.width>>6; + aGlyph.props.bearingX = face->glyph->metrics.horiBearingX>>6; + aGlyph.props.bearingY = face->glyph->metrics.horiBearingY>>6; + aGlyph.props.xmin = face->glyph->bitmap_left; + aGlyph.props.xmax = aGlyph.props.xmin + aGlyph.props.width; + aGlyph.props.ymin = -face->glyph->bitmap_top; + aGlyph.props.ymax = aGlyph.props.ymin + aGlyph.props.height; + aGlyph.props.advance = face->glyph->metrics.horiAdvance>>6; + aGlyph.props.tW = aGlyph.props.width; + aGlyph.props.tH = aGlyph.props.height; + + FT_Bitmap& bitmap= face->glyph->bitmap; + int width = bitmap.width; + int height = bitmap.rows; + if(width==0 || height==0) return aGlyph; + + // Allocate Memory For The Texture Data. + aGlyph.pixels.allocate(width, height, OF_PIXELS_GRAY_ALPHA); + //-------------------------------- clear data: + aGlyph.pixels.set(0,255); // every luminance pixel = 255 + aGlyph.pixels.set(1,0); + + + if (settings.antialiased == true){ + ofPixels bitmapPixels; + bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,OF_PIXELS_GRAY); + aGlyph.pixels.setChannel(1,bitmapPixels); + } else { + //----------------------------------- + // true type packs monochrome info in a + // 1-bit format, hella funky + // here we unpack it: + unsigned char *src = bitmap.buffer; + for(unsigned int j=0; j (loadFace,FT_Done_Face); - - if(!loadFontFace(_filename,_fontSize,face,filename)){ - return false; + if(settings.ranges.empty()){ + settings.ranges.push_back(ofUnicode::Latin1Supplement); } + int border = 1; - FT_Set_Char_Size( face, fontSize << 6, fontSize << 6, dpi, dpi); - float fontUnitScale = ((float)fontSize * dpi) / (72 * face->units_per_EM); + FT_Set_Char_Size( face.get(), settings.fontSize << 6, settings.fontSize << 6, settings.dpi, settings.dpi); + fontUnitScale = (float(settings.fontSize * settings.dpi)) / (72 * face->units_per_EM); lineHeight = face->height * fontUnitScale; ascenderHeight = face->ascender * fontUnitScale; descenderHeight = face->descender * fontUnitScale; glyphBBox.set(face->bbox.xMin * fontUnitScale, - face->bbox.yMin * fontUnitScale, + face->bbox.yMin * fontUnitScale, (face->bbox.xMax - face->bbox.xMin) * fontUnitScale, (face->bbox.yMax - face->bbox.yMin) * fontUnitScale); - //------------------------------------------------------ - //kerning would be great to support: - //ofLogNotice("ofTrueTypeFont") << "FT_HAS_KERNING ? " << FT_HAS_KERNING(face); - //------------------------------------------------------ - - nCharacters = (bFullCharacterSet ? 256 : 128) - NUM_CHARACTER_TO_START; - //--------------- initialize character info and textures - cps.resize(nCharacters); - - if(bMakeContours){ - charOutlines.assign(nCharacters, ofTTFCharacter()); - charOutlinesNonVFlipped.assign(nCharacters, ofTTFCharacter()); - charOutlinesContour.assign(nCharacters, ofTTFCharacter()); - charOutlinesNonVFlippedContour.assign(nCharacters, ofTTFCharacter()); + auto nGlyphs = std::accumulate(settings.ranges.begin(), settings.ranges.end(), 0u, + [](uint32_t acc, ofUnicode::range range){ + return acc + range.getNumGlyphs(); + }); + cps.resize(nGlyphs); + if(settings.contours){ + charOutlines.resize(nGlyphs); + charOutlinesNonVFlipped.resize(nGlyphs); + charOutlinesContour.resize(nGlyphs); + charOutlinesNonVFlippedContour.resize(nGlyphs); }else{ charOutlines.resize(1); } - vector expanded_data(nCharacters); - - long areaSum=0; - FT_Error err; + vector all_glyphs; + uint32_t areaSum=0; //--------------------- load each char ----------------------- - for (int i = 0 ; i < nCharacters; i++){ - - //------------------------------------------ anti aliased or not: - int glyph = (unsigned char)(i+NUM_CHARACTER_TO_START); - if (glyph == 0xA4) glyph = 0x20AC; // hack to load the euro sign, all codes in 8859-15 match with utf-32 except for this one - err = FT_Load_Glyph( face, FT_Get_Char_Index( face, glyph ), bAntiAliased ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT ); - if(err){ - ofLogError("ofTrueTypeFont") << "loadFont(): FT_Load_Glyph failed for char " << i << ": FT_Error " << err; - - } - - if (bAntiAliased == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); - else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); - - //------------------------------------------ - - - if(bMakeContours){ - if(printVectorInfo){ - ofLogNotice("ofTrueTypeFont") << "character " << char(i+NUM_CHARACTER_TO_START); - } - - //int character = i + NUM_CHARACTER_TO_START; - charOutlines[i] = makeContoursForCharacter( face ); - charOutlinesContour[i] = charOutlines[i]; - charOutlinesContour[i].setFilled(false); - charOutlinesContour[i].setStrokeWidth(1); - - charOutlinesNonVFlipped[i] = charOutlines[i]; - charOutlinesNonVFlipped[i].translate(ofVec3f(0,cps[i].height)); - charOutlinesNonVFlipped[i].scale(1,-1); - charOutlinesNonVFlippedContour[i] = charOutlines[i]; - charOutlinesNonVFlippedContour[i].setFilled(false); - charOutlinesNonVFlippedContour[i].setStrokeWidth(1); - - - if(simplifyAmt>0){ - charOutlines[i].simplify(simplifyAmt); - charOutlinesNonVFlipped[i].simplify(simplifyAmt); - charOutlinesContour[i].simplify(simplifyAmt); - charOutlinesNonVFlippedContour[i].simplify(simplifyAmt); - } - } - - - // ------------------------- - // info about the character: - FT_Bitmap& bitmap= face->glyph->bitmap; - int width = bitmap.width; - int height = bitmap.rows; - - cps[i].characterIndex = i; - cps[i].glyph = glyph; - cps[i].height = face->glyph->metrics.height>>6; - cps[i].width = face->glyph->metrics.width>>6; - cps[i].bearingX = face->glyph->metrics.horiBearingX>>6; - cps[i].bearingY = face->glyph->metrics.horiBearingY>>6; - cps[i].xmin = face->glyph->bitmap_left; - cps[i].xmax = cps[i].xmin + cps[i].width; - cps[i].ymin = -face->glyph->bitmap_top; - cps[i].ymax = cps[i].ymin + cps[i].height; - cps[i].advance = face->glyph->metrics.horiAdvance>>6; - - - cps[i].tW = cps[i].width; - cps[i].tH = cps[i].height; - - - areaSum += (cps[i].tW+border*2)*(cps[i].tH+border*2); - - if(width==0 || height==0) continue; - - // Allocate Memory For The Texture Data. - expanded_data[i].allocate(width, height, OF_PIXELS_GRAY_ALPHA); - //-------------------------------- clear data: - expanded_data[i].set(0,255); // every luminance pixel = 255 - expanded_data[i].set(1,0); - - - if (bAntiAliased == true){ - ofPixels bitmapPixels; - bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,OF_PIXELS_GRAY); - expanded_data[i].setChannel(1,bitmapPixels); - } else { - //----------------------------------- - // true type packs monochrome info in a - // 1-bit format, hella funky - // here we unpack it: - unsigned char *src = bitmap.buffer; - for(unsigned int j=0; j 0){ + charOutlines[i].simplify(settings.simplifyAmt); + charOutlinesNonVFlipped[i].simplify(settings.simplifyAmt); + charOutlinesContour[i].simplify(settings.simplifyAmt); + charOutlinesNonVFlippedContour[i].simplify(settings.simplifyAmt); } - src += bitmap.pitch; } - //----------------------------------- } } - vector sortedCopy = cps; - sort(sortedCopy.begin(),sortedCopy.end(),&compare_cps); + vector sortedCopy = cps; + sort(sortedCopy.begin(),sortedCopy.end(),[](const ofTrueTypeFont::glyphProps & c1, const ofTrueTypeFont::glyphProps & c2){ + if(c1.tH == c2.tH) return c1.tW > c2.tW; + else return c1.tH > c2.tH; + }); // pack in a texture, algorithm to calculate min w/h from // http://upcommons.upc.edu/pfc/bitstream/2099.1/7720/1/TesiMasterJonas.pdf //ofLogNotice("ofTrueTypeFont") << "loadFont(): areaSum: " << areaSum bool packed = false; - float alpha = logf(areaSum)*1.44269; - + float alpha = logf(areaSum)*1.44269f; int w; int h; while(!packed){ - w = pow(2,floor((alpha/2.f) + 0.5)); // there doesn't seem to be a round in cmath for windows. + w = pow(2,floor((alpha/2.f) + 0.5f)); // there doesn't seem to be a round in cmath for windows. //w = pow(2,round(alpha/2.f)); h = w;//pow(2,round(alpha - round(alpha/2.f))); int x=0; int y=0; - int maxRowHeight = sortedCopy[0].tH + border*2; - for(int i=0;i<(int)cps.size();i++){ - if(x+sortedCopy[i].tW + border*2>w){ + auto maxRowHeight = sortedCopy[0].tH + border*2; + packed = true; + for(auto & glyph: sortedCopy){ + if(x+glyph.tW + border*2>w){ x = 0; y += maxRowHeight; - maxRowHeight = sortedCopy[i].tH + border*2; + maxRowHeight = glyph.tH + border*2; if(y + maxRowHeight > h){ alpha++; + packed = false; break; } } - x+= sortedCopy[i].tW + border*2; - if(i==(int)cps.size()-1) packed = true; + x+= glyph.tW + border*2; } } @@ -664,35 +904,33 @@ bool ofTrueTypeFont::load(string _filename, int _fontSize, bool _bAntiAliased, b int x=0; int y=0; - int maxRowHeight = sortedCopy[0].tH + border*2; - for(int i=0;i<(int)cps.size();i++){ - ofPixels & charPixels = expanded_data[sortedCopy[i].characterIndex]; + auto maxRowHeight = sortedCopy[0].tH + border*2; + for(auto & glyph: sortedCopy){ + ofPixels & charPixels = all_glyphs[glyph.characterIndex].pixels; - if(x+sortedCopy[i].tW + border*2>w){ + if(x+glyph.tW + border*2>w){ x = 0; y += maxRowHeight; - maxRowHeight = sortedCopy[i].tH + border*2; + maxRowHeight = glyph.tH + border*2; } - cps[sortedCopy[i].characterIndex].t1 = float(x + border)/float(w); - cps[sortedCopy[i].characterIndex].v1 = float(y + border)/float(h); - cps[sortedCopy[i].characterIndex].t2 = float(cps[sortedCopy[i].characterIndex].tW + x + border)/float(w); - cps[sortedCopy[i].characterIndex].v2 = float(cps[sortedCopy[i].characterIndex].tH + y + border)/float(h); + cps[glyph.characterIndex].t1 = float(x + border)/float(w); + cps[glyph.characterIndex].v1 = float(y + border)/float(h); + cps[glyph.characterIndex].t2 = float(cps[glyph.characterIndex].tW + x + border)/float(w); + cps[glyph.characterIndex].v2 = float(cps[glyph.characterIndex].tH + y + border)/float(h); charPixels.pasteInto(atlasPixelsLuminanceAlpha,x+border,y+border); - x+= sortedCopy[i].tW + border*2; + x+= glyph.tW + border*2; } texAtlas.allocate(atlasPixelsLuminanceAlpha,false); texAtlas.setRGToRGBASwizzles(true); - if(bAntiAliased && fontSize>20){ + if(settings.antialiased && settings.fontSize>20){ texAtlas.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR); }else{ texAtlas.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST); } texAtlas.loadData(atlasPixelsLuminanceAlpha); - - // ------------- close the library and typeface - bLoadedOk = true; + bLoadedOk = true; return true; } @@ -703,17 +941,17 @@ bool ofTrueTypeFont::isLoaded() const{ //----------------------------------------------------------- bool ofTrueTypeFont::isAntiAliased() const{ - return bAntiAliased; + return settings.antialiased; } //----------------------------------------------------------- bool ofTrueTypeFont::hasFullCharacterSet() const{ - return bFullCharacterSet; + return true; } //----------------------------------------------------------- int ofTrueTypeFont::getSize() const{ - return fontSize; + return settings.fontSize; } //----------------------------------------------------------- @@ -762,52 +1000,51 @@ float ofTrueTypeFont::getSpaceSize() const{ } //------------------------------------------------------------------ -ofTTFCharacter ofTrueTypeFont::getCharacterAsPoints(int character, bool vflip, bool filled) const{ - if( bMakeContours == false ){ +ofTTFCharacter ofTrueTypeFont::getCharacterAsPoints(uint32_t character, bool vflip, bool filled) const{ + if( settings.contours == false ){ ofLogError("ofxTrueTypeFont") << "getCharacterAsPoints(): contours not created, call loadFont() with makeContours set to true"; return ofTTFCharacter(); } - if (character - NUM_CHARACTER_TO_START >= nCharacters || character < NUM_CHARACTER_TO_START){ - //ofLogError("ofxTrueTypeFont") << "getCharacterAsPoint(): char " << character + NUM_CHARACTER_TO_START << " not allocated: line " << __LINE__ << " in " << __FILE__; - + if (!isValidGlyph(character)){ return ofTTFCharacter(); } if(vflip){ if(filled){ - return charOutlines[character - NUM_CHARACTER_TO_START]; + return charOutlines[indexForGlyph(character)]; }else{ - return charOutlinesContour[character - NUM_CHARACTER_TO_START]; + return charOutlinesContour[indexForGlyph(character)]; } }else{ if(filled){ - return charOutlinesNonVFlipped[character - NUM_CHARACTER_TO_START]; + return charOutlinesNonVFlipped[indexForGlyph(character)]; }else{ - return charOutlinesNonVFlippedContour[character - NUM_CHARACTER_TO_START]; + return charOutlinesNonVFlippedContour[indexForGlyph(character)]; } } } //----------------------------------------------------------- -void ofTrueTypeFont::drawChar(int c, float x, float y, bool vFlipped) const{ +void ofTrueTypeFont::drawChar(uint32_t c, float x, float y, bool vFlipped) const{ - if (c >= nCharacters){ + if (!isValidGlyph(c)){ //ofLogError("ofTrueTypeFont") << "drawChar(): char " << c + NUM_CHARACTER_TO_START << " not allocated: line " << __LINE__ << " in " << __FILE__; return; } - int xmin, ymin, xmax, ymax; + long xmin, ymin, xmax, ymax; float t1, v1, t2, v2; - t2 = cps[c].t2; - v2 = cps[c].v2; - t1 = cps[c].t1; - v1 = cps[c].v1; + auto props = getGlyphProperties(c); + t1 = props.t1; + t2 = props.t2; + v2 = props.v2; + v1 = props.v1; - xmin = cps[c].xmin+x; - ymin = cps[c].ymin; - xmax = cps[c].xmax+x; - ymax = cps[c].ymax; + xmin = long(props.xmin+x); + ymin = props.ymin; + xmax = long(props.xmax+x); + ymax = props.ymax; if(!vFlipped){ ymin *= -1; @@ -817,7 +1054,7 @@ void ofTrueTypeFont::drawChar(int c, float x, float y, bool vFlipped) const{ ymin += y; ymax += y; - int firstIndex = stringQuads.getVertices().size(); + ofIndexType firstIndex = stringQuads.getVertices().size(); stringQuads.addVertex(ofVec3f(xmin,ymin)); stringQuads.addVertex(ofVec3f(xmax,ymin)); @@ -838,93 +1075,126 @@ void ofTrueTypeFont::drawChar(int c, float x, float y, bool vFlipped) const{ } //----------------------------------------------------------- -int ofTrueTypeFont::getKerning(int c, int prevC) const{ - if(FT_HAS_KERNING( face ) && prevC>0 && prevC0 && c>6; + FT_Get_Kerning(face.get(), FT_Get_Char_Index(face.get(), c), FT_Get_Char_Index(face.get(), prevC), FT_KERNING_UNFITTED, &kerning); + return kerning.x * fontUnitScale; }else{ return 0; } } -//----------------------------------------------------------- -vector ofTrueTypeFont::getStringAsPoints(string str, bool vflip, bool filled) const{ - vector shapes; - - if (!bLoadedOk){ - ofLogError("ofxTrueTypeFont") << "getStringAsPoints(): font not allocated: line " << __LINE__ << " in " << __FILE__; - return shapes; - }; +void ofTrueTypeFont::iterateString(const string & str, float x, float y, bool vFlipped, std::function f) const{ + ofVec2f pos(x,y); - GLfloat X = 0; - GLfloat Y = 0; int newLineDirection = 1; - - if(vflip){ + if(!vFlipped){ // this would align multiline texts to the last line when vflip is disabled //int lines = ofStringTimesInString(c,"\n"); //Y = lines*lineHeight; newLineDirection = -1; } - try{ - int prevCy = -1; - for(auto c: ofUTF8Iterator(str)){ - int cy = c - NUM_CHARACTER_TO_START; - if (cy < nCharacters){ // full char set or not? - if (c == '\n') { - Y += lineHeight*newLineDirection; - X = 0 ; //reset X Pos back to zero - } else if(cy > -1){ - shapes.push_back(getCharacterAsPoints(c,vflip,filled)); - - X += getKerning(cy,prevCy); - - shapes.back().translate(ofPoint(X,Y)); - - X += cps[cy].advance * letterSpacing; + int directionX = settings.direction == ofTtfSettings::LeftToRight?1:-1; + + string str_valid; + utf8::replace_invalid(str.begin(),str.end(),back_inserter(str_valid)); + utf8::iterator it(&str_valid.front(), &str_valid.front(), (&str_valid.back())+1); + utf8::iterator end((&str_valid.back())+1, &str_valid.front(), (&str_valid.back())+1); + uint32_t prevC = 0; + while(it != end){ + try{ + auto c = *it; + if (c == '\n') { + pos.y += lineHeight*newLineDirection; + pos.x = x ; //reset X Pos back to zero + prevC = 0; + }if (c == '\t') { + pos.x += getGlyphProperties(' ').advance * letterSpacing * 4 * directionX; + prevC = c; + } else if(isValidGlyph(c)) { + const auto & props = getGlyphProperties(c); + if(prevC>0){ + pos.x += getKerning(c,prevC);// * directionX; } + f(c,pos); + pos.x += props.advance * letterSpacing * directionX; + prevC = c; } - prevCy = cy; + ++it; + }catch(...){ + break; } - }catch(...){ - } - return shapes; +} +//----------------------------------------------------------- +void ofTrueTypeFont::setDirection(ofTtfSettings::Direction direction){ + settings.direction = direction; } //----------------------------------------------------------- -void ofTrueTypeFont::drawCharAsShape(int c, float x, float y, bool vFlipped, bool filled) const{ - if (c - NUM_CHARACTER_TO_START >= nCharacters || c < NUM_CHARACTER_TO_START){ - //ofLogError("ofTrueTypeFont") << "drawCharAsShape(): char " << << c + NUM_CHARACTER_TO_START << " not allocated: line " << __LINE__ << " in " << __FILE__; - return; +vector ofTrueTypeFont::getStringAsPoints(const string & str, bool vflip, bool filled) const{ + vector shapes; + + if (!bLoadedOk){ + ofLogError("ofxTrueTypeFont") << "getStringAsPoints(): font not allocated: line " << __LINE__ << " in " << __FILE__; + return shapes; + }; + iterateString(str,0,0,vflip,[&](uint32_t c, ofVec2f pos){ + shapes.push_back(getCharacterAsPoints(c,vflip,filled)); + shapes.back().translate(pos); + }); + return shapes; + +} + +bool ofTrueTypeFont::isValidGlyph(uint32_t glyph) const{ + //return glyphIndexMap.find(glyph) != glyphIndexMap.end(); + return std::any_of(settings.ranges.begin(), settings.ranges.end(), + [&](ofUnicode::range range){ + return glyph >= range.begin && glyph <= range.end; + }); +} + +size_t ofTrueTypeFont::indexForGlyph(uint32_t glyph) const{ + return glyphIndexMap.find(glyph)->second; +} + +const ofTrueTypeFont::glyphProps & ofTrueTypeFont::getGlyphProperties(uint32_t glyph) const{ + if(isValidGlyph(glyph)){ + return cps[indexForGlyph(glyph)]; + }else{ + return invalidProps; } - //----------------------- +} + +//----------------------------------------------------------- +void ofTrueTypeFont::drawCharAsShape(uint32_t c, float x, float y, bool vFlipped, bool filled) const{ if(vFlipped){ if(filled){ - charOutlines[c - NUM_CHARACTER_TO_START].draw(x,y); + charOutlines[indexForGlyph(c)].draw(x,y); }else{ - charOutlinesContour[c - NUM_CHARACTER_TO_START].draw(x,y); + charOutlinesContour[indexForGlyph(c)].draw(x,y); } }else{ if(filled){ - charOutlinesNonVFlipped[c - NUM_CHARACTER_TO_START].draw(x,y); + charOutlinesNonVFlipped[indexForGlyph(c)].draw(x,y); }else{ - charOutlinesNonVFlippedContour[c - NUM_CHARACTER_TO_START].draw(x,y); + charOutlinesNonVFlippedContour[indexForGlyph(c)].draw(x,y); } } } //----------------------------------------------------------- -float ofTrueTypeFont::stringWidth(string c) const{ +float ofTrueTypeFont::stringWidth(const std::string& c) const{ ofRectangle rect = getStringBoundingBox(c, 0,0); return rect.width; } //----------------------------------------------------------- -ofRectangle ofTrueTypeFont::getStringBoundingBox(string c, float x, float y, bool vflip) const{ +ofRectangle ofTrueTypeFont::getStringBoundingBox(const std::string& c, float x, float y, bool vflip) const{ ofMesh mesh = getStringMesh(c,x,y,vflip); ofRectangle bb(std::numeric_limits::max(),std::numeric_limits::max(),0,0); float maxX = std::numeric_limits::min(); @@ -941,49 +1211,21 @@ ofRectangle ofTrueTypeFont::getStringBoundingBox(string c, float x, float y, boo } //----------------------------------------------------------- -float ofTrueTypeFont::stringHeight(string c) const{ +float ofTrueTypeFont::stringHeight(const std::string& c) const{ ofRectangle rect = getStringBoundingBox(c, 0,0); return rect.height; } //----------------------------------------------------------- -void ofTrueTypeFont::createStringMesh(string str, float x, float y, bool vFlipped) const{ - stringQuads.clear(); - GLfloat X = x; - GLfloat Y = y; - int newLineDirection = 1; - - if(!vFlipped){ - // this would align multiline texts to the last line when vflip is disabled - //int lines = ofStringTimesInString(c,"\n"); - //Y = lines*lineHeight; - newLineDirection = -1; - } - - int prevCy = -1; - try{ - for(auto c: ofUTF8Iterator(str)){ - int cy = c - NUM_CHARACTER_TO_START; - if (cy < nCharacters){ // full char set or not? - if (c == '\n') { - Y += lineHeight*newLineDirection; - X = x ; //reset X Pos back to zero - prevCy = -1; - } else if(cy > -1){ - X += getKerning(cy,prevCy); - drawChar(cy, X, Y, vFlipped); - X += cps[cy].advance * letterSpacing; - } - } - prevCy = cy; - } - }catch(...){ - - } +void ofTrueTypeFont::createStringMesh(const std::string& str, float x, float y, bool vflip) const{ + iterateString(str,x,y,vflip,[&](uint32_t c, ofVec2f pos){ + drawChar(c, pos.x, pos.y, vflip); + }); } //----------------------------------------------------------- -const ofMesh & ofTrueTypeFont::getStringMesh(string c, float x, float y, bool vFlipped) const{ +const ofMesh & ofTrueTypeFont::getStringMesh(const std::string& c, float x, float y, bool vFlipped) const{ + stringQuads.clear(); createStringMesh(c,x,y,vFlipped); return stringQuads; } @@ -994,7 +1236,65 @@ const ofTexture & ofTrueTypeFont::getFontTexture() const{ } //----------------------------------------------------------- -void ofTrueTypeFont::drawString(string c, float x, float y) const{ +ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) const{ + string str_valid; + utf8::replace_invalid(str.begin(),str.end(),back_inserter(str_valid)); + vector glyphs; + vector glyphPositions; + utf8::iterator it(&str_valid.front(), &str_valid.front(), (&str_valid.back())+1); + utf8::iterator end((&str_valid.back())+1, &str_valid.front(), (&str_valid.back())+1); + int x = 0; + int y = 0; + long height = 0; + uint32_t prevC = 0; + while(it != end){ + try{ + auto c = *it; + if (c == '\n') { + y += lineHeight; + x = 0 ; //reset X Pos back to zero + prevC = 0; + } else { + glyphs.push_back(loadGlyph(c)); + if(prevC>0){ + x += getKerning(c,prevC); + }else if(settings.direction == ofTtfSettings::RightToLeft){ + x += glyphs.back().props.width; + } + glyphPositions.emplace_back(static_cast(x), static_cast(y)); + x += glyphs.back().props.advance * letterSpacing; + height = max(height, glyphs.back().props.ymax + y + long(getLineHeight())); + } + ++it; + prevC = c; + }catch(...){ + break; + } + } + ofTexture tex; + ofPixels totalPixels; + totalPixels.allocate(x, height, OF_PIXELS_GRAY_ALPHA); + //-------------------------------- clear data: + totalPixels.set(0,255); // every luminance pixel = 255 + totalPixels.set(1,0); + size_t i = 0; + for(auto & g: glyphs){ + if(settings.direction == ofTtfSettings::LeftToRight){ + g.pixels.blendInto(totalPixels, glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); + }else{ + g.pixels.blendInto(totalPixels, x-glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() ); + } + i++; + if(i==glyphPositions.size()){ + break; + } + } + tex.allocate(totalPixels); + return tex; +} + +//----------------------------------------------------------- +void ofTrueTypeFont::drawString(const std::string & c, float x, float y) const{ if (!bLoadedOk){ ofLogError("ofTrueTypeFont") << "drawString(): font not allocated"; return; @@ -1005,52 +1305,24 @@ void ofTrueTypeFont::drawString(string c, float x, float y) const{ } //----------------------------------------------------------- -void ofTrueTypeFont::drawStringAsShapes(string str, float x, float y) const{ +void ofTrueTypeFont::drawStringAsShapes(const std::string& str, float x, float y) const{ if (!bLoadedOk){ ofLogError("ofTrueTypeFont") << "drawStringAsShapes(): font not allocated: line " << __LINE__ << " in " << __FILE__; return; }; //----------------------- error checking - if (!bMakeContours){ + if (!settings.contours){ ofLogError("ofTrueTypeFont") << "drawStringAsShapes(): contours not created for this font, call loadFont() with makeContours set to true"; return; } - GLfloat X = x; - GLfloat Y = y; - int newLineDirection = 1; - - if(!ofIsVFlipped()){ - // this would align multiline texts to the last line when vflip is disabled - //int lines = ofStringTimesInString(c,"\n"); - //Y = lines*lineHeight; - newLineDirection = -1; - } - - int prevCy = -1; - try{ - for(auto c: ofUTF8Iterator(str)){ - int cy = c - NUM_CHARACTER_TO_START; - if (cy < nCharacters){ // full char set or not? - if (c == '\n') { - Y += lineHeight*newLineDirection; - X = x ; //reset X Pos back to zero - prevCy = -1; - } else if(cy > -1){ - X += getKerning(cy,prevCy); - drawCharAsShape(c, X, Y, ofIsVFlipped(), ofGetStyle().bFill); - X += cps[cy].advance * letterSpacing; - } - } - prevCy = cy; - } - }catch(...){ - } - + iterateString(str,x,y,true,[&](uint32_t c, ofVec2f pos){ + drawCharAsShape(c, pos.x, pos.y, ofIsVFlipped(), ofGetStyle().bFill); + }); } //----------------------------------------------------------- -int ofTrueTypeFont::getNumCharacters() const{ - return nCharacters; +std::size_t ofTrueTypeFont::getNumCharacters() const{ + return cps.size(); } diff --git a/libs/openFrameworks/graphics/ofTrueTypeFont.h b/libs/openFrameworks/graphics/ofTrueTypeFont.h index 147c6a6bbb0..d976fbd838b 100644 --- a/libs/openFrameworks/graphics/ofTrueTypeFont.h +++ b/libs/openFrameworks/graphics/ofTrueTypeFont.h @@ -24,40 +24,128 @@ /// \cond INTERNAL -//-------------------------------------------------- -typedef struct { - int characterIndex; - int glyph; - int height; - int width; - int bearingX, bearingY; - int xmin, xmax, ymin, ymax; - int advance; - float tW,tH; - float t1,t2,v1,v2; -} charProps; - typedef ofPath ofTTFCharacter; - -//-------------------------------------------------- -#define NUM_CHARACTER_TO_START 32 // 0 - 32 are control characters, no graphics needed. - - typedef struct FT_FaceRec_* FT_Face; /// \endcond /// \name Fonts /// \{ -static const string OF_TTF_SANS = "sans-serif"; -static const string OF_TTF_SERIF = "serif"; -static const string OF_TTF_MONO = "monospace"; +static const std::string OF_TTF_SANS = "sans-serif"; +static const std::string OF_TTF_SERIF = "serif"; +static const std::string OF_TTF_MONO = "monospace"; /// \} void ofTrueTypeShutdown(); +class ofUnicode{ +public: + struct range{ + std::uint32_t begin; + std::uint32_t end; + + std::uint32_t getNumGlyphs() const{ + return end - begin + 1; + } + }; + + static const range Space; + static const range Latin; + static const range Latin1Supplement; + static const range Greek; + static const range Cyrillic; + static const range Arabic; + static const range ArabicSupplement; + static const range ArabicExtendedA; + static const range Devanagari; + static const range HangulJamo; + static const range VedicExtensions; + static const range LatinExtendedAdditional; + static const range GreekExtended; + static const range GeneralPunctuation; + static const range SuperAndSubScripts; + static const range CurrencySymbols; + static const range LetterLikeSymbols; + static const range NumberForms; + static const range Arrows; + static const range MathOperators; + static const range MiscTechnical; + static const range BoxDrawing; + static const range BlockElement; + static const range GeometricShapes; + static const range MiscSymbols; + static const range Dingbats; + static const range Hiragana; + static const range Katakana; + static const range HangulCompatJamo; + static const range KatakanaPhoneticExtensions; + static const range CJKLettersAndMonths; + static const range CJKUnified; + static const range DevanagariExtended; + static const range HangulExtendedA; + static const range HangulSyllables; + static const range HangulExtendedB; + static const range AlphabeticPresentationForms; + static const range ArabicPresFormsA; + static const range ArabicPresFormsB; + static const range KatakanaHalfAndFullwidthForms; + static const range KanaSupplement; + static const range RumiNumericalSymbols; + static const range ArabicMath; + static const range MiscSymbolsAndPictographs; + static const range Emoticons; + static const range TransportAndMap; + +}; + +class ofAlphabet{ +public: + static const std::initializer_list Emoji; + static const std::initializer_list Japanese; + static const std::initializer_list Chinese; + static const std::initializer_list Korean; + static const std::initializer_list Arabic; + static const std::initializer_list Devanagari; + static const std::initializer_list Latin; + static const std::initializer_list Greek; + static const std::initializer_list Cyrillic; +}; + + + + +class ofTtfSettings{ + friend class ofTrueTypeFont; + vector ranges; + +public: + ofTtfSettings(const string & name, int size) + :fontName(name) + ,fontSize(size){} + + string fontName; + int fontSize; + bool antialiased = true; + bool contours = false; + float simplifyAmt = 0.3f; + int dpi = 0; + + enum Direction{ + LeftToRight, + RightToLeft + }; + Direction direction = LeftToRight; + + void addRanges(std::initializer_list alphabet){ + ranges.insert(ranges.end(), alphabet); + } + + void addRange(const ofUnicode::range & range){ + ranges.push_back(range); + } +}; class ofTrueTypeFont{ @@ -65,12 +153,18 @@ class ofTrueTypeFont{ public: - /// \todo + /// \brief Construct a default ofTrueTypeFont. ofTrueTypeFont(); - /// \todo + /// \brief Destroy the ofTrueTypeFont. virtual ~ofTrueTypeFont(); + ofTrueTypeFont(const ofTrueTypeFont& mom); + ofTrueTypeFont & operator=(const ofTrueTypeFont& mom); + + ofTrueTypeFont(ofTrueTypeFont&& mom); + ofTrueTypeFont & operator=(ofTrueTypeFont&& mom); + /// \name Load Font /// \{ @@ -95,16 +189,19 @@ class ofTrueTypeFont{ bool _bAntiAliased=true, bool _bFullCharacterSet=true, bool makeContours=false, - float simplifyAmt=0.3, - int dpi=0); + float simplifyAmt=0.3f, + int dpi=0); + OF_DEPRECATED_MSG("Use load instead",bool loadFont(string filename, int fontsize, bool _bAntiAliased=true, bool _bFullCharacterSet=false, bool makeContours=false, - float simplifyAmt=0.3, - int dpi=0)); + float simplifyAmt=0.3f, + int dpi=0)); + bool load(const ofTtfSettings & settings); + /// \brief Has the font been loaded successfully? /// \returns true if the font was loaded. bool isLoaded() const; @@ -113,8 +210,7 @@ class ofTrueTypeFont{ /// \name Font Settings /// \{ - // set the default dpi for all typefaces. - /// \todo + /// \brief Set the default dpi for all typefaces. static void setGlobalDpi(int newDpi); /// \brief Is the font anti-aliased? @@ -125,24 +221,24 @@ class ofTrueTypeFont{ /// \returns true if the font was allocated with a full character set. bool hasFullCharacterSet() const; - /// \brief Get the number characters in the loaded character set. + /// \brief Get the number of characters in the loaded character set. /// /// If you allocate the font using different parameters, you can load in partial /// and full character sets, this helps you know how many characters it can represent. /// /// \returns Number of characters in loaded character set. - int getNumCharacters(); + std::size_t getNumCharacters() const; /// \} /// \name Font Size - /// \{ + /// \{ /// \brief Returns the size of the font. /// \returns Size of font, set when font was loaded. int getSize() const; /// \brief Computes line height based on font size. - /// \returns Returns current line height. + /// \returns the current line height. float getLineHeight() const; /// \brief Sets line height for text drawn on screen. @@ -158,7 +254,7 @@ class ofTrueTypeFont{ /// The meaning of "character" coordinate depends on the font. Some fonts take accents into account, /// others do not, and still others define it simply to be the highest coordinate over all glyphs. /// - /// \returns Returns font ascender height in pixels. + /// \returns the font ascender height in pixels. float getAscenderHeight() const; /// \brief Get the descender distance for this font. @@ -168,7 +264,7 @@ class ofTrueTypeFont{ /// others do not, and still others define it simply to be the lowest coordinate over all glyphs. /// This value will be negative for descenders below the baseline (which is typical). /// - /// \returns Returns font descender height in pixels. + /// \returns the font descender height in pixels. float getDescenderHeight() const; /// \brief Get the global bounding box for this font. @@ -177,7 +273,7 @@ class ofTrueTypeFont{ /// Glyphs are drawn starting from (0,0) in the returned box (though note that the box can /// extend in any direction out from the origin). /// - /// \returns Returns font descender height in pixels. + /// \returns the font descender height in pixels. const ofRectangle & getGlyphBBox() const; /// \brief Returns letter spacing of font object. @@ -185,7 +281,7 @@ class ofTrueTypeFont{ /// You can control this by the ofTrueTypeFont::setLetterSpacing() function. 1.0 = default spacing, /// less then 1.0 would be tighter spacing, greater then 1.0 would be wider spacing. /// - /// \returns Returns letter spacing of font object. + /// \returns the letter spacing of font object. float getLetterSpacing() const; /// \brief Sets the letter spacing of the font object. @@ -199,7 +295,7 @@ class ofTrueTypeFont{ /// It's a scalar for the width of the letter 'p', so 1.0 means that a space will be the size of the lower /// case 'p' of that font. 2.0 means that it's 2 times the size of the lower case 'p', etc. /// - /// \returns Returns a variable that represents how wide spaces are. + /// \returns the width of the space. float getSpaceSize() const; /// \brief Sets the size of the space ' ' character. @@ -214,23 +310,23 @@ class ofTrueTypeFont{ /// This is essentially the width component of the ofTrueTypeFont::getStringBoundingBox() rectangle. /// /// \param s The string to get the width of. - /// \returns Returns the string width. - float stringWidth(string s) const; + /// \returns the string width. + float stringWidth(const std::string& s) const; /// \brief Returns the string height. /// /// This is essentially the height component of the ofTrueTypeFont::getStringBoundingBox() rectangle. /// /// \param s The string to get the height of. - /// \returns Returns the string height. - float stringHeight(string s) const; + /// \returns the string height. + float stringHeight(const std::string& s) const; /// \brief Returns the bounding box of a string as a rectangle. /// \param s The string to get bounding box of. /// \param x X position of returned rectangle. /// \param y Y position of returned rectangle. - /// \returns Returns the bounding box of a string as a rectangle. - ofRectangle getStringBoundingBox(string s, float x, float y, bool vflip=true) const; + /// \returns the bounding box of a string as a rectangle. + ofRectangle getStringBoundingBox(const std::string& s, float x, float y, bool vflip=true) const; /// \} /// \name Drawing @@ -240,7 +336,7 @@ class ofTrueTypeFont{ /// \param s String to draw /// \param x X position of string /// \param y Y position of string - void drawString(string s, float x, float y) const; + void drawString(const std::string& s, float x, float y) const; /// \brief Draws the string as if it was geometrical shapes. /// @@ -248,31 +344,22 @@ class ofTrueTypeFont{ /// /// \param x X position of shapes /// \param y Y position of shapes - void drawStringAsShapes(string s, float x, float y) const; - - /// \brief Get the num chars in the loaded character set. - /// - /// If you allocate the font using different paramters, you can load in partial - /// and full character sets, this helps you know how many characters it can represent. - /// - /// \returns Number of characters in loaded character set. - int getNumCharacters() const; + void drawStringAsShapes(const std::string& s, float x, float y) const; /// \todo - ofTTFCharacter getCharacterAsPoints(int character, bool vflip=true, bool filled=true) const; - vector getStringAsPoints(string str, bool vflip=true, bool filled=true) const; - const ofMesh & getStringMesh(string s, float x, float y, bool vflip=true) const; + ofTTFCharacter getCharacterAsPoints(uint32_t character, bool vflip=true, bool filled=true) const; + vector getStringAsPoints(const std::string & str, bool vflip=true, bool filled=true) const; + const ofMesh & getStringMesh(const std::string & s, float x, float y, bool vflip=true) const; const ofTexture & getFontTexture() const; + ofTexture getStringTexture(const std::string & s, bool vflip=true) const; + bool isValidGlyph(uint32_t) const; + /// \} - /// \} - + void setDirection(ofTtfSettings::Direction direction); protected: /// \cond INTERNAL bool bLoadedOk; - bool bAntiAliased; - bool bFullCharacterSet; - int nCharacters; vector charOutlines; vector charOutlinesNonVFlipped; @@ -285,21 +372,40 @@ class ofTrueTypeFont{ ofRectangle glyphBBox; float letterSpacing; float spaceSize; + float fontUnitScale; - vector cps; // properties for each character - int fontSize; - bool bMakeContours; - float simplifyAmt; - int dpi; + struct glyphProps{ + std::size_t characterIndex; + uint32_t glyph; + long height; + long width; + long bearingX, bearingY; + long xmin, xmax, ymin, ymax; + long advance; + float tW,tH; + float t1,t2,v1,v2; + }; + struct glyph{ + glyphProps props; + ofPixels pixels; + }; - int getKerning(int c, int prevC) const; - void drawChar(int c, float x, float y, bool vFlipped) const; - void drawCharAsShape(int c, float x, float y, bool vFlipped, bool filled) const; - void createStringMesh(string s, float x, float y, bool vFlipped) const; - - string filename; + vector cps; // properties for each character + + ofTtfSettings settings; + unordered_map glyphIndexMap; + + + int getKerning(uint32_t c, uint32_t prevC) const; + void drawChar(uint32_t c, float x, float y, bool vFlipped) const; + void drawCharAsShape(uint32_t c, float x, float y, bool vFlipped, bool filled) const; + void createStringMesh(const string & s, float x, float y, bool vFlipped) const; + glyph loadGlyph(uint32_t utf8) const; + const glyphProps & getGlyphProperties(uint32_t glyph) const; + void iterateString(const string & str, float x, float y, bool vFlipped, std::function f) const; + size_t indexForGlyph(uint32_t glyph) const; ofTexture texAtlas; mutable ofMesh stringQuads; @@ -311,13 +417,13 @@ class ofTrueTypeFont{ friend void ofUnloadAllFontTextures(); friend void ofReloadAllFontTextures(); #endif - FT_Face face; + shared_ptr face; + static const glyphProps invalidProps; void unloadTextures(); void reloadTextures(); static bool initLibraries(); static void finishLibraries(); friend void ofExitCallback(); -}; - +}; diff --git a/libs/openFrameworks/math/ofMath.cpp b/libs/openFrameworks/math/ofMath.cpp index 53fc5fbeea5..139b91da12f 100644 --- a/libs/openFrameworks/math/ofMath.cpp +++ b/libs/openFrameworks/math/ofMath.cpp @@ -79,7 +79,6 @@ float ofNormalize(float value, float min, float max){ float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp) { if (fabs(inputMin - inputMax) < FLT_EPSILON){ - ofLogWarning("ofMath") << "ofMap(): avoiding possible divide by zero, check inputMin and inputMax: " << inputMin << " " << inputMax; return outputMin; } else { float outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin); diff --git a/libs/openFrameworks/math/ofMath.h b/libs/openFrameworks/math/ofMath.h index 101903b60b3..f76791bca15 100644 --- a/libs/openFrameworks/math/ofMath.h +++ b/libs/openFrameworks/math/ofMath.h @@ -150,6 +150,9 @@ float ofNormalize(float value, float min, float max); /// \param outputMin The lower bound of the output range. /// \param outputMax The upper bound of the output range. /// \param clamp True if the value should be clamped to [outputMin, outputMax). +/// \note If the absolute difference between inputMin and inputMax is less than +/// FLT_EPSILON, outputMin will be returned to prevent divide by zero +/// errors. /// \returns a mapped floating point number. float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp = false); @@ -369,7 +372,7 @@ float ofAngleDifferenceRadians(float currentAngle, float targetAngle); float ofWrap(float value, float from, float to); // \brief Convenience function for ofWrap(), constrained between -PI...PI -float ofWrapRadians(float angle, float from = -PI, float to=+PI); +float ofWrapRadians(float angle, float from = static_cast(-PI), float to=static_cast(PI)); // \brief Convenience function for ofWrap(), constrained between -180...180 float ofWrapDegrees(float angle, float from = -180, float to=+180); @@ -534,7 +537,7 @@ template Type ofInterpolateCosine(const Type& y1, const Type& y2, float pct){ float pct2; - pct2 = (1-cos(pct*PI))/2; + pct2 = (1-cos(pct*static_cast(PI)))/2; return(y1*(1-pct2)+y2*pct2); } diff --git a/libs/openFrameworks/math/ofMatrix3x3.h b/libs/openFrameworks/math/ofMatrix3x3.h index a217e7a497c..9510dcc504d 100644 --- a/libs/openFrameworks/math/ofMatrix3x3.h +++ b/libs/openFrameworks/math/ofMatrix3x3.h @@ -101,7 +101,8 @@ class ofMatrix3x3 { /// \brief Multiply a matrix by a matrix entry by entry (i.e. a*a, b*b, c*c...) - /// \brief This is referred to as an entrywise, Hadamard, or Schur product + /// + /// This is referred to as an entrywise, Hadamard, or Schur product. ofMatrix3x3 entrywiseTimes(const ofMatrix3x3& A); /// \} diff --git a/libs/openFrameworks/math/ofMatrix4x4.h b/libs/openFrameworks/math/ofMatrix4x4.h index 05473c6ba4b..05dc8dc2e2e 100644 --- a/libs/openFrameworks/math/ofMatrix4x4.h +++ b/libs/openFrameworks/math/ofMatrix4x4.h @@ -20,7 +20,7 @@ /// /// You'll sometimes see it used for doing things like setting where the camera /// in OpenGL (the mathematically calculated one, not the ofCamera one) is -/// looking or is pointedA, or figuring how to position something in 3d space, +/// looking or is pointed, or figuring how to position something in 3d space, /// doing scaling, etc. The great thing about the 4x4 matrix is that it can do /// all these things at the same time. A single ofMatrix4x4 can represent a ton /// of different information about a stuff that goes on in doing 3d @@ -145,7 +145,7 @@ class ofMatrix4x4 { /// \param z Z-value of the rotation axis. void makeRotationMatrix( float angle, float x, float y, float z ); /// \param quaternion Matrix becomes a rotation that produces the quaternion's orientation. - void makeRotationMatrix( const ofQuaternion& ); + void makeRotationMatrix( const ofQuaternion& quaternion ); /// \brief Matrix becomes a rotation around multiple axes. /// /// The final rotation is the result of rotating around each of the three @@ -316,22 +316,22 @@ class ofMatrix4x4 { /// \{ /// \brief Write data with `matrix(row,col)=number` - float& operator()(int row, int col) { + float& operator()(std::size_t row, std::size_t col) { return _mat[row][col]; } /// \brief Read data with `matrix(row, col)` - float operator()(int row, int col) const { + float operator()(std::size_t row, std::size_t col) const { return _mat[row][col]; } /// \brief returns a copy of row i - ofVec3f getRowAsVec3f(int i) const { + ofVec3f getRowAsVec3f(std::size_t i) const { return ofVec3f(_mat[i][0], _mat[i][1], _mat[i][2]); } /// \brief returns a copy of row i - ofVec4f getRowAsVec4f(int i) const { + ofVec4f getRowAsVec4f(std::size_t i) const { return _mat[i]; } @@ -756,12 +756,12 @@ inline void ofMatrix4x4::set(const ofMatrix4x4& rhs) { inline void ofMatrix4x4::set(float const * const ptr) { float* local_ptr = (float*)_mat; - for (int i = 0;i < 16;++i) local_ptr[i] = (float)ptr[i]; + for (std::size_t i = 0;i < 16;++i) local_ptr[i] = (float)ptr[i]; } inline void ofMatrix4x4::set(double const * const ptr) { float* local_ptr = (float*)_mat; - for (int i = 0;i < 16;++i) local_ptr[i] = (float)ptr[i]; + for (std::size_t i = 0;i < 16;++i) local_ptr[i] = (float)ptr[i]; } inline bool ofMatrix4x4::isIdentity() const { @@ -962,7 +962,7 @@ inline void ofMatrix4x4::preMultTranslate( const ofVec3f& v ) { /// \brief translates this matrix by treating the ofVec3f like a translation matrix, /// and multiplying this Matrix by it in a post-multiplication manner (M mult T) inline void ofMatrix4x4::postMultTranslate( const ofVec3f& v ) { - for (unsigned i = 0; i < 3; ++i) { + for (std::size_t i = 0; i < 3; ++i) { float tmp = v.getPtr()[i]; if (tmp == 0) continue; @@ -1042,7 +1042,7 @@ inline void ofMatrix4x4::rotate(float angle, float x, float y, float z){ /// \brief Rotates this Matrix by the provided angle (in Radians) around an axis defined by the three values inline void ofMatrix4x4::rotateRad(float angle, float x, float y, float z){ - postMultRotate(angle*RAD_TO_DEG,x,y,z); + postMultRotate(angle*static_cast(RAD_TO_DEG),x,y,z); } /// \brief Translates this matrix by the provided amount @@ -1071,7 +1071,7 @@ inline void ofMatrix4x4::glRotate(float angle, float x, float y, float z){ } inline void ofMatrix4x4::glRotateRad(float angle, float x, float y, float z){ - preMultRotate(ofQuaternion(angle*RAD_TO_DEG,ofVec3f(x,y,z))); + preMultRotate(ofQuaternion(angle*static_cast(RAD_TO_DEG),ofVec3f(x,y,z))); } inline void ofMatrix4x4::glRotate(const ofQuaternion& q){ @@ -1144,4 +1144,4 @@ inline ofVec4f operator* (const ofVec4f& v, const ofMatrix4x4& m ) { } -/// \endcond \ No newline at end of file +/// \endcond diff --git a/libs/openFrameworks/math/ofQuaternion.cpp b/libs/openFrameworks/math/ofQuaternion.cpp index 864aa164a48..bfc26fe9304 100644 --- a/libs/openFrameworks/math/ofQuaternion.cpp +++ b/libs/openFrameworks/math/ofQuaternion.cpp @@ -294,3 +294,21 @@ ofVec3f ofQuaternion::getEuler() const { #define QZ _v.z #define QW _v.w +//---------------------------------------- +std::ostream& operator<<(std::ostream& os, const ofQuaternion &q) { + os << q._v.x << ", " << q._v.y << ", " << q._v.z << ", " << q._v.w; + return os; +} + + +//---------------------------------------- +std::istream& operator>>(std::istream& is, ofQuaternion &q) { + is >> q._v.x; + is.ignore(2); + is >> q._v.y; + is.ignore(2); + is >> q._v.z; + is.ignore(2); + is >> q._v.w; + return is; +} diff --git a/libs/openFrameworks/math/ofQuaternion.h b/libs/openFrameworks/math/ofQuaternion.h index a9e273e7fc9..f0e4f4ff4b6 100644 --- a/libs/openFrameworks/math/ofQuaternion.h +++ b/libs/openFrameworks/math/ofQuaternion.h @@ -121,7 +121,7 @@ class ofQuaternion { void makeRotate(float angle1, const ofVec3f& axis1, float angle2, const ofVec3f& axis2, float angle3, const ofVec3f& axis3); - /// \briew Make a rotation Quat which will rotate vec1 to vec2. + /// \brief Make a rotation Quat which will rotate vec1 to vec2. /// Generally take a dot product to get the angle between these /// and then use a cross product to get the rotation axis /// Watch out for the two special cases when the vectors @@ -178,14 +178,12 @@ class ofQuaternion { inline const ofQuaternion operator -(const ofQuaternion& rhs) const; ///< Binary subtraction inline const ofQuaternion operator -() const; ///< returns the negative of the quaternion. calls operator -() on the Vec4 - inline ostream& operator<<(ostream& os); - inline istream& operator>>(istream& is); + friend ostream& operator<<(ostream& os, const ofQuaternion &q); + friend istream& operator>>(istream& is, ofQuaternion &q); /// \} }; - - // ---------------------------------------------------------------- // IMPLEMENTATION // ---------------------------------------------------------------- @@ -198,26 +196,6 @@ ofQuaternion::ofQuaternion() { } -//---------------------------------------- -ostream& ofQuaternion::operator<<(ostream& os) { - os << _v.x << ", " << _v.y << ", " << _v.z << ", " << _v.w; - return os; -} - - -//---------------------------------------- -istream& ofQuaternion::operator>>(istream& is) { - is >> _v.x; - is.ignore(2); - is >> _v.y; - is.ignore(2); - is >> _v.z; - is.ignore(2); - is >> _v.w; - return is; -} - - //---------------------------------------- ofQuaternion::ofQuaternion(float x, float y, float z, float w) { _v.set(x, y, z, w); @@ -408,14 +386,14 @@ ofQuaternion& ofQuaternion::operator*=(const ofQuaternion& rhs) { //---------------------------------------- ofQuaternion ofQuaternion::operator /(float rhs) const { - float div = 1.0 / rhs; + float div = 1.0f / rhs; return ofQuaternion(_v.x*div, _v.y*div, _v.z*div, _v.w*div); } //---------------------------------------- ofQuaternion& ofQuaternion::operator /=(float rhs) { - float div = 1.0 / rhs; + float div = 1.0f / rhs; _v.x *= div; _v.y *= div; _v.z *= div; diff --git a/libs/openFrameworks/math/ofVec2f.h b/libs/openFrameworks/math/ofVec2f.h index e7677db8d32..eb1687099a0 100644 --- a/libs/openFrameworks/math/ofVec2f.h +++ b/libs/openFrameworks/math/ofVec2f.h @@ -87,9 +87,6 @@ class ofVec2f { /// ofVec3f v3(0.1, 0.3); // v3.x is 0.1, v3.y is 0.3 /// ~~~~ /// - /// \param x The x component - /// \param y The y component - /// \returns A new ofVec2f with the `x` and `y` components set to 0 ofVec2f(); /// \brief Construct a 2D vector with `x` and `y` set to `scalar` @@ -105,7 +102,6 @@ class ofVec2f { /// /// \param x The x component /// \param y The y component - /// \returns A new ofVec2f with the `x` and `y` components set ofVec2f( float x, float y ); /// \brief Create a 2D vector (ofVec2f) from a 3D vector (ofVec3f) by @@ -248,7 +244,7 @@ class ofVec2f { /// This is handy if, for example, you want to find out when a point becomes /// *close enough* to another point to trigger an event. /// - bool match( const ofVec2f& vec, float tolerance=0.0001 ) const; + bool match( const ofVec2f& vec, float tolerance = 0.0001f ) const; /// \brief Determine if two vectors are aligned /// @@ -260,13 +256,13 @@ class ofVec2f { /// \param vec The vector to compare alignment with /// \param tolerance an angle tolerance/threshold (specified in degrees) for deciding if the vectors are sufficiently aligned. /// \returns true if both vectors are aligned (pointing in the same direction). - bool isAligned( const ofVec2f& vec, float tolerance=0.0001 ) const; + bool isAligned( const ofVec2f& vec, float tolerance = 0.0001f ) const; /// \brief Determine if two vectors are aligned with tolerance in radians /// \param vec The vector to compare alignment with /// \param tolerance an angle tolerance/threshold (specified in radians) for deciding if the vectors are sufficiently aligned. /// \sa isAligned() - bool isAlignedRad( const ofVec2f& vec, float tolerance=0.0001 ) const; + bool isAlignedRad( const ofVec2f& vec, float tolerance = 0.0001f ) const; /// \brief Determine if two vectors are aligned /// @@ -278,13 +274,13 @@ class ofVec2f { /// \param vec The vector to compare alignment with /// \param tolerance an angle tolerance/threshold (specified in degrees) for deciding if the vectors are sufficiently aligned. /// \returns true if both vectors are aligned (pointing in the same direction). - bool align( const ofVec2f& vec, float tolerance=0.0001 ) const; + bool align( const ofVec2f& vec, float tolerance = 0.0001f ) const; /// \brief Determine if two vectors are aligned with tolerance in radians /// \param vec The vector to compare alignment with /// \param tolerance an angle tolerance/threshold (specified in radians) for deciding if the vectors are sufficiently aligned. /// \sa align() - bool alignRad( const ofVec2f& vec, float tolerance=0.0001 ) const; + bool alignRad( const ofVec2f& vec, float tolerance = 0.0001f ) const; /// \} @@ -597,7 +593,7 @@ class ofVec2f { /// squareDistance() instead. /// /// \param pnt The point to calculate the distance to - /// \returns The distance as float + /// \returns The distance as float /// \sa squareDistance() float distance( const ofVec2f& pnt) const; @@ -718,7 +714,7 @@ class ofVec2f { /// \param points The array of ofVec2f to avarage over /// \param num specifies the number of ofVec2f in the array. /// \returns Vector that is the avarage of the points in the array - ofVec2f& average( const ofVec2f* points, int num ); + ofVec2f& average( const ofVec2f* points, std::size_t num ); /// \} @@ -770,13 +766,12 @@ class ofVec2f { /// // v2Limited is (2, 1) (same as v2) /// ~~~~ /// - /// \sa limit() + /// \sa limit() /// \param max The maximum length of the vector to return /// \returns A copy of this vector with its length (magnitude) restricted to a /// maximum of max units by scaling down if necessary. ofVec2f getLimited(float max) const; - ofVec2f& getLimited(float max); /// \brief Restrict the length (magnitude) of this vector to a maximum of max units by scaling down if necessary. /// @@ -789,7 +784,7 @@ class ofVec2f { /// // v2 is unchanged /// ~~~~ /// - /// \sa limit() + /// \sa limit() ofVec2f& limit(float max); @@ -1359,10 +1354,13 @@ inline ofVec2f& ofVec2f::middle( const ofVec2f& pnt ) { -inline ofVec2f& ofVec2f::average( const ofVec2f* points, int num ) { +inline ofVec2f& ofVec2f::average( const ofVec2f* points, std::size_t num ) { + if (0 == num) { + return *this; + } x = 0.f; y = 0.f; - for( int i=0; i 0.01) /// ~~~~ /// - bool match( const ofVec3f& vec, float tolerance=0.0001 ) const; + bool match( const ofVec3f& vec, float tolerance = 0.0001f ) const; /** * Checks if vectors look in the same direction. */ - bool isAligned( const ofVec3f& vec, float tolerance=0.0001 ) const; - bool isAlignedRad( const ofVec3f& vec, float tolerance=0.0001 ) const; + bool isAligned( const ofVec3f& vec, float tolerance = 0.0001f ) const; + bool isAlignedRad( const ofVec3f& vec, float tolerance = 0.0001f ) const; /// \brief Returns 'true' if this vector is pointing in the same direction as /// 'vec', with an angle error threshold 'tolerance' in degrees (default @@ -258,7 +258,7 @@ class ofVec3f { /// ofVec3f v2 = ofVec3f(4, 2, 7); /// // v1.align(v2, 0.0) is true /// ~~~~ - bool align( const ofVec3f& vec, float tolerance=0.0001 ) const; + bool align( const ofVec3f& vec, float tolerance = 0.0001f ) const; /// \brief Returns 'true' if this vector is pointing in the same direction /// as 'vec', with an angle error threshold 'tolerance' in radians @@ -269,7 +269,7 @@ class ofVec3f { /// ofVec3f v2 = ofVec3f(4, 2, 7); /// // v1.align(v2, 0.0) is true /// ~~~~ - bool alignRad( const ofVec3f& vec, float tolerance=0.0001 ) const; + bool alignRad( const ofVec3f& vec, float tolerance = 0.0001f ) const; /// \} diff --git a/libs/openFrameworks/math/ofVec4f.h b/libs/openFrameworks/math/ofVec4f.h index 39d68b09ca2..e2f165cb81f 100644 --- a/libs/openFrameworks/math/ofVec4f.h +++ b/libs/openFrameworks/math/ofVec4f.h @@ -61,7 +61,7 @@ class ofVec4f { bool operator==( const ofVec4f& vec ) const; bool operator!=( const ofVec4f& vec ) const; - bool match( const ofVec4f& vec, float tolerance=0.0001) const; + bool match( const ofVec4f& vec, float tolerance = 0.0001f) const; /// \} diff --git a/libs/openFrameworks/sound/ofBaseSoundStream.cpp b/libs/openFrameworks/sound/ofBaseSoundStream.cpp index 970c2b4d559..a160024bdc7 100644 --- a/libs/openFrameworks/sound/ofBaseSoundStream.cpp +++ b/libs/openFrameworks/sound/ofBaseSoundStream.cpp @@ -4,6 +4,56 @@ #include "ofSoundBuffer.h" #include "ofLog.h" + +std::string toString(ofSoundDevice::Api api){ + switch(api){ + case ofSoundDevice::ALSA: + return "Alsa"; + case ofSoundDevice::PULSE: + return "Pulse"; + case ofSoundDevice::OSS: + return "OSS"; + case ofSoundDevice::JACK: + return "Jack"; + case ofSoundDevice::OSX_CORE: + return "OSX Core Audio"; + case ofSoundDevice::MS_WASAPI: + return "MS WASAPI"; + case ofSoundDevice::MS_ASIO: + return "MS ASIO"; + case ofSoundDevice::MS_DS: + return "MS DirectShow"; + default: + return "Unkown API"; + } +} + + void ofBaseSoundStream::printDeviceList() const { - ofLogNotice("ofBaseSoundStream::printDeviceList") << std::endl << getDeviceList(); + ofLogNotice("ofBaseSoundStream::printDeviceList") << std::endl; + for(int i=ofSoundDevice::ALSA; i& devs) { + for(std::size_t i = 0; i < devs.size(); i++) { + os << devs[i] << std::endl; + } + return os; } diff --git a/libs/openFrameworks/sound/ofBaseSoundStream.h b/libs/openFrameworks/sound/ofBaseSoundStream.h index 5f90f817870..dbac7481ee5 100644 --- a/libs/openFrameworks/sound/ofBaseSoundStream.h +++ b/libs/openFrameworks/sound/ofBaseSoundStream.h @@ -4,61 +4,73 @@ class ofBaseSoundInput; class ofBaseSoundOutput; class ofSoundBuffer; +class ofSoundStreamSettings; /// \class ofSoundDevice /// \brief Represents information about a sound device on the system. class ofSoundDevice { public: - - ofSoundDevice(); + enum Api { + UNSPECIFIED, + DEFAULT, + ALSA, /*!< The Advanced Linux Sound Architecture API. */ + PULSE, /*!< The Linux PulseAudio API. */ + OSS, /*!< The Linux Open Sound System API. */ + JACK, /*!< The Jack Low-Latency Audio Server API. */ + OSX_CORE, /*!< Macintosh OS-X Core Audio API. */ + MS_WASAPI, /*!< The Microsoft WASAPI API. */ + MS_ASIO, /*!< The Steinberg Audio Stream I/O API. */ + MS_DS, /*!< The Microsoft Direct Sound API. */ + NUM_APIS + } api = UNSPECIFIED; friend std::ostream& operator << (std::ostream& os, const ofSoundDevice& dev); friend std::ostream& operator << (std::ostream& os, const std::vector& devs); /// \brief Descriptive name for the device /// This is the same string that ofSoundStream::getMatchingDevices() will be looking for - std::string name; + std::string name{"Unknown"}; /// \brief The device's unique ID (to be used in ofSoundStream::setDeviceID() ) - unsigned int deviceID; + int deviceID = -1; /// \brief Number of input channels the device supports - unsigned int inputChannels; + unsigned int inputChannels = 0; /// \brief Number of output channels the device supports - unsigned int outputChannels; + unsigned int outputChannels = 0; /// \brief If true, this device will be used by ofSoundStream unless changed with setDeviceID() - bool isDefaultInput; + bool isDefaultInput = false; /// \brief If true, this device will be used by ofSoundStream unless changed with setDeviceID() - bool isDefaultOutput; + bool isDefaultOutput = false; /// \brief List of sample rates the device claims to support std::vector sampleRates; }; -class ofBaseSoundStream{ - public: - virtual ~ofBaseSoundStream(){} - - virtual void setDeviceID(int deviceID) = 0; - virtual bool setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers)=0; - virtual bool setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers)=0; - virtual void setInput(ofBaseSoundInput * soundInput) = 0; - virtual void setOutput(ofBaseSoundOutput * soundOutput) = 0; - - virtual std::vector getDeviceList() const = 0; - virtual void printDeviceList() const; - - virtual void start() = 0; - virtual void stop() = 0; - virtual void close() = 0; +class ofBaseSoundStream { +public: + virtual ~ofBaseSoundStream() {} + virtual bool setup(const ofSoundStreamSettings & settings) = 0; + virtual void setInput(ofBaseSoundInput * soundInput) = 0; + virtual void setOutput(ofBaseSoundOutput * soundOutput) = 0; + + virtual std::vector getDeviceList(ofSoundDevice::Api api) const = 0; + virtual void printDeviceList() const; - virtual long unsigned long getTickCount() const = 0; - virtual int getNumInputChannels() const = 0; - virtual int getNumOutputChannels() const = 0; - virtual int getSampleRate() const = 0; - virtual int getBufferSize() const = 0; - virtual int getDeviceID() const = 0; + virtual void start() = 0; + virtual void stop() = 0; + virtual void close() = 0; + + virtual uint64_t getTickCount() const = 0; + virtual int getNumInputChannels() const = 0; + virtual int getNumOutputChannels() const = 0; + virtual int getSampleRate() const = 0; + virtual int getBufferSize() const = 0; + virtual ofSoundDevice getInDevice() const = 0; + virtual ofSoundDevice getOutDevice() const = 0; }; + +std::string toString(ofSoundDevice::Api api); diff --git a/libs/openFrameworks/sound/ofFmodSoundPlayer.cpp b/libs/openFrameworks/sound/ofFmodSoundPlayer.cpp index 876de8367e2..023da2acf82 100644 --- a/libs/openFrameworks/sound/ofFmodSoundPlayer.cpp +++ b/libs/openFrameworks/sound/ofFmodSoundPlayer.cpp @@ -4,11 +4,11 @@ #include "ofUtils.h" -bool bFmodInitialized_ = false; -bool bUseSpectrum_ = false; -float fftValues_[8192]; // -float fftInterpValues_[8192]; // -float fftSpectrum_[8192]; // maximum #ofFmodSoundPlayer is 8192, in fmodex.... +static bool bFmodInitialized_ = false; +static float fftValues_[8192]; // +static float fftInterpValues_[8192]; // +static float fftSpectrum_[8192]; // maximum #ofFmodSoundPlayer is 8192, in fmodex.... +static unsigned int buffersize = 1024; // --------------------- static vars @@ -124,6 +124,10 @@ float * ofFmodSoundGetSpectrum(int nBands){ return fftInterpValues_; } +void ofFmodSetBuffersize(unsigned int bs){ + buffersize = bs; +} + // ------------------------------------------------------------ // ------------------------------------------------------------ @@ -151,7 +155,15 @@ ofFmodSoundPlayer::~ofFmodSoundPlayer(){ // this should only be called once void ofFmodSoundPlayer::initializeFmod(){ if(!bFmodInitialized_){ + FMOD_System_Create(&sys); + + // set buffersize, keep number of buffers + unsigned int bsTmp; + int nbTmp; + FMOD_System_GetDSPBufferSize(sys, &bsTmp, &nbTmp); + FMOD_System_SetDSPBufferSize(sys, buffersize, nbTmp); + #ifdef TARGET_LINUX FMOD_System_SetOutput(sys,FMOD_OUTPUTTYPE_ALSA); #endif @@ -162,6 +174,8 @@ void ofFmodSoundPlayer::initializeFmod(){ } + + //--------------------------------------- void ofFmodSoundPlayer::closeFmod(){ if(bFmodInitialized_){ diff --git a/libs/openFrameworks/sound/ofFmodSoundPlayer.h b/libs/openFrameworks/sound/ofFmodSoundPlayer.h index c6fae6e20ab..55a5fe91cd8 100644 --- a/libs/openFrameworks/sound/ofFmodSoundPlayer.h +++ b/libs/openFrameworks/sound/ofFmodSoundPlayer.h @@ -29,6 +29,7 @@ void ofFmodSoundStopAll(); void ofFmodSoundSetVolume(float vol); void ofFmodSoundUpdate(); // calls FMOD update. float * ofFmodSoundGetSpectrum(int nBands); // max 512... +void ofFmodSetBuffersize(unsigned int bs); // --------------------- player functions: @@ -63,6 +64,7 @@ class ofFmodSoundPlayer : public ofBaseSoundPlayer { static void initializeFmod(); static void closeFmod(); + bool isStreaming; bool bMultiPlay; diff --git a/libs/openFrameworks/sound/ofRtAudioSoundStream.cpp b/libs/openFrameworks/sound/ofRtAudioSoundStream.cpp index 7e2aceefeb9..8be73475b57 100644 --- a/libs/openFrameworks/sound/ofRtAudioSoundStream.cpp +++ b/libs/openFrameworks/sound/ofRtAudioSoundStream.cpp @@ -1,275 +1,312 @@ #include "ofRtAudioSoundStream.h" -#include "ofConstants.h" - -#ifdef OF_SOUNDSTREAM_RTAUDIO -#include "ofSoundStream.h" #include "ofMath.h" #include "ofUtils.h" +#include "ofAppRunner.h" #include "RtAudio.h" +//------------------------------------------------------------------------------ +RtAudio::Api toRtAudio(ofSoundDevice::Api api){ + switch (api) { + case ofSoundDevice::Api::ALSA: + return RtAudio::Api::LINUX_ALSA; + case ofSoundDevice::Api::PULSE: + return RtAudio::Api::LINUX_PULSE; + case ofSoundDevice::Api::OSS: + return RtAudio::Api::LINUX_OSS; + case ofSoundDevice::Api::JACK: + return RtAudio::Api::UNIX_JACK; +#ifndef TARGET_LINUX + case ofSoundDevice::Api::OSX_CORE: + return RtAudio::Api::MACOSX_CORE; + case ofSoundDevice::Api::MS_WASAPI: + return RtAudio::Api::WINDOWS_WASAPI; + case ofSoundDevice::Api::MS_ASIO: + return RtAudio::Api::WINDOWS_ASIO; + case ofSoundDevice::Api::MS_DS: + return RtAudio::Api::WINDOWS_DS; +#endif + default: + return RtAudio::Api::UNSPECIFIED; + } +} //------------------------------------------------------------------------------ -ofRtAudioSoundStream::ofRtAudioSoundStream(){ - outDeviceID = -1; - inDeviceID = -1; - soundOutputPtr = nullptr; - soundInputPtr = nullptr; - tickCount= 0; - nOutputChannels = 0; - nInputChannels = 0; - bufferSize = 0; - sampleRate = 0; +ofSoundDevice::Api toOf(RtAudio::Api api){ + switch (api) { + case RtAudio::Api::LINUX_ALSA: + return ofSoundDevice::Api::ALSA; + case RtAudio::Api::LINUX_PULSE: + return ofSoundDevice::Api::PULSE; + case RtAudio::Api::LINUX_OSS: + return ofSoundDevice::Api::OSS; + case RtAudio::Api::UNIX_JACK: + return ofSoundDevice::Api::JACK; +#ifndef TARGET_LINUX + case RtAudio::Api::MACOSX_CORE: + return ofSoundDevice::Api::OSX_CORE; + case RtAudio::Api::WINDOWS_WASAPI: + return ofSoundDevice::Api::MS_WASAPI; + case RtAudio::Api::WINDOWS_ASIO: + return ofSoundDevice::Api::MS_ASIO; + case RtAudio::Api::WINDOWS_DS: + return ofSoundDevice::Api::MS_DS; +#endif + default: + return ofSoundDevice::Api::UNSPECIFIED; + } } //------------------------------------------------------------------------------ -ofRtAudioSoundStream::~ofRtAudioSoundStream(){ +ofRtAudioSoundStream::ofRtAudioSoundStream() { + tickCount = 0; +} + +//------------------------------------------------------------------------------ +ofRtAudioSoundStream::~ofRtAudioSoundStream() { stop(); close(); } //------------------------------------------------------------------------------ -vector ofRtAudioSoundStream::getDeviceList() const{ - shared_ptr audioTemp; - try { - audioTemp = shared_ptr(new RtAudio()); - } catch (std::exception &error) { - ofLogError() << error.what(); - return vector(); - } - int deviceCount = audioTemp->getDeviceCount(); - RtAudio::DeviceInfo info; +std::vector ofRtAudioSoundStream::getDeviceList(ofSoundDevice::Api api) const{ vector deviceList; - for (int i=0; i< deviceCount; i++) { - try { - info = audioTemp->getDeviceInfo(i); - } catch (std::exception &error) { - ofLogError("ofRtAudioSoundStream") << "Error retrieving info for device " << i; - ofLogError() << error.what(); - break; + try { + auto rtAudioApi = toRtAudio(api); + RtAudio audioTemp(toRtAudio(api)); + audioTemp.showWarnings(false); + if(audioTemp.getCurrentApi()!=rtAudioApi && rtAudioApi!=RtAudio::Api::UNSPECIFIED){ + return deviceList; } - - ofSoundDevice dev; - dev.deviceID = i; - dev.name = info.name; - dev.outputChannels = info.outputChannels; - dev.inputChannels = info.inputChannels; - dev.sampleRates = info.sampleRates; - dev.isDefaultInput = info.isDefaultInput; - dev.isDefaultOutput = info.isDefaultOutput; - deviceList.push_back(dev); - } - - return deviceList; -} - -//------------------------------------------------------------------------------ -void ofRtAudioSoundStream::setDeviceID(int _deviceID){ - inDeviceID = outDeviceID = _deviceID; -} + auto deviceCount = audioTemp.getDeviceCount(); + RtAudio::DeviceInfo info; + for (unsigned int i = 0; i < deviceCount; i++) { + try { + info = audioTemp.getDeviceInfo(i); + } + catch (std::exception &error) { + ofLogError("ofRtAudioSoundStream") << "Error retrieving info for device " << i; + ofLogError() << error.what(); + break; + } -int ofRtAudioSoundStream::getDeviceID() const{ - return inDeviceID; -} + ofSoundDevice dev; + dev.deviceID = i; + dev.name = info.name; + dev.outputChannels = info.outputChannels; + dev.inputChannels = info.inputChannels; + dev.sampleRates = info.sampleRates; + dev.isDefaultInput = info.isDefaultInput; + dev.isDefaultOutput = info.isDefaultOutput; + dev.api = api; + deviceList.push_back(dev); + } + }catch (std::exception &error) { + ofLogError() << error.what(); + } -void ofRtAudioSoundStream::setInDeviceID(int _deviceID){ - inDeviceID = _deviceID; -} + return deviceList; -void ofRtAudioSoundStream::setOutDeviceID(int _deviceID){ - outDeviceID = _deviceID; } //------------------------------------------------------------------------------ -void ofRtAudioSoundStream::setInput(ofBaseSoundInput * soundInput){ - soundInputPtr = soundInput; +void ofRtAudioSoundStream::setInput(ofBaseSoundInput * soundInput) { + settings.setInListener(soundInput); } //------------------------------------------------------------------------------ -void ofRtAudioSoundStream::setOutput(ofBaseSoundOutput * soundOutput){ - soundOutputPtr = soundOutput; +void ofRtAudioSoundStream::setOutput(ofBaseSoundOutput * soundOutput) { + settings.setOutListener(soundOutput); } //------------------------------------------------------------------------------ -bool ofRtAudioSoundStream::setup(int outChannels, int inChannels, int _sampleRate, int _bufferSize, int nBuffers){ - if( audio != nullptr ){ +bool ofRtAudioSoundStream::setup(const ofSoundStreamSettings & settings_) +{ + if (audio != nullptr) { close(); } - nInputChannels = inChannels; - nOutputChannels = outChannels; + this->settings = settings_; - sampleRate = _sampleRate; - tickCount = 0; - bufferSize = ofNextPow2(_bufferSize); // must be pow2 + tickCount = 0; + this->settings.bufferSize = ofNextPow2(settings.bufferSize); // must be pow2 try { - audio = shared_ptr(new RtAudio()); - } catch (std::exception &error) { - ofLogError() << error.what(); + if (settings.getApi() != ofSoundDevice::Api::UNSPECIFIED) { + audio = std::make_shared(toRtAudio(settings.getApi())); + }else{ + audio = std::make_shared(); + } + } + catch (std::exception &error) { + ofLogError() << error.what(); return false; } RtAudio::StreamParameters outputParameters; RtAudio::StreamParameters inputParameters; - if(nInputChannels>0){ - if( inDeviceID >= 0 ){ - inputParameters.deviceId = inDeviceID; - }else{ - inputParameters.deviceId = audio->getDefaultInputDevice(); + if (settings.numInputChannels > 0) { + if (!settings.getInDevice()) { + ofSoundDevice device = *settings.getInDevice(); + device.deviceID = audio->getDefaultInputDevice(); + settings.setInDevice(device); } - inputParameters.nChannels = nInputChannels; + inputParameters.deviceId = settings.getInDevice()->deviceID; + inputParameters.nChannels = settings.numInputChannels; } - if(nOutputChannels>0){ - if( outDeviceID >= 0 ){ - outputParameters.deviceId = outDeviceID; - }else{ - outputParameters.deviceId = audio->getDefaultOutputDevice(); + if (settings.numOutputChannels > 0) { + if (!settings.getOutDevice()) { + ofSoundDevice device = *settings.getOutDevice(); + device.deviceID = audio->getDefaultOutputDevice(); + settings.setOutDevice(device); } - outputParameters.nChannels = nOutputChannels; + outputParameters.deviceId = settings.getOutDevice()->deviceID; + outputParameters.nChannels = settings.numOutputChannels; } - unsigned int bufferFrames = (unsigned int)bufferSize; // 256 sample frames - RtAudio::StreamOptions options; options.flags = RTAUDIO_SCHEDULE_REALTIME; - options.numberOfBuffers = nBuffers; + options.numberOfBuffers = settings.numBuffers; options.priority = 1; - outputBuffer.setDeviceID(outDeviceID); - inputBuffer.setDeviceID(inDeviceID); - + outputBuffer.setDeviceID(outputParameters.deviceId); + inputBuffer.setDeviceID(inputParameters.deviceId); + unsigned int bufferSize = settings.bufferSize; try { - audio ->openStream( (nOutputChannels>0)?&outputParameters:nullptr, (nInputChannels>0)?&inputParameters:nullptr, RTAUDIO_FLOAT32, - sampleRate, &bufferFrames, &rtAudioCallback, this, &options); + audio->openStream((settings.numOutputChannels > 0) ? &outputParameters : nullptr, (settings.numInputChannels > 0) ? &inputParameters : nullptr, RTAUDIO_FLOAT32, + settings.sampleRate, &bufferSize, &rtAudioCallback, this, &options); audio->startStream(); - } catch (std::exception &error) { - ofLogError() << error.what(); - return false; - } + } + catch (std::exception &error) { + ofLogError() << error.what(); + return false; + } return true; } //------------------------------------------------------------------------------ -bool ofRtAudioSoundStream::setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ - setInput(app); - setOutput(app); - return setup(outChannels,inChannels,sampleRate,bufferSize,nBuffers); -} +void ofRtAudioSoundStream::start() { + if (audio == nullptr) return; -//------------------------------------------------------------------------------ -void ofRtAudioSoundStream::start(){ - if( audio == nullptr ) return; - - try{ + try { audio->startStream(); - } catch (std::exception &error) { - ofLogError() << error.what(); - } + } + catch (std::exception &error) { + ofLogError() << error.what(); + } } //------------------------------------------------------------------------------ -void ofRtAudioSoundStream::stop(){ - if( audio == nullptr ) return; +void ofRtAudioSoundStream::stop() { + if (audio == nullptr) return; try { - if(audio->isStreamRunning()) { - audio->stopStream(); + if (audio->isStreamRunning()) { + audio->stopStream(); } - } catch (std::exception &error) { - ofLogError() << error.what(); - } + } + catch (std::exception &error) { + ofLogError() << error.what(); + } } //------------------------------------------------------------------------------ -void ofRtAudioSoundStream::close(){ - if( audio == nullptr ) return; +void ofRtAudioSoundStream::close() { + if (audio == nullptr) return; try { - if(audio->isStreamOpen()) { - audio->closeStream(); + if (audio->isStreamOpen()) { + audio->closeStream(); } - } catch (std::exception &error) { - ofLogError() << error.what(); - } - soundOutputPtr = nullptr; - soundInputPtr = nullptr; + } + catch (std::exception &error) { + ofLogError() << error.what(); + } + settings.outCallback = nullptr; + settings.inCallback = nullptr; audio.reset(); // delete } //------------------------------------------------------------------------------ -long unsigned long ofRtAudioSoundStream::getTickCount() const{ +uint64_t ofRtAudioSoundStream::getTickCount() const { return tickCount; } //------------------------------------------------------------------------------ -int ofRtAudioSoundStream::getNumInputChannels() const{ - return nInputChannels; +int ofRtAudioSoundStream::getNumInputChannels() const { + return settings.numInputChannels; } //------------------------------------------------------------------------------ -int ofRtAudioSoundStream::getNumOutputChannels() const{ - return nOutputChannels; +int ofRtAudioSoundStream::getNumOutputChannels() const { + return settings.numOutputChannels; } //------------------------------------------------------------------------------ -int ofRtAudioSoundStream::getSampleRate() const{ - return sampleRate; +int ofRtAudioSoundStream::getSampleRate() const { + return settings.sampleRate; } //------------------------------------------------------------------------------ -int ofRtAudioSoundStream::getBufferSize() const{ - return bufferSize; +int ofRtAudioSoundStream::getBufferSize() const { + return settings.bufferSize; +} + +ofSoundDevice ofRtAudioSoundStream::getInDevice() const{ + return *settings.getInDevice(); +} + +ofSoundDevice ofRtAudioSoundStream::getOutDevice() const{ + return *settings.getOutDevice(); } //------------------------------------------------------------------------------ -int ofRtAudioSoundStream::rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFramesPerBuffer, double streamTime, RtAudioStreamStatus status, void *data){ +int ofRtAudioSoundStream::rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFramesPerBuffer, double streamTime, RtAudioStreamStatus status, void *data) { ofRtAudioSoundStream * rtStreamPtr = (ofRtAudioSoundStream *)data; - - if ( status ) { + + if (status) { ofLogWarning("ofRtAudioSoundStream") << "stream over/underflow detected"; } - + // rtAudio uses a system by which the audio // can be of different formats // char, float, etc. // we choose float float * fPtrOut = (float *)outputBuffer; - float * fPtrIn = (float *)inputBuffer; + float * fPtrIn = (float *)inputBuffer; // [zach] memset output to zero before output call // this is because of how rtAudio works: duplex w/ one callback // you need to cut in the middle. if the simpleApp // doesn't produce audio, we pass silence instead of duplex... - - int nInputChannels = rtStreamPtr->getNumInputChannels(); - int nOutputChannels = rtStreamPtr->getNumOutputChannels(); - - if(nInputChannels > 0){ - if( rtStreamPtr->soundInputPtr != nullptr ){ + + auto nInputChannels = rtStreamPtr->getNumInputChannels(); + auto nOutputChannels = rtStreamPtr->getNumOutputChannels(); + + if (nInputChannels > 0) { + if (rtStreamPtr->settings.inCallback) { rtStreamPtr->inputBuffer.copyFrom(fPtrIn, nFramesPerBuffer, nInputChannels, rtStreamPtr->getSampleRate()); rtStreamPtr->inputBuffer.setTickCount(rtStreamPtr->tickCount); - rtStreamPtr->soundInputPtr->audioIn(rtStreamPtr->inputBuffer); + rtStreamPtr->settings.inCallback(rtStreamPtr->inputBuffer); } // [damian] not sure what this is for? assuming it's for underruns? or for when the sound system becomes broken? memset(fPtrIn, 0, nFramesPerBuffer * nInputChannels * sizeof(float)); } - + if (nOutputChannels > 0) { - if( rtStreamPtr->soundOutputPtr != nullptr ){ - - if ( rtStreamPtr->outputBuffer.size() != nFramesPerBuffer*nOutputChannels || rtStreamPtr->outputBuffer.getNumChannels()!=nOutputChannels ){ + if (rtStreamPtr->settings.outCallback) { + + if (rtStreamPtr->outputBuffer.size() != nFramesPerBuffer*nOutputChannels || rtStreamPtr->outputBuffer.getNumChannels() != nOutputChannels) { rtStreamPtr->outputBuffer.setNumChannels(nOutputChannels); rtStreamPtr->outputBuffer.resize(nFramesPerBuffer*nOutputChannels); } rtStreamPtr->outputBuffer.setTickCount(rtStreamPtr->tickCount); - rtStreamPtr->soundOutputPtr->audioOut(rtStreamPtr->outputBuffer); + rtStreamPtr->settings.outCallback(rtStreamPtr->outputBuffer); } - rtStreamPtr->outputBuffer.copyTo(fPtrOut, nFramesPerBuffer, nOutputChannels,0); + rtStreamPtr->outputBuffer.copyTo(fPtrOut, nFramesPerBuffer, nOutputChannels, 0); rtStreamPtr->outputBuffer.set(0); } - + // increment tick count rtStreamPtr->tickCount++; - + return 0; } -#endif diff --git a/libs/openFrameworks/sound/ofRtAudioSoundStream.h b/libs/openFrameworks/sound/ofRtAudioSoundStream.h index 00b3b22d405..2b49c2880c2 100644 --- a/libs/openFrameworks/sound/ofRtAudioSoundStream.h +++ b/libs/openFrameworks/sound/ofRtAudioSoundStream.h @@ -3,55 +3,46 @@ #include "ofConstants.h" #include "ofBaseSoundStream.h" +#include "ofSoundStream.h" #include "ofTypes.h" #include "ofSoundBuffer.h" -class RtAudio; typedef unsigned int RtAudioStreamStatus; +class RtAudio; -class ofRtAudioSoundStream : public ofBaseSoundStream{ - public: - ofRtAudioSoundStream(); - ~ofRtAudioSoundStream(); - - std::vector getDeviceList() const; - void setDeviceID(int deviceID); - void setInDeviceID(int deviceID); - void setOutDeviceID(int deviceID); - - void setInput(ofBaseSoundInput * soundInput); - void setOutput(ofBaseSoundOutput * soundOutput); - bool setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); - bool setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); - - void start(); - void stop(); - void close(); - - long unsigned long getTickCount() const; - - int getNumInputChannels() const; - int getNumOutputChannels() const; - int getSampleRate() const; - int getBufferSize() const; - int getDeviceID() const; - - private: - long unsigned long tickCount; - shared_ptr audio; - int sampleRate; - int outDeviceID; - int inDeviceID; - int bufferSize; - int nInputChannels; - int nOutputChannels; - ofBaseSoundInput * soundInputPtr; - ofBaseSoundOutput * soundOutputPtr; - ofSoundBuffer inputBuffer; - ofSoundBuffer outputBuffer; - - static int rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int bufferSize, double streamTime, RtAudioStreamStatus status, void *data); +class ofRtAudioSoundStream : public ofBaseSoundStream { +public: + ofRtAudioSoundStream(); + ~ofRtAudioSoundStream(); -}; + std::vector getDeviceList(ofSoundDevice::Api api) const; + + void setInput(ofBaseSoundInput * soundInput); + void setOutput(ofBaseSoundOutput * soundOutput); + bool setup(const ofSoundStreamSettings & settings); + + void start(); + void stop(); + void close(); + + uint64_t getTickCount() const; + int getNumInputChannels() const; + int getNumOutputChannels() const; + int getSampleRate() const; + int getBufferSize() const; + ofSoundDevice getInDevice() const; + ofSoundDevice getOutDevice() const; + +private: + long unsigned long tickCount; + std::shared_ptr audio; + + ofSoundBuffer inputBuffer; + ofSoundBuffer outputBuffer; + ofSoundStreamSettings settings; + + static int rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int bufferSize, double streamTime, RtAudioStreamStatus status, void *data); + +}; diff --git a/libs/openFrameworks/sound/ofSoundBuffer.cpp b/libs/openFrameworks/sound/ofSoundBuffer.cpp index 80a8eb1a526..698a6da311d 100644 --- a/libs/openFrameworks/sound/ofSoundBuffer.cpp +++ b/libs/openFrameworks/sound/ofSoundBuffer.cpp @@ -117,7 +117,9 @@ void ofSoundBuffer::set(float value){ checkSizeAndChannelsConsistency("set"); } -bool ofSoundBuffer::checkSizeAndChannelsConsistency( string function ) { +bool ofSoundBuffer::checkSizeAndChannelsConsistency(const std::string& _function ) { + std::string function = _function; + if ( function.size()!= 0 ){ function += ": "; } @@ -351,7 +353,7 @@ void ofSoundBuffer::linearResampleTo(ofSoundBuffer &outBuffer, std::size_t fromF for(std::size_t i=0;ibuffer[0]; + targetBuffer.resize(getNumFrames()); + const float * bufferPtr = &this->buffer[sourceChannel]; for(std::size_t i = 0; i < targetBuffer.getNumFrames(); i++){ targetBuffer[i] = *bufferPtr; bufferPtr += channels; @@ -513,7 +515,7 @@ void ofSoundBuffer::setChannel(const ofSoundBuffer & inBuffer, std::size_t targe resize(inBuffer.getNumFrames() * channels); // copy from inBuffer to targetChannel float * bufferPtr = &this->buffer[targetChannel]; - const float * inBufferPtr = &(inBuffer[0]); + const float * inBufferPtr = &(inBuffer[targetChannel]); for(std::size_t i = 0; i < getNumFrames(); i++){ *bufferPtr = *inBufferPtr; bufferPtr += channels; diff --git a/libs/openFrameworks/sound/ofSoundBuffer.h b/libs/openFrameworks/sound/ofSoundBuffer.h index c3d2892acad..a447ad814c0 100644 --- a/libs/openFrameworks/sound/ofSoundBuffer.h +++ b/libs/openFrameworks/sound/ofSoundBuffer.h @@ -190,16 +190,16 @@ class ofSoundBuffer { void hermiteResampleTo(ofSoundBuffer & buffer, std::size_t fromFrame, std::size_t numFrames, float speed, bool loop) const; /// fills the buffer with random noise between -amplitude and amplitude. useful for debugging. - void fillWithNoise(float amplitude = 1); + void fillWithNoise(float amplitude = 1.0f); /// fills the buffer with a sine wave. useful for debugging. - float fillWithTone(float pitchHz = 440., float phase = 0); + float fillWithTone(float pitchHz = 440.0f, float phase = 0.0f); /// amplifies samples so that the maximum amplitude is equal to 'level' void normalize(float level = 1); /// removes initial / ending silence from the buffer - bool trimSilence(float threshold = 0.0001, bool trimStart = true, bool trimEnd = true); + bool trimSilence(float threshold = 0.0001f, bool trimStart = true, bool trimEnd = true); /// return the total number of samples in this buffer (==getNumFrames()*getNumChannels()) std::size_t size() const { return buffer.size(); } @@ -219,7 +219,7 @@ class ofSoundBuffer { protected: // checks that size() and number of channels are consistent, logs a warning if not. returns consistency check result. - bool checkSizeAndChannelsConsistency( string function="" ); + bool checkSizeAndChannelsConsistency(const std::string& function="" ); vector buffer; std::size_t channels; diff --git a/libs/openFrameworks/sound/ofSoundStream.cpp b/libs/openFrameworks/sound/ofSoundStream.cpp index 156023da1ef..426ad5028f5 100644 --- a/libs/openFrameworks/sound/ofSoundStream.cpp +++ b/libs/openFrameworks/sound/ofSoundStream.cpp @@ -1,8 +1,77 @@ #include "ofSoundStream.h" #include "ofAppRunner.h" -ofSoundStream soundStreamInput; -ofSoundStream soundStreamOutput; +#if defined(OF_SOUND_PLAYER_FMOD) +#include "ofSoundPlayer.h" +#endif + +#ifdef OF_SOUNDSTREAM_RTAUDIO +#include "ofRtAudioSoundStream.h" +#define OF_SOUND_STREAM_TYPE ofRtAudioSoundStream +#elif defined(OF_SOUNDSTREAM_ANDROID) +#include "ofxAndroidSoundStream.h" +#define OF_SOUND_STREAM_TYPE ofxAndroidSoundStream +#elif defined(OF_SOUNDSTREAM_IOS) +#include "ofxiOSSoundStream.h" +#define OF_SOUND_STREAM_TYPE ofxiOSSoundStream +#elif defined(OF_SOUNDSTREAM_EMSCRIPTEN) +#include "ofxEmscriptenSoundStream.h" +#define OF_SOUND_STREAM_TYPE ofxEmscriptenSoundStream +#endif + +namespace{ + ofSoundStream systemSoundStream; +} + +//------------------------------------------------------------ +bool ofSoundStreamSettings::setInDevice(const ofSoundDevice & device){ + if(api!=ofSoundDevice::UNSPECIFIED && device.api!=api){ + ofLogWarning("ofSoundStreamSettings") << "Setting IN device with api: " << toString(device.api) << " will override the previously set: " << toString(api); + } + api = device.api; + inDevice = device; + return true; +} + +//------------------------------------------------------------ +bool ofSoundStreamSettings::setOutDevice(const ofSoundDevice & device){ + if(api!=ofSoundDevice::UNSPECIFIED && device.api!=api){ + ofLogWarning("ofSoundStreamSettings") << "Setting OUT device with api: " << toString(device.api) << " will override the previously set: " << toString(api); + } + api = device.api; + outDevice = device; + return true; +} + +//------------------------------------------------------------ +bool ofSoundStreamSettings::setApi(ofSoundDevice::Api api){ + if(api!=ofSoundDevice::UNSPECIFIED && inDevice.deviceID!=-1 && inDevice.api != api){ + ofLogError("ofSoundStreamSettings") << "Setting API after setting IN device with api: " << toString(inDevice.api) << " won't do anything"; + return false; + } + if(api!=ofSoundDevice::UNSPECIFIED && outDevice.deviceID!=-1 && outDevice.api != api){ + ofLogError("ofSoundStreamSettings") << "Setting API after setting IN device with api: " << toString(outDevice.api) << " won't do anything"; + return false; + } + this->api = api; + return true; +} + +//------------------------------------------------------------ +const ofSoundDevice * ofSoundStreamSettings::getInDevice() const{ + return inDevice.deviceID==-1 ? nullptr : &inDevice; +} + +//------------------------------------------------------------ +const ofSoundDevice * ofSoundStreamSettings::getOutDevice() const{ + return outDevice.deviceID==-1 ? nullptr : &outDevice; +} + +//------------------------------------------------------------ +ofSoundDevice::Api ofSoundStreamSettings::getApi() const{ + return api; +} + //------------------------------------------------------------ void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr){ @@ -19,30 +88,32 @@ void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, int sampleRate, //------------------------------------------------------------ void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr, int sampleRate, int bufferSize, int nBuffers){ - soundStreamOutput.setup(appPtr, nOutputChannels, nInputChannels, sampleRate, bufferSize, nBuffers); + systemSoundStream.setup(appPtr, nOutputChannels, nInputChannels, sampleRate, bufferSize, nBuffers); +} + +//------------------------------------------------------------ +void ofSoundStreamSetup(ofSoundStreamSettings & settings) { + systemSoundStream.setup(settings); } //------------------------------------------------------------ void ofSoundStreamStop(){ - soundStreamOutput.stop(); - soundStreamInput.stop(); + systemSoundStream.stop(); } //------------------------------------------------------------ void ofSoundStreamStart(){ - soundStreamOutput.start(); - soundStreamInput.start(); + systemSoundStream.start(); } //------------------------------------------------------------ void ofSoundStreamClose(){ - soundStreamOutput.close(); - soundStreamInput.close(); + systemSoundStream.close(); } //------------------------------------------------------------ vector ofSoundStreamListDevices(){ - vector deviceList = soundStreamOutput.getDeviceList(); + vector deviceList = systemSoundStream.getDeviceList(); ofLogNotice("ofSoundStreamListDevices") << std::endl << deviceList; return deviceList; } @@ -65,9 +136,9 @@ shared_ptr ofSoundStream::getSoundStream(){ } //------------------------------------------------------------ -vector ofSoundStream::getDeviceList() const{ +vector ofSoundStream::getDeviceList(ofSoundDevice::Api api) const{ if( soundStream ){ - return soundStream->getDeviceList(); + return soundStream->getDeviceList(api); } else { return vector(); } @@ -90,7 +161,7 @@ void ofSoundStream::printDeviceList() const{ //------------------------------------------------------------ void ofSoundStream::setDeviceID(int deviceID){ if( soundStream ){ - soundStream->setDeviceID(deviceID); + tmpDeviceId = deviceID; } } @@ -99,10 +170,58 @@ void ofSoundStream::setDevice(const ofSoundDevice &device) { setDeviceID(device.deviceID); } +//------------------------------------------------------------ +bool ofSoundStream::setup(const ofSoundStreamSettings & settings) +{ + if (soundStream) { +#if defined(OF_SOUND_PLAYER_FMOD) + ofFmodSetBuffersize(settings.bufferSize); +#endif + return soundStream->setup(settings); + } + return false; +} + //------------------------------------------------------------ bool ofSoundStream::setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ if( soundStream ){ - return soundStream->setup(app, outChannels, inChannels, sampleRate, bufferSize, nBuffers); + ofSoundStreamSettings settings; + settings.setInListener(app); + settings.setOutListener(app); + settings.numOutputChannels = outChannels; + settings.numInputChannels = inChannels; + settings.sampleRate = sampleRate; + settings.bufferSize = bufferSize; + settings.numBuffers = nBuffers; + if(tmpDeviceId!=-1){ + ofSoundDevice device; + device.deviceID = tmpDeviceId; + settings.setInDevice(device); + settings.setOutDevice(device); + } + return soundStream->setup(settings); + } + return false; +} + +//------------------------------------------------------------ +bool ofSoundStream::setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ + if( soundStream ){ + ofSoundStreamSettings settings; + settings.setInListener(ofGetAppPtr()); + settings.setOutListener(ofGetAppPtr()); + settings.numOutputChannels = outChannels; + settings.numInputChannels = inChannels; + settings.sampleRate = sampleRate; + settings.bufferSize = bufferSize; + settings.numBuffers = nBuffers; + if(tmpDeviceId!=-1){ + ofSoundDevice device; + device.deviceID = tmpDeviceId; + settings.setInDevice(device); + settings.setOutDevice(device); + } + return soundStream->setup(settings); } return false; } @@ -131,14 +250,6 @@ void ofSoundStream::setOutput(ofBaseSoundOutput &soundOutput){ setOutput(&soundOutput); } -//------------------------------------------------------------ -bool ofSoundStream::setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers){ - if( soundStream ){ - return soundStream->setup(outChannels, inChannels, sampleRate, bufferSize, nBuffers); - } - return false; -} - //------------------------------------------------------------ void ofSoundStream::start(){ if( soundStream ){ @@ -161,7 +272,7 @@ void ofSoundStream::close(){ } //------------------------------------------------------------ -long unsigned long ofSoundStream::getTickCount() const{ +uint64_t ofSoundStream::getTickCount() const{ if( soundStream ){ return soundStream->getTickCount(); } @@ -200,17 +311,6 @@ int ofSoundStream::getBufferSize() const{ return 0; } -//------------------------------------------------------------ -ofSoundDevice::ofSoundDevice() -: name("Unknown") -, deviceID(0) -, inputChannels(0) -, outputChannels(0) -, isDefaultInput(false) -, isDefaultOutput(false) { - -} - //------------------------------------------------------------ vector ofSoundStream::getMatchingDevices(const std::string& name, unsigned int inChannels, unsigned int outChannels) const { vector devs = getDeviceList(); @@ -228,20 +328,3 @@ vector ofSoundStream::getMatchingDevices(const std::string& name, return hits; } - -//------------------------------------------------------------ -std::ostream& operator << (std::ostream& os, const ofSoundDevice& dev) { - os << "[" << dev.deviceID << "] " << dev.name; - os << " [in:" << dev.inputChannels << " out:" << dev.outputChannels << "]"; - if(dev.isDefaultInput) os << " (default in)"; - if(dev.isDefaultOutput) os << " (default out)"; - return os; -} - -//------------------------------------------------------------ -std::ostream& operator << (std::ostream& os, const std::vector& devs) { - for(std::size_t i = 0; i < devs.size(); i++) { - os << devs[i] << std::endl; - } - return os; -} diff --git a/libs/openFrameworks/sound/ofSoundStream.h b/libs/openFrameworks/sound/ofSoundStream.h index fd82cc59396..43259e216ee 100644 --- a/libs/openFrameworks/sound/ofSoundStream.h +++ b/libs/openFrameworks/sound/ofSoundStream.h @@ -7,50 +7,44 @@ #include "ofBaseSoundStream.h" #include -#ifdef OF_SOUNDSTREAM_RTAUDIO - #include "ofRtAudioSoundStream.h" - #define OF_SOUND_STREAM_TYPE ofRtAudioSoundStream -#elif defined(OF_SOUNDSTREAM_ANDROID) - #include "ofxAndroidSoundStream.h" - #define OF_SOUND_STREAM_TYPE ofxAndroidSoundStream -#elif defined(OF_SOUNDSTREAM_IOS) - #include "ofxiOSSoundStream.h" - #define OF_SOUND_STREAM_TYPE ofxiOSSoundStream -#elif defined(OF_SOUNDSTREAM_EMSCRIPTEN) - #include "ofxEmscriptenSoundStream.h" - #define OF_SOUND_STREAM_TYPE ofxEmscriptenSoundStream -#endif - - -/// \brief Sets up and starts a global ofSoundStream. -/// -/// This will set up a sound stream with a default sample rate of 44100, a -/// buffer size of 256 samples, and a queue of 4 buffers. -/// -/// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). -/// \param nInputChannels number of requested input channels. -/// \param appPtr pointer to the app which will own the sound stream (optional). -void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr = nullptr); - -/// \brief Sets up and starts a global ofSoundStream. -/// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). -/// \param nInputChannels number of requested input channels. -/// \param sampleRate requested sample rate (44100 is typical). -/// \param bufferSize requested buffer size (256 is typical). Smaller values -/// will be more responsive, but less stable. -/// \param nBuffers number of buffers to queue. Less buffers will be more responsive, but less stable. -void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, int sampleRate, int bufferSize, int nBuffers); - -/// \brief Sets up and starts a global ofSoundStream. -/// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). -/// \param nInputChannels number of requested input channels. -/// \param appPtr pointer to the app which will own the sound stream (optional). -/// \param sampleRate requested sample rate (44100 is typical). -/// \param bufferSize requested buffer size (256 is typical). Smaller values -/// will be more responsive, but less stable. -/// \param nBuffers number of buffers to queue. Less buffers will be more -/// responsive, but less stable. -void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr, int sampleRate, int bufferSize, int nBuffers); + +class ofSoundStreamSettings; + + +///// \brief Sets up and starts a global ofSoundStream. +///// +///// This will set up a sound stream with a default sample rate of 44100, a +///// buffer size of 256 samples, and a queue of 4 buffers. +///// +///// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). +///// \param nInputChannels number of requested input channels. +///// \param appPtr pointer to the app which will own the sound stream (optional). +OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr = nullptr)); + +///// \brief Sets up and starts a global ofSoundStream. +///// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). +///// \param nInputChannels number of requested input channels. +///// \param sampleRate requested sample rate (44100 is typical). +///// \param bufferSize requested buffer size (256 is typical). Smaller values +///// will be more responsive, but less stable. +///// \param nBuffers number of buffers to queue. Less buffers will be more responsive, but less stable. +OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, int sampleRate, int bufferSize, int nBuffers)); + +///// \brief Sets up and starts a global ofSoundStream. +///// \param nOutputChannels number of requested output channels (i.e. 2 for stereo). +///// \param nInputChannels number of requested input channels. +///// \param appPtr pointer to the app which will own the sound stream (optional). +///// \param sampleRate requested sample rate (44100 is typical). +///// \param bufferSize requested buffer size (256 is typical). Smaller values +///// will be more responsive, but less stable. +///// \param nBuffers number of buffers to queue. Less buffers will be more +///// responsive, but less stable. +OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + void ofSoundStreamSetup(int nOutputChannels, int nInputChannels, ofBaseApp * appPtr, int sampleRate, int bufferSize, int nBuffers)); + +void ofSoundStreamSetup(ofSoundStreamSettings & settings); /// \brief Stops the sound stream (audioIn() / audioOut() will stop being called) void ofSoundStreamStop(); @@ -88,72 +82,78 @@ std::vector ofSoundStreamListDevices(); /// /// \warning Be aware that audioIn() and audioOut() will be called on a different /// thread from your app's update() / draw() thread. -class ofSoundStream{ +class ofSoundStream { public: ofSoundStream(); - + void setSoundStream(shared_ptr soundStreamPtr); shared_ptr getSoundStream(); - + /// \brief Prints a list of available audio devices to the console void printDeviceList() const; - + /// \brief Retrieves a list of available audio devices - std::vector getDeviceList() const; - + std::vector getDeviceList(ofSoundDevice::Api api = ofSoundDevice::Api::DEFAULT) const; + /// \brief Get all devices which match the arguments (name can be a partial match) std::vector getMatchingDevices(const std::string& name, unsigned int inChannels = UINT_MAX, unsigned int outChannels = UINT_MAX) const; - + /// \brief sets the device represented by the stream, see ofSoundStream::getDeviceList(). - void setDeviceID(int deviceID); - + OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + void setDeviceID(int deviceID)); + /// \brief sets the device represented by the stream, see ofSoundStream::getDeviceList(). - void setDevice(const ofSoundDevice& device); - - /// \brief Sets up and starts the stream. - /// \param app pointer to the app which will own the sound stream. - /// \param outChannels number of requested output channels (i.e. 2 for stereo). - /// \param inChannels number of requested input channels. - /// \param sampleRate requested sample rate (44100 is typical). - /// \param bufferSize requested buffer size (256 is typical). Smaller - /// values will be more responsive, but less stable. - /// \param nBuffers number of buffers to queue. Less buffers will be more - /// responsive, but less stable. - /// \return true on success - bool setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); - - /// \brief Sets up and starts the stream. - /// \param outChannels number of requested output channels (i.e. 2 for stereo). - /// \param inChannels number of requested input channels. - /// \param sampleRate requested sample rate (44100 is typical). - /// \param bufferSize requested buffer size (256 is typical). Smaller values - /// will be more responsive, but less stable. - /// \param nBuffers number of buffers to queue. Less buffers will be more - /// responsive, but less stable. - /// \return true on success - bool setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers); - + OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + void setDevice(const ofSoundDevice& device)); + + bool setup(const ofSoundStreamSettings & settings); + + ///// \brief Sets up and starts the stream. + ///// \param app pointer to the app which will own the sound stream. + ///// \param outChannels number of requested output channels (i.e. 2 for stereo). + ///// \param inChannels number of requested input channels. + ///// \param sampleRate requested sample rate (44100 is typical). + ///// \param bufferSize requested buffer size (256 is typical). Smaller + ///// values will be more responsive, but less stable. + ///// \param nBuffers number of buffers to queue. Less buffers will be more + ///// responsive, but less stable. + ///// \return true on success + OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + bool setup(ofBaseApp * app, int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers)); + + ///// \brief Sets up and starts the stream. + ///// \param outChannels number of requested output channels (i.e. 2 for stereo). + ///// \param inChannels number of requested input channels. + ///// \param sampleRate requested sample rate (44100 is typical). + ///// \param bufferSize requested buffer size (256 is typical). Smaller values + ///// will be more responsive, but less stable. + ///// \param nBuffers number of buffers to queue. Less buffers will be more + ///// responsive, but less stable. + ///// \return true on success + OF_DEPRECATED_MSG("Use an ofSoundStreamSettings object instead of directly passing the parameters", + bool setup(int outChannels, int inChannels, int sampleRate, int bufferSize, int nBuffers)); + /// \brief Sets the object which will have audioIn() called when the device receives audio. void setInput(ofBaseSoundInput * soundInput); - + /// \brief Sets the object which will have audioIn() called when the device receives audio. void setInput(ofBaseSoundInput &soundInput); - + /// \brief Sets the object which will have audioOut() called when the device requests audio. void setOutput(ofBaseSoundOutput * soundOutput); - + /// \brief Sets the object which will have audioOut() called when the device requests audio. void setOutput(ofBaseSoundOutput &soundOutput); - + /// \brief Starts a stream (note that setup() will start the stream on its own). void start(); - + /// \brief Stops the stream. void stop(); - + /// \brief stops the stream and cleans up its resources. void close(); - + /// \brief Queries the number of "ticks" passed since the stream started. /// /// This is a representation of how many buffers have passed through the @@ -163,29 +163,64 @@ class ofSoundStream{ /// secondsOfPlayback = (tickCount * bufferSize) / sampleRate /// /// \return number of buffers passed through the stream since it started. - long unsigned long getTickCount() const; - + uint64_t getTickCount() const; + /// \brief Queries the stream's number of input channels. /// \return the number of input channels (e.g. 2 for stereo). int getNumInputChannels() const; - + /// \brief Queries the stream's number of output channels. /// \return the number of output channels (e.g. 2 for stereo). int getNumOutputChannels() const; - + /// \brief Queries the stream's sample rate /// \return the current sample rate of the stream /// \note The returned sample rate may differ from the requested sample rate. int getSampleRate() const; - + /// \brief Queries the stream's buffer size. /// \return the current buffer size of the stream. int getBufferSize() const; - + /// \brief Retrieves a list of available audio devices and prints device descriptions to the console OF_DEPRECATED_MSG("Use printDeviceList instead", std::vector listDevices() const); - + protected: shared_ptr soundStream; - + int tmpDeviceId = -1; + }; + +class ofSoundStreamSettings { +public: + virtual ~ofSoundStreamSettings() {} + int sampleRate = 44100; + int bufferSize = 256; + int numBuffers = 4; + int numInputChannels = 0; + int numOutputChannels = 0; + virtual bool setInDevice(const ofSoundDevice & device); + virtual bool setOutDevice(const ofSoundDevice & device); + virtual bool setApi(ofSoundDevice::Api api); + virtual const ofSoundDevice * getInDevice() const; + virtual const ofSoundDevice * getOutDevice() const; + virtual ofSoundDevice::Api getApi() const; + + template + void setInListener(Listener * inListener){ + inCallback = std::bind(static_cast(&Listener::audioIn), inListener, std::placeholders::_1); + } + + template + void setOutListener(Listener * outListener){ + outCallback = std::bind(static_cast(&Listener::audioOut), outListener, std::placeholders::_1); + } + + std::function inCallback; + std::function outCallback; +private: + ofSoundDevice inDevice; + ofSoundDevice outDevice; + ofSoundDevice::Api api = ofSoundDevice::Api::UNSPECIFIED; +}; + diff --git a/libs/openFrameworks/types/ofBaseTypes.h b/libs/openFrameworks/types/ofBaseTypes.h index 7f4c0699646..08f36e6ffde 100644 --- a/libs/openFrameworks/types/ofBaseTypes.h +++ b/libs/openFrameworks/types/ofBaseTypes.h @@ -72,7 +72,9 @@ class ofBaseDraws{ /// \param y Draw position on the y axis. /// \param w Draw width. /// \param h Draw height. - virtual void draw(float x, float y, float w, float h) const=0; + virtual void draw(float x, float y, float w, float h) const{ + draw(x, y, getWidth(), getHeight()); + } /// \brief Draw at a position at the native size. /// @@ -715,7 +717,7 @@ class ofBaseRenderer{ /// \param z The z-coordinate of the box's origin. /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. virtual void drawBox( float x, float y, float z, float width, float height, float depth) const; /// \brief Draws a cube with the specified size, starting from the specified coordinates. @@ -745,7 +747,7 @@ class ofBaseRenderer{ /// \param position an ofPoint which contains the (x,y,z) coordinates for the box's reference corner. /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. virtual void drawBox(const ofPoint& position, float width, float height, float depth) const; /// \brief Draws a cube with the specified size, starting from the specified position. @@ -776,7 +778,7 @@ class ofBaseRenderer{ /// /// \param width The width of the box. /// \param height The height of the box. - /// \param height The depth of the box. + /// \param depth The depth of the box. virtual void drawBox( float width, float height, float depth ) const; virtual void drawAxis(float size) const; @@ -791,7 +793,7 @@ class ofBaseGLRenderer: public ofBaseRenderer{ using ofBaseRenderer::draw; virtual void draw(const ofTexture & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const=0; virtual void draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const=0; - virtual void drawElements(const ofVbo & vbo, GLuint drawMode, int amt) const=0; + virtual void drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const=0; virtual void drawInstanced(const ofVbo & vbo, GLuint drawMode, int first, int total, int primCount) const=0; virtual void drawElementsInstanced(const ofVbo & vbo, GLuint drawMode, int amt, int primCount) const=0; virtual void draw(const ofVboMesh & mesh, ofPolyRenderMode renderType) const=0; diff --git a/libs/openFrameworks/types/ofColor.cpp b/libs/openFrameworks/types/ofColor.cpp index d9e7bc1063f..99aa319abbf 100644 --- a/libs/openFrameworks/types/ofColor.cpp +++ b/libs/openFrameworks/types/ofColor.cpp @@ -668,7 +668,7 @@ ofColor_ & ofColor_::operator /= (const float& val){ template -const PixelType & ofColor_::operator [] (int n) const{ +const PixelType & ofColor_::operator [] (std::size_t n) const{ switch( n ){ case 0: return r; @@ -685,7 +685,7 @@ const PixelType & ofColor_::operator [] (int n) const{ } template -PixelType & ofColor_::operator [] (int n){ +PixelType & ofColor_::operator [] (std::size_t n){ switch( n ){ case 0: return r; diff --git a/libs/openFrameworks/types/ofColor.h b/libs/openFrameworks/types/ofColor.h index 11aa6da61a6..e506f1b5d04 100644 --- a/libs/openFrameworks/types/ofColor.h +++ b/libs/openFrameworks/types/ofColor.h @@ -113,10 +113,7 @@ class ofColor_{ /// \param green The green component. /// \param blue The blue component. /// \param alpha The alpha component. - ofColor_(float red, - float green, - float blue, - float alpha = limit()); + ofColor_(float red, float green, float blue, float alpha = limit()); /// \brief Construct a grayscale ofColor_ by specifying a single number. /// @@ -526,8 +523,8 @@ class ofColor_{ /// /// \param hue A reference to the hue to fill. Will be in the range of /// 0 - limit(). - /// \param hue A reference to the saturation to fill. Will be in the range - /// of 0 - limit(). + /// \param saturation A reference to the saturation to fill. Will be in the + /// range of 0 - limit(). /// \param brightness A reference to the brightness to fill. Will be in the /// range of 0 - limit(). void getHsb(float& hue, float& saturation, float& brightness) const; @@ -538,7 +535,7 @@ class ofColor_{ /// ofShortColor), the maximum value different. For a ofFloatColor the /// maximum is `1.0`, but for a ofColor it's `255`. /// - /// Use this function to get this maximum number.. + /// Use this function to get this maximum number. /// /// \returns The value associated with a fully saturated color component. static float limit(); @@ -577,9 +574,9 @@ class ofColor_{ /// ofColor myColor(127, 127, 127, 255); /// ~~~~~ /// - /// \param val The grayscale value. + /// \param value The grayscale value. /// \returns A reference to itself. - ofColor_& operator = (const float& val); + ofColor_& operator = (const float& value); /// \brief Test two colors for equality. /// \returns true iff the R, G, B and A components are all equal. @@ -607,7 +604,7 @@ class ofColor_{ /// /// \param color The value to add. /// \returns The new clamped color. - ofColor_ operator + (const float& val) const; + ofColor_ operator + (const float& color) const; /// \brief Clamped addition operator. /// @@ -627,7 +624,7 @@ class ofColor_{ /// /// \param color The value to add. /// \returns A reference to itself, the new clamped color. - ofColor_& operator += (const float& val); + ofColor_& operator += (const float& color); /// \brief Clamped subtraction operator. /// @@ -646,9 +643,9 @@ class ofColor_{ /// /// \warning The alpha component is ignored. /// - /// \param color The value to subtract. + /// \param value The value to subtract. /// \returns The new clamped color. - ofColor_ operator - (const float& val) const; + ofColor_ operator - (const float& value) const; /// \brief Clamped subtraction operator. /// @@ -666,7 +663,7 @@ class ofColor_{ /// /// \param color The value to subtract. /// \returns A reference to itself, the new clamped color. - ofColor_& operator -= (const float& val); + ofColor_& operator -= (const float& color); /// \brief Clamped multiplication operator. /// @@ -685,9 +682,9 @@ class ofColor_{ /// /// \warning The alpha component is ignored. /// - /// \param color The value to multiply. + /// \param value The value to multiply. /// \returns The new clamped color. - ofColor_ operator * (const float& val) const; + ofColor_ operator * (const float& value) const; /// \brief Clamped multiplication operator. /// @@ -706,9 +703,9 @@ class ofColor_{ /// /// \warning The alpha component is ignored. /// - /// \param color The scaler value. + /// \param value The scaler value. /// \returns A reference to itself, the new clamped color. - ofColor_& operator *= (const float& val); + ofColor_& operator *= (const float& value); /// \brief Clamped division operator. /// @@ -726,9 +723,9 @@ class ofColor_{ /// /// \warning The alpha component is ignored. /// - /// \param val The divisor value. + /// \param value The divisor value. /// \returns The new clamped color. - ofColor_ operator / (const float& val) const; + ofColor_ operator / (const float& value) const; /// \brief Clamped division operator. /// @@ -744,9 +741,9 @@ class ofColor_{ /// /// \warning The alpha component is ignored. /// - /// \param valu The divisor value. + /// \param value The divisor value. /// \returns A reference to itself, the new clamped color. - ofColor_& operator /= (const float& val); + ofColor_& operator /= (const float& value); /// \brief Array subscript operator. /// @@ -760,7 +757,7 @@ class ofColor_{ /// /// \param n An index 0-3 of the component to get. /// \returns The value of the requested component. - const PixelType& operator [] (int n) const; + const PixelType& operator [] (std::size_t n) const; /// \brief Array subscript operator. /// @@ -774,7 +771,7 @@ class ofColor_{ /// /// \param n An index 0-3 of the component to get. /// \returns The value of the requested component. - PixelType& operator [] (int n); + PixelType& operator [] (std::size_t n); /// \brief An output stream operator. /// diff --git a/libs/openFrameworks/types/ofParameter.cpp b/libs/openFrameworks/types/ofParameter.cpp index d55e6ae3203..7eda0ee8cd8 100644 --- a/libs/openFrameworks/types/ofParameter.cpp +++ b/libs/openFrameworks/types/ofParameter.cpp @@ -63,3 +63,76 @@ istream& operator>>(istream& is, ofAbstractParameter& p){ p.fromString(str); return is; } + + + +ofParameter::ofParameter() +:obj(new Value){ + +} + +ofParameter::ofParameter(const string& name) +:obj(new Value(name)){ + +} + +void ofParameter::setName(const string & name){ + obj->name = name; +} + +string ofParameter::getName() const{ + return obj->name; +} + +std::string ofParameter::toString() const{ + return ""; +} + +void ofParameter::fromString(const std::string & name){ + +} + +ofParameter& ofParameter::set(const std::string & name){ + setName(name); + return *this; +} + +void ofParameter::trigger(){ + ofNotifyEvent(obj->changedE,this); +} + +void ofParameter::enableEvents(){ + obj->changedE.enable(); +} + +void ofParameter::disableEvents(){ + obj->changedE.disable(); +} + +bool ofParameter::isSerializable() const{ + return obj->serializable; +} + +bool ofParameter::isReadOnly() const{ + return false; +} + +void ofParameter::makeReferenceTo(ofParameter & mom){ + *this = mom; +} + +void ofParameter::setSerializable(bool serializable){ + obj->serializable = serializable; +} + +shared_ptr ofParameter::newReference() const{ + return std::make_shared>(*this); +} + +void ofParameter::setParent(ofParameterGroup & parent){ + obj->parents.emplace_back(parent.obj); +} + +size_t ofParameter::getNumListeners() const{ + return obj->changedE.size(); +} diff --git a/libs/openFrameworks/types/ofParameter.h b/libs/openFrameworks/types/ofParameter.h index f7ab1810006..aa3ebd47a41 100644 --- a/libs/openFrameworks/types/ofParameter.h +++ b/libs/openFrameworks/types/ofParameter.h @@ -20,7 +20,7 @@ class ofParameterGroup; /// Base class for ofParameter, ofReadOnlyParameter and ofParameterGroup class ofAbstractParameter{ public: - virtual ~ofAbstractParameter(){}; + virtual ~ofAbstractParameter(){} virtual string getName() const = 0; virtual void setName(const string & name) = 0; virtual string toString() const = 0; @@ -72,7 +72,7 @@ class ofParameterGroup: public ofAbstractParameter { template ofParameterGroup(const string & name, Args&... p) - :obj(new Value){ + :obj(std::make_shared()){ add(p...); setName(name); } @@ -88,51 +88,91 @@ class ofParameterGroup: public ofAbstractParameter { void clear(); - ofParameter getBool(const string& name) const; - ofParameter getInt(const string& name) const; - ofParameter getFloat(const string& name) const; - ofParameter getChar(const string& name) const; - ofParameter getString(const string& name) const; - ofParameter getPoint(const string& name) const; - ofParameter getVec2f(const string& name) const; - ofParameter getVec3f(const string& name) const; - ofParameter getVec4f(const string& name) const; - ofParameter getColor(const string& name) const; - ofParameter getShortColor(const string& name) const; - ofParameter getFloatColor(const string& name) const; - - ofParameterGroup getGroup(string name) const; - - - ofParameter getBool(int pos) const; - ofParameter getInt(int pos) const; - ofParameter getFloat(int pos) const; - ofParameter getChar(int pos) const; - ofParameter getString(int pos) const; - ofParameter getPoint(int pos) const; - ofParameter getVec2f(int pos) const; - ofParameter getVec3f(int pos) const; - ofParameter getVec4f(int pos) const; - ofParameter getColor(int pose) const; - ofParameter getShortColor(int pos) const; - ofParameter getFloatColor(int pos) const; - ofParameterGroup getGroup(int pos) const; - - ofAbstractParameter & get(const string& name) const; - ofAbstractParameter & get(int pos) const; - - ofAbstractParameter & operator[](const string& name) const; - ofAbstractParameter & operator[](int pos) const; + const ofParameter & getBool(const string& name) const; + const ofParameter & getInt(const string& name) const; + const ofParameter & getFloat(const string& name) const; + const ofParameter & getChar(const string& name) const; + const ofParameter & getString(const string& name) const; + const ofParameter & getPoint(const string& name) const; + const ofParameter & getVec2f(const string& name) const; + const ofParameter & getVec3f(const string& name) const; + const ofParameter & getVec4f(const string& name) const; + const ofParameter & getColor(const string& name) const; + const ofParameter & getShortColor(const string& name) const; + const ofParameter & getFloatColor(const string& name) const; + const ofParameterGroup & getGroup(const string& name) const; + + + const ofParameter & getBool(std::size_t pos) const; + const ofParameter & getInt(std::size_t pos) const; + const ofParameter & getFloat(std::size_t pos) const; + const ofParameter & getChar(std::size_t pos) const; + const ofParameter & getString(std::size_t pos) const; + const ofParameter & getPoint(std::size_t pos) const; + const ofParameter & getVec2f(std::size_t pos) const; + const ofParameter & getVec3f(std::size_t pos) const; + const ofParameter & getVec4f(std::size_t pos) const; + const ofParameter & getColor(std::size_t pose) const; + const ofParameter & getShortColor(std::size_t pos) const; + const ofParameter & getFloatColor(std::size_t pos) const; + const ofParameterGroup & getGroup(std::size_t pos) const; + + ofParameter & getBool(const string& name); + ofParameter & getInt(const string& name); + ofParameter & getFloat(const string& name); + ofParameter & getChar(const string& name); + ofParameter & getString(const string& name); + ofParameter & getPoint(const string& name); + ofParameter & getVec2f(const string& name); + ofParameter & getVec3f(const string& name); + ofParameter & getVec4f(const string& name); + ofParameter & getColor(const string& name); + ofParameter & getShortColor(const string& name); + ofParameter & getFloatColor(const string& name); + ofParameterGroup & getGroup(const string& name); + + + ofParameter & getBool(std::size_t pos); + ofParameter & getInt(std::size_t pos); + ofParameter & getFloat(std::size_t pos); + ofParameter & getChar(std::size_t pos); + ofParameter & getString(std::size_t pos); + ofParameter & getPoint(std::size_t pos); + ofParameter & getVec2f(std::size_t pos); + ofParameter & getVec3f(std::size_t pos); + ofParameter & getVec4f(std::size_t pos); + ofParameter & getColor(std::size_t pose); + ofParameter & getShortColor(std::size_t pos); + ofParameter & getFloatColor(std::size_t pos); + ofParameterGroup & getGroup(std::size_t pos); + + const ofAbstractParameter & get(const string& name) const; + const ofAbstractParameter & get(std::size_t pos) const; + + const ofAbstractParameter & operator[](const string& name) const; + const ofAbstractParameter & operator[](std::size_t pos) const; + + ofAbstractParameter & get(const string& name); + ofAbstractParameter & get(std::size_t pos); + + ofAbstractParameter & operator[](const string& name); + ofAbstractParameter & operator[](std::size_t pos); template - ofParameter get(const string& name) const; + const ofParameter & get(const string& name) const; template - ofParameter get(int pos) const; + const ofParameter & get(std::size_t pos) const; - int size() const; - string getName(int position) const; - string getType(int position) const; + template + ofParameter & get(const string& name); + + template + ofParameter & get(std::size_t pos); + + std::size_t size() const; + string getName(std::size_t position) const; + string getType(std::size_t position) const; bool getIsReadOnly(int position) const; int getPosition(const string& name) const; @@ -144,7 +184,7 @@ class ofParameterGroup: public ofAbstractParameter { string toString() const; void fromString(const string& name); - bool contains(const string& name); + bool contains(const string& name) const; ofAbstractParameter & back(); ofAbstractParameter & front(); @@ -179,7 +219,7 @@ class ofParameterGroup: public ofAbstractParameter { void notifyParameterChanged(ofAbstractParameter & param); - map parametersIndex; + map parametersIndex; vector > parameters; string name; bool serializable; @@ -200,12 +240,22 @@ class ofParameterGroup: public ofAbstractParameter { }; template -ofParameter ofParameterGroup::get(const string& name) const{ +const ofParameter & ofParameterGroup::get(const string& name) const{ + return static_cast& >(get(name)); +} + +template +const ofParameter & ofParameterGroup::get(std::size_t pos) const{ + return static_cast& >(get(pos)); +} + +template +ofParameter & ofParameterGroup::get(const string& name){ return static_cast& >(get(name)); } template -ofParameter ofParameterGroup::get(int pos) const{ +ofParameter & ofParameterGroup::get(std::size_t pos){ return static_cast& >(get(pos)); } @@ -228,6 +278,18 @@ namespace priv{ static T max() { return std::numeric_limits::max(); } }; + template<> + struct TypeInfo_ { + static float min() { return 0; } + static float max() { return 1; } + }; + + template<> + struct TypeInfo_ { + static float min() { return 0; } + static float max() { return 1; } + }; + // Types without numeric_limits resolve to this template specialization: template struct TypeInfo_ { @@ -242,45 +304,104 @@ namespace priv{ // Here we provide some of our own specializations: template<> struct TypeInfo { - static ofVec2f min() { return ofVec2f(std::numeric_limits::lowest()); }; - static ofVec2f max() { return ofVec3f(std::numeric_limits::max()); }; + static ofVec2f min() { return ofVec2f(0); } + static ofVec2f max() { return ofVec2f(1); } }; template<> struct TypeInfo { - static ofVec3f min() { return ofVec3f(std::numeric_limits::lowest()); }; - static ofVec3f max() { return ofVec3f(std::numeric_limits::max()); }; + static ofVec3f min() { return ofVec3f(0); } + static ofVec3f max() { return ofVec3f(1); } }; template<> struct TypeInfo { - static ofVec4f min() { return ofVec4f(std::numeric_limits::lowest()); }; - static ofVec4f max() { return ofVec4f(std::numeric_limits::max()); }; + static ofVec4f min() { return ofVec4f(0); } + static ofVec4f max() { return ofVec4f(1); } }; template struct TypeInfo > { - static ofColor_ min() { return ofColor_(0,0); }; - static ofColor_ max() { return ofColor_(ofColor_::limit(),ofColor_::limit()); }; + static ofColor_ min() { return ofColor_(0,0); } + static ofColor_ max() { return ofColor_(ofColor_::limit(),ofColor_::limit()); } }; + + + // detection of stream operators + typedef char yes; + typedef char (&no)[2]; + + struct anyx { template anyx(const T &); }; + + no operator << (const anyx &, const anyx &); + no operator >> (const anyx &, const anyx &); + + + template yes check(T const&); + no check(no); + + template + struct has_loading_support { + static istream & stream; + static T & x; + static const bool value = sizeof(check(stream >> x)) == sizeof(yes); + }; + + template + struct has_saving_support { + static ostream & stream; + static T & x; + static const bool value = sizeof(check(stream << x)) == sizeof(yes); + }; + + template + struct has_stream_operators { + static const bool can_load = has_loading_support::value; + static const bool can_save = has_saving_support::value; + static const bool value = can_load && can_save; + }; + + template + typename std::enable_if::value, std::string>::type toStringImpl(const ParameterType & value){ + return ofToString(value); + } + + template + typename std::enable_if::value, std::string>::type toStringImpl(const ParameterType &){ + throw std::exception(); + } + + template + typename std::enable_if::value, ParameterType>::type fromStringImpl(const std::string & str){ + return ofFromString(str); + } + + template + typename std::enable_if::value, ParameterType>::type fromStringImpl(const std::string &){ + throw std::exception(); + + } } } /*! \endcond */ - - -//---------------------------------------------------------------------- -/// Holds a value and notify it's listeners when it changes. Can be used as -/// the value itself. For example an ofParameter can be added, multiplied -/// substracted... with another number. -/// for ofParameter of other objects it's methods can be access using pointer -/// syntax -> +/// \brief ofParameter holds a value and notifies its listeners when it changes. +/// +/// ofParameter can be used as the value itself. For example an `ofParameter` +/// can be added, multiplied, substracted, etc with another number. +/// +/// For an ofParameter with a custom object such as `ofParameter myObject`, +/// `MyObject`'s methods can be accessed using pointer syntax, +/// e.g. `myObject->myMethod();`. +/// +/// \tparam ParameterType The data wrapped by the ofParameter. template class ofParameter: public ofAbstractParameter{ public: ofParameter(); + ofParameter(const ofParameter & v); ofParameter(const ParameterType & v); ofParameter(const string& name, const ParameterType & v); ofParameter(const string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max); @@ -296,7 +417,9 @@ class ofParameter: public ofAbstractParameter{ ParameterType getMax() const; - string toString() const; + + std::string toString() const; + void fromString(const std::string & name); template void addListener(ListenerClass * listener, ListenerMethod method, int prio=OF_EVENT_ORDER_AFTER_APP){ @@ -308,12 +431,17 @@ class ofParameter: public ofAbstractParameter{ ofRemoveListener(obj->changedE,listener,method,prio); } + template + ofEventListener newListener(Args...args) { + return obj->changedE.newListener(args...); + } + void enableEvents(); void disableEvents(); bool isSerializable() const; bool isReadOnly() const; - void makeReferenceTo(ofParameter mom); + void makeReferenceTo(ofParameter & mom); ofParameter & operator=(const ofParameter & v); const ParameterType & operator=(const ParameterType & v); @@ -350,11 +478,11 @@ class ofParameter: public ofAbstractParameter{ ofParameter & set(const string& name, const ParameterType & v); ofParameter & set(const string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max); + ofParameter & setWithoutEventNotifications(const ParameterType & v); + void setMin(const ParameterType & min); void setMax(const ParameterType & max); - void fromString(const string & name); - void setSerializable(bool serializable); shared_ptr newReference() const; @@ -368,29 +496,32 @@ class ofParameter: public ofAbstractParameter{ return shared_ptr(nullptr); } } + + size_t getNumListeners() const; + private: class Value{ public: Value() :min(of::priv::TypeInfo::min()) - ,max(of::priv::TypeInfo::min()) + ,max(of::priv::TypeInfo::max()) ,bInNotify(false) - ,serializable(true){}; + ,serializable(true){} Value(ParameterType v) :value(v) ,min(of::priv::TypeInfo::min()) - ,max(of::priv::TypeInfo::min()) + ,max(of::priv::TypeInfo::max()) ,bInNotify(false) - ,serializable(true){}; + ,serializable(true){} Value(string name, ParameterType v) :name(name) ,value(v) ,min(of::priv::TypeInfo::min()) - ,max(of::priv::TypeInfo::min()) + ,max(of::priv::TypeInfo::max()) ,bInNotify(false) - ,serializable(true){}; + ,serializable(true){} Value(string name, ParameterType v, ParameterType min, ParameterType max) :name(name) @@ -398,7 +529,7 @@ class ofParameter: public ofAbstractParameter{ ,min(min) ,max(max) ,bInNotify(false) - ,serializable(true){}; + ,serializable(true){} string name; ParameterType value; @@ -418,23 +549,28 @@ class ofParameter: public ofAbstractParameter{ template ofParameter::ofParameter() -:obj(new Value) -,setMethod(std::bind(&ofParameter::eventsSetValue,this, std::placeholders::_1)){} +:obj(std::make_shared()) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)){} + +template +ofParameter::ofParameter(const ofParameter & v) +:obj(v.obj) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)) {} template ofParameter::ofParameter(const ParameterType & v) -:obj(shared_ptr(new Value(v))) -,setMethod(std::bind(&ofParameter::eventsSetValue,this, std::placeholders::_1)) {} +:obj(std::make_shared(v)) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)) {} template ofParameter::ofParameter(const string& name, const ParameterType & v) -:obj(shared_ptr(new Value(name, v))) -,setMethod(std::bind(&ofParameter::eventsSetValue,this, std::placeholders::_1)){} +:obj(std::make_shared(name, v)) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)){} template ofParameter::ofParameter(const string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max) -:obj(shared_ptr(new Value(name, v, min, max))) -,setMethod(std::bind(&ofParameter::eventsSetValue,this, std::placeholders::_1)){} +:obj(std::make_shared(name, v, min, max)) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)){} template @@ -471,6 +607,12 @@ ofParameter & ofParameter::set(const string& name, return *this; } +template +inline ofParameter & ofParameter::setWithoutEventNotifications(const ParameterType & v){ + noEventsSetValue(v); + return *this; +} + template inline const ParameterType & ofParameter::get() const{ return obj->value; @@ -482,21 +624,58 @@ inline const ParameterType * ofParameter::operator->() const{ template inline void ofParameter::eventsSetValue(const ParameterType & v){ - if(obj->bInNotify) { + + // If the object is notifying its parents, just set the value without triggering an event. + if(obj->bInNotify) + { noEventsSetValue(v); - return; } - obj->bInNotify = true; - obj->value = v; - ofNotifyEvent(obj->changedE,obj->value,this); - if(!obj->parents.empty()){ - obj->parents.erase(std::remove_if(obj->parents.begin(),obj->parents.end(),[this](weak_ptr p){ - auto parent = p.lock(); - if(parent) parent->notifyParameterChanged(*this); - return !parent; - }),obj->parents.end()); - } - obj->bInNotify = false; + else + { + // Mark the object as in its notification loop. + obj->bInNotify = true; + + // Set the value. + obj->value = v; + + // Notify any local subscribers. + ofNotifyEvent(obj->changedE,obj->value,this); + + // Notify all parents, if there are any. + if(!obj->parents.empty()) + { + + // This lambda will conditionally notify a parent if its child + // value has changed. + // + // If it was successful (i.e. the parent pointer is valid) the + // lambda will return false. If it was unsuccessful (i.e. the + // parent pointer is invalid) the lambda will return true. + // + // This return value is used by the std::remove_if algorithm + // to erase invalid parents from this object's parent list. + auto notifyParents = [this](weak_ptr p){ + // Try to get a valid shared pointer ot the parent. + auto parent = p.lock(); + + // If the parent's shared pointer is not nullptr, notify it. + if(parent != nullptr) { + parent->notifyParameterChanged(*this); + return false; + } else { + return true; + } + }; + + // Erase each invalid parent and notify all valid parents of this + // object's changed value. + obj->parents.erase(std::remove_if(obj->parents.begin(), + obj->parents.end(), + notifyParents), + obj->parents.end()); + } + obj->bInNotify = false; + } } template @@ -512,7 +691,7 @@ void ofParameter::setSerializable(bool serializable){ template bool ofParameter::isSerializable() const{ - return obj->serializable; + return of::priv::has_stream_operators::value && obj->serializable; } template @@ -556,29 +735,36 @@ string ofParameter::getName() const{ } template -string ofParameter::toString() const{ - return ofToString(obj->value); +inline std::string ofParameter::toString() const{ + try{ + return of::priv::toStringImpl(obj->value); + }catch(...){ + ofLogError("ofParameter") << "Trying to serialize non-serializable parameter"; + return ""; + } } - template -void ofParameter::fromString(const string & str){ - set(ofFromString(str)); +inline void ofParameter::fromString(const std::string & str){ + try{ + set(of::priv::fromStringImpl(str)); + }catch(...){ + ofLogError("ofParameter") << "Trying to de-serialize non-serializable parameter"; + } } - template void ofParameter::enableEvents(){ - setMethod = std::bind(&ofParameter::eventsSetValue,this, std::placeholders::_1); + setMethod = std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1); } template void ofParameter::disableEvents(){ - setMethod = std::bind(&ofParameter::noEventsSetValue,this, std::placeholders::_1); + setMethod = std::bind(&ofParameter::noEventsSetValue, this, std::placeholders::_1); } template -inline ParameterType ofParameter::operator++(int v){ +inline ParameterType ofParameter::operator++(int){ ParameterType r = obj->value; obj->value++; set(obj->value); @@ -593,7 +779,7 @@ inline ofParameter & ofParameter::operator++(){ } template -inline ParameterType ofParameter::operator--(int v){ +inline ParameterType ofParameter::operator--(int){ ParameterType r = obj->value; obj->value--; set(obj->value); @@ -688,13 +874,13 @@ inline ofParameter & ofParameter::operator>>=(cons } template -void ofParameter::makeReferenceTo(ofParameter mom){ +void ofParameter::makeReferenceTo(ofParameter & mom){ obj = mom.obj; } template shared_ptr ofParameter::newReference() const{ - return shared_ptr(new ofParameter(*this)); + return std::make_shared>(*this); } template @@ -702,19 +888,94 @@ void ofParameter::setParent(ofParameterGroup & parent){ obj->parents.emplace_back(parent.obj); } +template +size_t ofParameter::getNumListeners() const{ + return obj->changedE.size(); +} +template<> +class ofParameter: public ofAbstractParameter{ +public: + ofParameter(); + ofParameter(const std::string& name); + ofParameter& set(const std::string & name); + void setName(const std::string & name); + std::string getName() const; + std::string toString() const; + void fromString(const std::string & name); -//---------------------------------------------------------------------- -/// Same as ofParameter but can only be modified by a friend class specified -/// as the second template argument + template + void addListener(ListenerClass * listener, ListenerMethod method, int prio=OF_EVENT_ORDER_AFTER_APP){ + ofAddListener(obj->changedE,listener,method,prio); + } + + template + void removeListener(ListenerClass * listener, ListenerMethod method, int prio=OF_EVENT_ORDER_AFTER_APP){ + ofRemoveListener(obj->changedE,listener,method,prio); + } + + void trigger(); + + void enableEvents(); + void disableEvents(); + bool isSerializable() const; + bool isReadOnly() const; + + void makeReferenceTo(ofParameter & mom); + + void setSerializable(bool serializable); + shared_ptr newReference() const; + + void setParent(ofParameterGroup & _parent); + + const ofParameterGroup getFirstParent() const{ + auto first = std::find_if(obj->parents.begin(),obj->parents.end(),[](weak_ptr p){return p.lock()!=nullptr;}); + if(first!=obj->parents.end()){ + return first->lock(); + }else{ + return shared_ptr(nullptr); + } + } + size_t getNumListeners() const; +private: + class Value{ + public: + Value() + :serializable(false){} + + Value(string name) + :name(name) + ,serializable(false){} + + string name; + ofEvent changedE; + bool serializable; + vector> parents; + }; + shared_ptr obj; +}; + + + +/// \brief ofReadOnlyParameter holds a value and notifies its listeners when it changes. +/// +/// ofReadOnlyParameter is a "read only" version of `ofPareameter`. "Friend" +/// classes specified in the template arguments allow other classes +/// write-access to the internal data. Otherwise, all other access is +/// "read only". +/// +/// \sa ofParameter +/// \tparam ParameterType The data wrapped by the ofParameter. +/// \tparam Friend The type of the "friend" class with write access. template class ofReadOnlyParameter: public ofAbstractParameter{ public: ofReadOnlyParameter(); ofReadOnlyParameter(ofParameter & p); + ofReadOnlyParameter(ofReadOnlyParameter & p); ofReadOnlyParameter(const ParameterType & v); ofReadOnlyParameter(const string& name, const ParameterType & v); ofReadOnlyParameter(const string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max); @@ -813,6 +1074,10 @@ template inline ofReadOnlyParameter::ofReadOnlyParameter(ofParameter & p) :parameter(p){} +template +inline ofReadOnlyParameter::ofReadOnlyParameter(ofReadOnlyParameter & p) +:parameter(p){} + template inline ofReadOnlyParameter::ofReadOnlyParameter(const ParameterType & v) :parameter(v){} @@ -940,7 +1205,7 @@ inline const ParameterType & ofReadOnlyParameter::operator template -inline ParameterType ofReadOnlyParameter::operator++(int v){ +inline ParameterType ofReadOnlyParameter::operator++(int){ return parameter++; } @@ -951,7 +1216,7 @@ inline ofReadOnlyParameter & ofReadOnlyParameter -inline ParameterType ofReadOnlyParameter::operator--(int v){ +inline ParameterType ofReadOnlyParameter::operator--(int){ return parameter--; } @@ -1070,7 +1335,7 @@ inline void ofReadOnlyParameter::fromString(const string & template shared_ptr ofReadOnlyParameter::newReference() const{ - return shared_ptr(new ofReadOnlyParameter(*this)); + return std::make_shared>(*this); } template diff --git a/libs/openFrameworks/types/ofParameterGroup.cpp b/libs/openFrameworks/types/ofParameterGroup.cpp index 29e708146e2..19d09ca80d2 100644 --- a/libs/openFrameworks/types/ofParameterGroup.cpp +++ b/libs/openFrameworks/types/ofParameterGroup.cpp @@ -2,7 +2,7 @@ #include "ofParameter.h" ofParameterGroup::ofParameterGroup() -:obj(new Value) +:obj(std::make_shared()) { } @@ -19,126 +19,238 @@ void ofParameterGroup::clear(){ obj->parametersIndex.clear(); } -ofParameter ofParameterGroup::getBool(const string& name) const { +const ofParameter & ofParameterGroup::getBool(const string& name) const { return get(name); } -ofParameter ofParameterGroup::getInt(const string& name) const{ +const ofParameter & ofParameterGroup::getInt(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getFloat(const string& name) const{ +const ofParameter & ofParameterGroup::getFloat(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getChar(const string& name) const{ +const ofParameter & ofParameterGroup::getChar(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getString(const string& name) const{ +const ofParameter & ofParameterGroup::getString(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getPoint(const string& name) const{ +const ofParameter & ofParameterGroup::getPoint(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getVec2f(const string& name) const{ +const ofParameter & ofParameterGroup::getVec2f(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getVec3f(const string& name) const{ +const ofParameter & ofParameterGroup::getVec3f(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getVec4f(const string& name) const{ +const ofParameter & ofParameterGroup::getVec4f(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getColor(const string& name) const{ +const ofParameter & ofParameterGroup::getColor(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getShortColor(const string& name) const{ +const ofParameter & ofParameterGroup::getShortColor(const string& name) const{ return get(name); } -ofParameter ofParameterGroup::getFloatColor(const string& name) const{ +const ofParameter & ofParameterGroup::getFloatColor(const string& name) const{ return get(name); } -ofParameterGroup ofParameterGroup::getGroup(string name) const{ +const ofParameterGroup & ofParameterGroup::getGroup(const string& name) const{ + return static_cast(get(name)); +} + +const ofParameter & ofParameterGroup::getBool(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getInt(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getFloat(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getChar(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getString(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getPoint(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getVec2f(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getVec3f(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getVec4f(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getColor(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getShortColor(std::size_t pos) const{ + return get(pos); +} + +const ofParameter & ofParameterGroup::getFloatColor(std::size_t pos) const{ + return get(pos); +} + + +const ofParameterGroup & ofParameterGroup::getGroup(std::size_t pos) const{ + if(pos>=size()){ + throw std::out_of_range(("get(): " + ofToString(pos) + "out of bounds").c_str()); + }else{ + if(getType(pos)==typeid(ofParameterGroup).name()){ + return *static_cast(obj->parameters[pos].get()); + }else{ + throw std::runtime_error(("get(): bad type for pos " + ofToString(pos) + ", returning empty group").c_str()); + } + } +} + +ofParameter & ofParameterGroup::getBool(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getInt(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getFloat(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getChar(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getString(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getPoint(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getVec2f(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getVec3f(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getVec4f(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getColor(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getShortColor(const string& name){ + return get(name); +} + +ofParameter & ofParameterGroup::getFloatColor(const string& name){ + return get(name); +} + +ofParameterGroup & ofParameterGroup::getGroup(const string& name){ return static_cast(get(name)); } -ofParameter ofParameterGroup::getBool(int pos) const{ +ofParameter & ofParameterGroup::getBool(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getInt(int pos) const{ +ofParameter & ofParameterGroup::getInt(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getFloat(int pos) const{ +ofParameter & ofParameterGroup::getFloat(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getChar(int pos) const{ +ofParameter & ofParameterGroup::getChar(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getString(int pos) const{ +ofParameter & ofParameterGroup::getString(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getPoint(int pos) const{ +ofParameter & ofParameterGroup::getPoint(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getVec2f(int pos) const{ +ofParameter & ofParameterGroup::getVec2f(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getVec3f(int pos) const{ +ofParameter & ofParameterGroup::getVec3f(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getVec4f(int pos) const{ +ofParameter & ofParameterGroup::getVec4f(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getColor(int pos) const{ +ofParameter & ofParameterGroup::getColor(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getShortColor(int pos) const{ +ofParameter & ofParameterGroup::getShortColor(std::size_t pos){ return get(pos); } -ofParameter ofParameterGroup::getFloatColor(int pos) const{ +ofParameter & ofParameterGroup::getFloatColor(std::size_t pos){ return get(pos); } -ofParameterGroup ofParameterGroup::getGroup(int pos) const{ +ofParameterGroup & ofParameterGroup::getGroup(std::size_t pos){ if(pos>=size()){ - return ofParameterGroup(); + throw std::out_of_range(("get(): " + ofToString(pos) + "out of bounds").c_str()); }else{ if(getType(pos)==typeid(ofParameterGroup).name()){ return *static_cast(obj->parameters[pos].get()); }else{ - ofLogError("ofParameterGroup") << "get(): bad type for pos " << pos << ", returning empty group"; - return ofParameterGroup(); + throw std::runtime_error(("get(): bad type for pos " + ofToString(pos) + ", returning empty group").c_str()); } } } -int ofParameterGroup::size() const{ +std::size_t ofParameterGroup::size() const{ return obj->parameters.size(); } -string ofParameterGroup::getName(int position) const{ +string ofParameterGroup::getName(std::size_t position) const{ if(position>=size()){ return ""; }else{ @@ -146,7 +258,7 @@ string ofParameterGroup::getName(int position) const{ } } -string ofParameterGroup::getType(int position) const{ +string ofParameterGroup::getType(std::size_t position) const{ if(position>=size()) return ""; else return obj->parameters[position]->type(); } @@ -189,28 +301,47 @@ void ofParameterGroup::fromString(const string & name){ } -ofAbstractParameter & ofParameterGroup::get(const string& name) const{ - map::const_iterator it = obj->parametersIndex.find(escape(name)); - int index = it->second; +const ofAbstractParameter & ofParameterGroup::get(const string& name) const{ + map::const_iterator it = obj->parametersIndex.find(escape(name)); + std::size_t index = it->second; + return get(index); +} + +const ofAbstractParameter & ofParameterGroup::get(std::size_t pos) const{ + return *obj->parameters[pos]; +} + + +const ofAbstractParameter & ofParameterGroup::operator[](const string& name) const{ + return get(name); +} + +const ofAbstractParameter & ofParameterGroup::operator[](std::size_t pos) const{ + return get(pos); +} + +ofAbstractParameter & ofParameterGroup::get(const string& name){ + map::const_iterator it = obj->parametersIndex.find(escape(name)); + std::size_t index = it->second; return get(index); } -ofAbstractParameter & ofParameterGroup::get(int pos) const{ +ofAbstractParameter & ofParameterGroup::get(std::size_t pos){ return *obj->parameters[pos]; } -ofAbstractParameter & ofParameterGroup::operator[](const string& name) const{ +ofAbstractParameter & ofParameterGroup::operator[](const string& name){ return get(name); } -ofAbstractParameter & ofParameterGroup::operator[](int pos) const{ +ofAbstractParameter & ofParameterGroup::operator[](std::size_t pos){ return get(pos); } ostream& operator<<(ostream& os, const ofParameterGroup& group) { std::streamsize width = os.width(); - for(int i=0;iparametersIndex.find(escape(name))!=obj->parametersIndex.end(); } @@ -278,7 +409,7 @@ bool ofParameterGroup::isReadOnly() const{ } shared_ptr ofParameterGroup::newReference() const{ - return shared_ptr(new ofParameterGroup(*this)); + return std::make_shared(*this); } void ofParameterGroup::setParent(ofParameterGroup & parent){ diff --git a/libs/openFrameworks/types/ofParameterGroup.h b/libs/openFrameworks/types/ofParameterGroup.h index c093d21dad9..a3354e03567 100644 --- a/libs/openFrameworks/types/ofParameterGroup.h +++ b/libs/openFrameworks/types/ofParameterGroup.h @@ -8,4 +8,6 @@ #ifndef OFXPARAMETERGROUP_H_ #define OFXPARAMETERGROUP_H_ +#include "ofParameter.h" + #endif /* OFXPARAMETERGROUP_H_ */ diff --git a/libs/openFrameworks/types/ofRectangle.h b/libs/openFrameworks/types/ofRectangle.h index 02288d209c9..c6acb7b664c 100644 --- a/libs/openFrameworks/types/ofRectangle.h +++ b/libs/openFrameworks/types/ofRectangle.h @@ -481,7 +481,7 @@ class ofRectangle{ /// rectangles. /// /// \param targetRect The target rectangle to align this rectangle to. - /// \param thisHorzAnchor The common edge of the rectangles to align. + /// \param sharedAnchor The common edge of the rectangles to align. void alignToHorz(const ofRectangle& targetRect, ofAlignHorz sharedAnchor = OF_ALIGN_HORZ_CENTER); diff --git a/libs/openFrameworks/utils/ofConstants.h b/libs/openFrameworks/utils/ofConstants.h index 0e9887bfe88..01d7fe7c951 100644 --- a/libs/openFrameworks/utils/ofConstants.h +++ b/libs/openFrameworks/utils/ofConstants.h @@ -4,7 +4,7 @@ //------------------------------- #define OF_VERSION_MAJOR 0 #define OF_VERSION_MINOR 9 -#define OF_VERSION_PATCH 0 +#define OF_VERSION_PATCH 1 #define OF_VERSION_PRE_RELEASE "master" //------------------------------- @@ -17,7 +17,7 @@ enum ofLoopType{ enum ofTargetPlatform{ OF_TARGET_OSX, - OF_TARGET_WINGCC, + OF_TARGET_MINGW, OF_TARGET_WINVS, OF_TARGET_IOS, OF_TARGET_ANDROID, @@ -35,7 +35,7 @@ enum ofTargetPlatform{ // Cross-platform deprecation warning #ifdef __GNUC__ // clang also has this defined. deprecated(message) is only for gcc>=4.5 - #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 5) + #if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || __GNUC__ > 4 #define OF_DEPRECATED_MSG(message, func) func __attribute__ ((deprecated(message))) #else #define OF_DEPRECATED_MSG(message, func) func __attribute__ ((deprecated)) @@ -94,14 +94,18 @@ enum ofTargetPlatform{ // then the the platform specific includes: #ifdef TARGET_WIN32 - #define GLEW_STATIC + #define GLEW_NO_GLU #include "GL/glew.h" #include "GL/wglew.h" #include "glu.h" #define __WINDOWS_DS__ #define __WINDOWS_MM__ #if (_MSC_VER) // microsoft visual studio + //TODO: Fix this in the code instead of disabling the warnings + #define _CRT_SECURE_NO_WARNINGS + #define _WINSOCK_DEPRECATED_NO_WARNINGS + #include #include #pragma warning(disable : 4068) // unknown pragmas @@ -157,39 +161,40 @@ enum ofTargetPlatform{ #ifdef TARGET_LINUX - #define GL_GLEXT_PROTOTYPES - #include + #include + + #ifdef TARGET_LINUX_ARM + #ifdef TARGET_RASPBERRY_PI + #include "bcm_host.h" + #endif - #ifdef TARGET_LINUX_ARM - #ifdef TARGET_RASPBERRY_PI - #include "bcm_host.h" - #endif - #include "GLES/gl.h" - #include "GLES/glext.h" + #include "GLES/glext.h" #include "GLES2/gl2.h" #include "GLES2/gl2ext.h" - + #define EGL_EGLEXT_PROTOTYPES #include "EGL/egl.h" #include "EGL/eglext.h" - #else // normal linux - #include - #include - #include - #endif + #else // normal linux + #define GL_GLEXT_PROTOTYPES + #include + #include + #include + #include + #endif - // for some reason, this isn't defined at compile time, - // so this hack let's us work - // for 99% of the linux folks that are on intel - // everyone one else will have RGB / BGR issues. + // for some reason, this isn't defined at compile time, + // so this hack let's us work + // for 99% of the linux folks that are on intel + // everyone one else will have RGB / BGR issues. //#if defined(__LITTLE_ENDIAN__) - #define TARGET_LITTLE_ENDIAN // intel cpu + #define TARGET_LITTLE_ENDIAN // intel cpu //#endif - // some things for serial compilation: - #define B14400 14400 - #define B28800 28800 + // some things for serial compilation: + #define B14400 14400 + #define B28800 28800 #endif @@ -294,7 +299,7 @@ typedef TESSindex ofIndexType; #define OF_VIDEO_PLAYER_ANDROID #elif defined(TARGET_OF_IOS) #define OF_VIDEO_PLAYER_IOS - #elif defined(TARGET_WIN32) && !defined(__MINGW32__) + #elif defined(TARGET_WIN32) #define OF_VIDEO_PLAYER_DIRECTSHOW #elif defined(TARGET_OSX) //for 10.8 and 10.9 users we use AVFoundation, for 10.7 we use QTKit, for 10.6 users we use QuickTime @@ -348,12 +353,14 @@ typedef TESSindex ofIndexType; #endif //------------------------------------------------ thread local storage -// xcode has a bug where it won't support tls on some versions even +// clang has a bug where it won't support tls on some versions even // on c++11, this is a workaround that bug -#if !defined(TARGET_OSX) && !defined(TARGET_OF_IOS) - #define HAS_TLS 1 -#elif __clang__ - #if __has_feature(cxx_thread_local) +#ifndef HAS_TLS + #if __clang__ + #if __has_feature(cxx_thread_local) && !defined(__MINGW64__) && !defined(__MINGW32__) + #define HAS_TLS 1 + #endif + #elif !defined(TARGET_WIN32) || _MSC_VER #define HAS_TLS 1 #endif #endif @@ -387,6 +394,11 @@ typedef ofBaseApp ofSimpleApp; #include #include +#include "json.hpp" + +// for convenience +using ofJson = nlohmann::json; + using namespace std; #ifndef PI @@ -703,6 +715,8 @@ enum ofPixelFormat{ OF_PIXELS_UV, OF_PIXELS_VU, + OF_PIXELS_NUM_FORMATS, + OF_PIXELS_UNKNOWN=-1, OF_PIXELS_NATIVE=-2 }; diff --git a/libs/openFrameworks/utils/ofFileUtils.cpp b/libs/openFrameworks/utils/ofFileUtils.cpp index fe733d1f127..3877f7f4b71 100644 --- a/libs/openFrameworks/utils/ofFileUtils.cpp +++ b/libs/openFrameworks/utils/ofFileUtils.cpp @@ -19,37 +19,31 @@ //------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------ - -size_t ofBuffer::ioSize = 1024; - //-------------------------------------------------- ofBuffer::ofBuffer() :currentLine(end(),end()){ - buffer.resize(1); } //-------------------------------------------------- ofBuffer::ofBuffer(const char * _buffer, std::size_t size) :buffer(_buffer,_buffer+size) ,currentLine(end(),end()){ - buffer.resize(buffer.size()+1,0); } //-------------------------------------------------- ofBuffer::ofBuffer(const string & text) :buffer(text.begin(),text.end()) ,currentLine(end(),end()){ - buffer.resize(buffer.size()+1,0); } //-------------------------------------------------- -ofBuffer::ofBuffer(istream & stream) +ofBuffer::ofBuffer(istream & stream, size_t ioBlockSize) :currentLine(end(),end()){ - set(stream); + set(stream, ioBlockSize); } //-------------------------------------------------- -bool ofBuffer::set(istream & stream){ +bool ofBuffer::set(istream & stream, size_t ioBlockSize){ if(stream.bad()){ clear(); return false; @@ -57,33 +51,36 @@ bool ofBuffer::set(istream & stream){ buffer.clear(); } - vector aux_buffer(ioSize); + vector aux_buffer(ioBlockSize); while(stream.good()){ - stream.read(&aux_buffer[0], ioSize); - buffer.insert(buffer.end(),aux_buffer.begin(),aux_buffer.begin()+stream.gcount()); + stream.read(&aux_buffer[0], ioBlockSize); + append(aux_buffer.data(), stream.gcount()); } - buffer.push_back(0); return true; } +//-------------------------------------------------- +void ofBuffer::setall(char mem){ + buffer.assign(buffer.size(), mem); +} + //-------------------------------------------------- bool ofBuffer::writeTo(ostream & stream) const { if(stream.bad()){ return false; } - stream.write(&(buffer[0]), buffer.size() - 1); - return true; + stream.write(buffer.data(), buffer.size()); + return stream.good(); } //-------------------------------------------------- void ofBuffer::set(const char * _buffer, std::size_t _size){ - buffer.assign(_buffer,_buffer+_size); - buffer.resize(buffer.size()+1,0); + buffer.assign(_buffer, _buffer+_size); } //-------------------------------------------------- void ofBuffer::set(const string & text){ - set(text.c_str(),text.size()); + set(text.c_str(), text.size()); } //-------------------------------------------------- @@ -93,45 +90,47 @@ void ofBuffer::append(const string& _buffer){ //-------------------------------------------------- void ofBuffer::append(const char * _buffer, std::size_t _size){ - buffer.insert(buffer.end()-1,_buffer,_buffer+_size); - buffer.back() = 0; + buffer.insert(buffer.end(), _buffer, _buffer + _size); +} + +//-------------------------------------------------- +void ofBuffer::reserve(size_t size){ + buffer.reserve(size); } //-------------------------------------------------- void ofBuffer::clear(){ - buffer.resize(1,0); + buffer.clear(); } //-------------------------------------------------- void ofBuffer::allocate(std::size_t _size){ - clear(); - //we always add a 0 at the end to avoid problems with strings - buffer.resize(_size + 1, 0); + resize(_size); } +//-------------------------------------------------- +void ofBuffer::resize(std::size_t _size){ + buffer.resize(_size); +} + + //-------------------------------------------------- char * ofBuffer::getData(){ - if(buffer.empty()){ - return nullptr; - } - return &buffer[0]; + return buffer.data(); } //-------------------------------------------------- const char * ofBuffer::getData() const{ - if(buffer.empty()){ - return nullptr; - } - return &buffer[0]; + return buffer.data(); } //-------------------------------------------------- -char *ofBuffer::getBinaryBuffer(){ +char * ofBuffer::getBinaryBuffer(){ return getData(); } //-------------------------------------------------- -const char *ofBuffer::getBinaryBuffer() const { +const char * ofBuffer::getBinaryBuffer() const { return getData(); } @@ -140,7 +139,7 @@ string ofBuffer::getText() const { if(buffer.empty()){ return ""; } - return &buffer[0]; + return std::string(buffer.begin(), buffer.end()); } //-------------------------------------------------- @@ -155,17 +154,8 @@ ofBuffer & ofBuffer::operator=(const string & text){ } //-------------------------------------------------- -long ofBuffer::size() const { - if(buffer.empty()){ - return 0; - } - //we always add a 0 at the end to avoid problems with strings - return buffer.size() - 1; -} - -//-------------------------------------------------- -void ofBuffer::setIOBufferSize(size_t _ioSize){ - ioSize = _ioSize; +std::size_t ofBuffer::size() const { + return buffer.size(); } //-------------------------------------------------- @@ -308,9 +298,9 @@ bool ofBuffer::Line::empty() const{ } //-------------------------------------------------- -ofBuffer::Lines::Lines(vector & buffer) -:_begin(buffer.begin()) -,_end(buffer.end()){} +ofBuffer::Lines::Lines(vector::iterator begin, vector::iterator end) +:_begin(begin) +,_end(end){} //-------------------------------------------------- ofBuffer::Line ofBuffer::Lines::begin(){ @@ -324,7 +314,7 @@ ofBuffer::Line ofBuffer::Lines::end(){ //-------------------------------------------------- ofBuffer::Lines ofBuffer::getLines(){ - return ofBuffer::Lines(buffer); + return ofBuffer::Lines(begin(), end()); } //-------------------------------------------------- @@ -341,20 +331,14 @@ istream & operator>>(istream & istr, ofBuffer & buf){ //-------------------------------------------------- ofBuffer ofBufferFromFile(const string & path, bool binary){ - ios_base::openmode mode = binary ? ifstream::binary : ios_base::in; - ifstream istr(ofToDataPath(path, true).c_str(), mode); - ofBuffer buffer(istr); - istr.close(); - return buffer; + ofFile f(path,ofFile::ReadOnly, binary); + return ofBuffer(f); } //-------------------------------------------------- bool ofBufferToFile(const string & path, ofBuffer & buffer, bool binary){ - ios_base::openmode mode = binary ? ofstream::binary : ios_base::out; - ofstream ostr(ofToDataPath(path, true).c_str(), mode); - bool ret = buffer.writeTo(ostr); - ostr.close(); - return ret; + ofFile f(path, ofFile::WriteOnly, binary); + return buffer.writeTo(f); } //------------------------------------------------------------------------------------------------------------ @@ -382,7 +366,9 @@ ofFile::~ofFile(){ //------------------------------------------------------------------------------------------------------------- ofFile::ofFile(const ofFile & mom) -:mode(Reference) +:basic_ios() +,fstream() +,mode(Reference) ,binary(true){ copyFrom(mom); } @@ -484,9 +470,11 @@ bool ofFile::create(){ bool success = false; if(!myFile.string().empty()){ - auto mode = this->mode; - success = open(path(),ofFile::WriteOnly); - open(path(),mode); + auto oldmode = this->mode; + auto oldpath = path(); + success = open(path(),ofFile::WriteOnly,binary); + close(); + open(oldpath,oldmode,binary); } return success; @@ -651,9 +639,10 @@ bool ofFile::isDevice() const { //------------------------------------------------------------------------------------------------------------ bool ofFile::isHidden() const { -#ifdef TARGET_WINDOWS +#ifdef TARGET_WIN32 + return false; #else - return myFile.filename().string()[0] == '.'; + return myFile.filename() != "." && myFile.filename() != ".." && myFile.filename().string()[0] == '.'; #endif } @@ -687,18 +676,18 @@ void ofFile::setExecutable(bool flag){ } //------------------------------------------------------------------------------------------------------------ -bool ofFile::copyTo(const string& _path, bool bRelativeToData, bool overwrite){ +bool ofFile::copyTo(const string& _path, bool bRelativeToData, bool overwrite) const{ std::string path = _path; if(isDirectory()){ return ofDirectory(myFile).copyTo(path,bRelativeToData,overwrite); } if(path.empty()){ - ofLogError("ofFile") << "copyTo(): destination path is empty"; + ofLogError("ofFile") << "copyTo(): destination path " << _path << " is empty"; return false; } if(!exists()){ - ofLogError("ofFile") << "copyTo(): source file does not exist"; + ofLogError("ofFile") << "copyTo(): source file " << this->path() << " does not exist"; return false; } @@ -706,7 +695,7 @@ bool ofFile::copyTo(const string& _path, bool bRelativeToData, bool overwrite){ path = ofToDataPath(path); } if(ofFile::doesFileExist(path, bRelativeToData)){ - if(isFile() && ofFile(path).isDirectory()){ + if(isFile() && ofFile(path,ofFile::Reference).isDirectory()){ path = ofFilePath::join(path,getFileName()); } if(ofFile::doesFileExist(path, bRelativeToData)){ @@ -722,7 +711,7 @@ bool ofFile::copyTo(const string& _path, bool bRelativeToData, bool overwrite){ if(!ofDirectory(ofFilePath::getEnclosingDirectory(path,bRelativeToData)).exists()){ ofFilePath::createEnclosingDirectory(path, bRelativeToData); } - std::filesystem::copy(myFile,path); + std::filesystem::copy_file(myFile,path); }catch(std::exception & except){ ofLogError("ofFile") << "copyTo(): unable to copy \"" << path << "\":" << except.what(); return false; @@ -748,7 +737,7 @@ bool ofFile::moveTo(const string& _path, bool bRelativeToData, bool overwrite){ path = ofToDataPath(path); } if(ofFile::doesFileExist(path, bRelativeToData)){ - if(isFile() && ofFile(path).isDirectory()){ + if(isFile() && ofFile(path,ofFile::Reference).isDirectory()){ path = ofFilePath::join(path,getFileName()); } if(ofFile::doesFileExist(path, bRelativeToData)){ @@ -761,11 +750,18 @@ bool ofFile::moveTo(const string& _path, bool bRelativeToData, bool overwrite){ } try{ + auto mode = this->mode; + if(mode != ofFile::Reference){ + changeMode(ofFile::Reference, binary); + } if(!ofDirectory(ofFilePath::getEnclosingDirectory(path,bRelativeToData)).exists()){ ofFilePath::createEnclosingDirectory(path, bRelativeToData); } std::filesystem::rename(myFile,path); myFile = path; + if(mode != ofFile::Reference){ + changeMode(mode, binary); + } } catch(std::exception & except){ ofLogError("ofFile") << "moveTo(): unable to move \"" << path << "\":" << except.what(); @@ -792,6 +788,9 @@ bool ofFile::remove(bool recursive){ } try{ + if(mode!=Reference){ + open(path(),Reference,binary); + } if(recursive){ std::filesystem::remove_all(myFile); }else{ @@ -850,13 +849,13 @@ bool ofFile::operator>=(const ofFile & file) const { //------------------------------------------------------------------------------------------------------------ bool ofFile::copyFromTo(const std::string& pathSrc, const std::string& pathDst, bool bRelativeToData, bool overwrite){ - return ofFile(pathSrc).copyTo(pathDst,bRelativeToData,overwrite); + return ofFile(pathSrc,ofFile::Reference).copyTo(pathDst,bRelativeToData,overwrite); } //be careful with slashes here - appending a slash when moving a folder will causes mad headaches //------------------------------------------------------------------------------------------------------------ bool ofFile::moveFromTo(const std::string& pathSrc, const std::string& pathDst, bool bRelativeToData, bool overwrite){ - return ofFile(pathSrc).moveTo(pathDst, bRelativeToData, overwrite); + return ofFile(pathSrc,ofFile::Reference).moveTo(pathDst, bRelativeToData, overwrite); } //------------------------------------------------------------------------------------------------------------ @@ -865,7 +864,7 @@ bool ofFile::doesFileExist(const std::string& _fPath, bool bRelativeToData){ if(bRelativeToData){ fPath = ofToDataPath(fPath); } - ofFile file(fPath); + ofFile file(fPath,ofFile::Reference); return !fPath.empty() && file.exists(); } @@ -875,7 +874,7 @@ bool ofFile::removeFile(const std::string& _path, bool bRelativeToData){ if(bRelativeToData){ path = ofToDataPath(path); } - return ofFile(path).remove(); + return ofFile(path,ofFile::Reference).remove(); } @@ -900,7 +899,7 @@ ofDirectory::ofDirectory(const std::filesystem::path & path){ void ofDirectory::open(const std::filesystem::path & path){ originalDirectory = ofFilePath::getPathForDirectory(path.string()); files.clear(); - myDir = std::filesystem::path(ofToDataPath(originalDirectory)); + myDir = std::filesystem::path(ofToDataPath(originalDirectory)); } //------------------------------------------------------------------------------------------------------------ @@ -914,9 +913,9 @@ bool ofDirectory::create(bool recursive){ if(!myDir.string().empty()){ try{ if(recursive){ - std::filesystem::create_directories(myDir); + std::filesystem::create_directories(myDir); }else{ - std::filesystem::create_directory(myDir); + std::filesystem::create_directory(myDir); } } catch(std::exception & except){ @@ -940,7 +939,11 @@ string ofDirectory::path() const { //------------------------------------------------------------------------------------------------------------ string ofDirectory::getAbsolutePath() const { - return std::filesystem::absolute(myDir).string(); + try{ + return std::filesystem::canonical(std::filesystem::absolute(myDir)).string(); + }catch(...){ + return std::filesystem::absolute(myDir).string(); + } } //------------------------------------------------------------------------------------------------------------ @@ -1030,7 +1033,7 @@ bool ofDirectory::copyTo(const std::string& _path, bool bRelativeToData, bool ov return false; } }else{ - ofFile(file->path()).copyTo(dst.string(),false); + ofFile(file->path(),ofFile::Reference).copyTo(dst.string(),false); } } @@ -1059,9 +1062,9 @@ bool ofDirectory::remove(bool recursive){ try{ if(recursive){ - std::filesystem::remove_all(myDir); + std::filesystem::remove_all(std::filesystem::canonical(myDir)); }else{ - std::filesystem::remove(myDir); + std::filesystem::remove(std::filesystem::canonical(myDir)); } }catch(std::exception & except){ ofLogError("ofDirectory") << "remove(): unable to remove file/directory: " << except.what(); @@ -1097,10 +1100,6 @@ std::size_t ofDirectory::listDir(){ return 0; } - // File::list(vector) is broken on windows as of march 23, 2011... - // so we need to use File::list(vector) and build a vector - // in the future the following can be replaced width: cur.list(files); - vectorfileStrings; std::filesystem::directory_iterator end_iter; if ( std::filesystem::exists(myDir) && std::filesystem::is_directory(myDir)){ for( std::filesystem::directory_iterator dir_iter(myDir) ; dir_iter != end_iter ; ++dir_iter){ @@ -1117,11 +1116,12 @@ std::size_t ofDirectory::listDir(){ }); } + if(!extensions.empty() && !ofContains(extensions, (string)"*")){ ofRemove(files, [&](ofFile & file){ return std::find(extensions.begin(), extensions.end(), ofToLower(file.getExtension())) == extensions.end(); }); - } + } if(ofGetLogLevel() == OF_LOG_VERBOSE){ for(int i = 0; i < (int)size(); i++){ @@ -1161,7 +1161,7 @@ ofFile ofDirectory::operator[](std::size_t position) const { //------------------------------------------------------------------------------------------------------------ const vector & ofDirectory::getFiles() const{ - if(files.empty()){ + if(files.empty() && !myDir.empty()){ const_cast(this)->listDir(); } return files; @@ -1190,9 +1190,20 @@ static bool natural(const ofFile& a, const ofFile& b) { //------------------------------------------------------------------------------------------------------------ void ofDirectory::sort(){ + if(files.empty() && !myDir.empty()){ + listDir(); + } ofSort(files, natural); } +//------------------------------------------------------------------------------------------------------------ +ofDirectory ofDirectory::getSorted(){ + ofDirectory sorted(*this); + sorted.listDir(); + sorted.sort(); + return sorted; +} + //------------------------------------------------------------------------------------------------------------ std::size_t ofDirectory::size() const{ return files.size(); @@ -1214,36 +1225,49 @@ bool ofDirectory::removeDirectory(const std::string& _path, bool deleteIfNotEmpt if(bRelativeToData){ path = ofToDataPath(path); } - return ofFile(path).remove(deleteIfNotEmpty); + return ofFile(path,ofFile::Reference).remove(deleteIfNotEmpty); } //------------------------------------------------------------------------------------------------------------ bool ofDirectory::createDirectory(const std::string& _dirPath, bool bRelativeToData, bool recursive){ + std::string dirPath = _dirPath; if(bRelativeToData){ dirPath = ofToDataPath(dirPath); } - - bool success = false; - try{ - if(!recursive){ - success = std::filesystem::create_directory(dirPath); - }else{ - success = std::filesystem::create_directories(dirPath); + + + // on OSX,std::filesystem::create_directories seems to return false *if* the path has folders that already exist + // and true if it doesn't + // so to avoid unnecessary warnings on OSX, we check if it exists here: + + bool bDoesExistAlready = ofDirectory::doesDirectoryExist(dirPath); + + if (!bDoesExistAlready){ + + bool success = false; + try{ + if(!recursive){ + success = std::filesystem::create_directory(dirPath); + }else{ + success = std::filesystem::create_directories(dirPath); + } + } catch(std::exception & except){ + ofLogError("ofDirectory") << "createDirectory(): couldn't create directory \"" << dirPath << "\": " << except.what(); + return false; } - } - catch(std::exception & except){ - ofLogError("ofDirectory") << "createDirectory(): couldn't create directory \"" << dirPath << "\": " << except.what(); - return false; + return success; + + } else { + + // no need to create it - it already exists. + return true; } - if(!success){ - ofLogWarning("ofDirectory") << "createDirectory(): directory already exists: \"" << dirPath << "\""; - success = true; - } - return success; + + } //------------------------------------------------------------------------------------------------------------ @@ -1252,7 +1276,7 @@ bool ofDirectory::doesDirectoryExist(const std::string& _dirPath, bool bRelative if(bRelativeToData){ dirPath = ofToDataPath(dirPath); } - return std::filesystem::exists(dirPath); + return std::filesystem::exists(dirPath) && std::filesystem::is_directory(dirPath); } //------------------------------------------------------------------------------------------------------------ @@ -1269,32 +1293,32 @@ bool ofDirectory::isDirectoryEmpty(const std::string& _dirPath, bool bRelativeTo } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator==(const ofDirectory & dir){ +bool ofDirectory::operator==(const ofDirectory & dir) const{ return getAbsolutePath() == dir.getAbsolutePath(); } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator!=(const ofDirectory & dir){ +bool ofDirectory::operator!=(const ofDirectory & dir) const{ return getAbsolutePath() != dir.getAbsolutePath(); } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator<(const ofDirectory & dir){ +bool ofDirectory::operator<(const ofDirectory & dir) const{ return getAbsolutePath() < dir.getAbsolutePath(); } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator<=(const ofDirectory & dir){ +bool ofDirectory::operator<=(const ofDirectory & dir) const{ return getAbsolutePath() <= dir.getAbsolutePath(); } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator>(const ofDirectory & dir){ +bool ofDirectory::operator>(const ofDirectory & dir) const{ return getAbsolutePath() > dir.getAbsolutePath(); } //------------------------------------------------------------------------------------------------------------ -bool ofDirectory::operator>=(const ofDirectory & dir){ +bool ofDirectory::operator>=(const ofDirectory & dir) const{ return getAbsolutePath() >= dir.getAbsolutePath(); } @@ -1399,7 +1423,7 @@ string ofFilePath::getFileName(const std::string& _filePath, bool bRelativeToDat //------------------------------------------------------------------------------------------------------------ string ofFilePath::getBaseName(const std::string& filePath){ - return ofFile(filePath).getBaseName(); + return ofFile(filePath,ofFile::Reference).getBaseName(); } //------------------------------------------------------------------------------------------------------------ @@ -1417,15 +1441,15 @@ bool ofFilePath::createEnclosingDirectory(const std::string& filePath, bool bRel } //------------------------------------------------------------------------------------------------------------ -string ofFilePath::getAbsolutePath(const std::string& _path, bool bRelativeToData){ - std::string path = _path; +string ofFilePath::getAbsolutePath(const std::string& path, bool bRelativeToData){ if(bRelativeToData){ - path = ofToDataPath(path); - } - try{ - return std::filesystem::canonical(path).string(); - }catch(...){ - return path; + return ofToDataPath(path, true); + }else{ + try{ + return std::filesystem::canonical(std::filesystem::absolute(path)).string(); + }catch(...){ + return std::filesystem::absolute(path).string(); + } } } @@ -1437,20 +1461,7 @@ bool ofFilePath::isAbsolute(const std::string& path){ //------------------------------------------------------------------------------------------------------------ string ofFilePath::getCurrentWorkingDirectory(){ - #ifdef TARGET_OSX - char pathOSX[FILENAME_MAX]; - uint32_t size = sizeof(pathOSX); - if(_NSGetExecutablePath(pathOSX, &size) != 0){ - ofLogError("ofFilePath") << "getCurrentWorkingDirectory(): path buffer too small, need size " << size; - } - string pathOSXStr = string(pathOSX); - string pathWithoutApp; - size_t found = pathOSXStr.find_last_of("/"); - pathWithoutApp = pathOSXStr.substr(0, found); - return pathWithoutApp; - #else - return std::filesystem::current_path().string(); - #endif + return std::filesystem::current_path().string(); } //------------------------------------------------------------------------------------------------------------ @@ -1500,7 +1511,7 @@ string ofFilePath::getUserHomeDir(){ // getenv will return any Environent Variable on Windows // USERPROFILE is the key on Windows 7 but it might be HOME // in other flavours of windows...need to check XP and NT... - return string(getenv("USERPROFILE")); + return ofGetEnv("USERPROFILE"); #elif !defined(TARGET_EMSCRIPTEN) struct passwd * pw = getpwuid(getuid()); return pw->pw_dir; @@ -1508,3 +1519,26 @@ string ofFilePath::getUserHomeDir(){ return ""; #endif } + +string ofFilePath::makeRelative(const std::string & from, const std::string & to){ + auto pathFrom = std::filesystem::absolute( from ); + auto pathTo = std::filesystem::absolute( to ); + std::filesystem::path ret; + std::filesystem::path::const_iterator itrFrom( pathFrom.begin() ), itrTo( pathTo.begin() ); + // Find common base + for( std::filesystem::path::const_iterator toEnd( pathTo.end() ), fromEnd( pathFrom.end() ) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo ); + // Navigate backwards in directory to reach previously found base + for( std::filesystem::path::const_iterator fromEnd( pathFrom.end() ); itrFrom != fromEnd; ++itrFrom ){ + if( (*itrFrom) != "." ){ + ret /= ".."; + } + } + // Now navigate down the directory branch + for( ; itrTo != pathTo.end() ; ++itrTo ){ + if( itrTo->string() != "."){ + ret /= *itrTo; + } + } + + return ret.string(); +} diff --git a/libs/openFrameworks/utils/ofFileUtils.h b/libs/openFrameworks/utils/ofFileUtils.h index 0de46331daa..f63b040495e 100644 --- a/libs/openFrameworks/utils/ofFileUtils.h +++ b/libs/openFrameworks/utils/ofFileUtils.h @@ -1,19 +1,15 @@ #pragma once #include "ofConstants.h" -#if _MSC_VER -//#define BOOST_NO_CXX11_SCOPED_ENUMS -#include -namespace std { - namespace filesystem = boost::filesystem; -} -#else +#if !_MSC_VER #define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SCOPED_ENUMS +#endif #include -namespace std{ +namespace std { namespace filesystem = boost::filesystem; } -#endif + //---------------------------------------------------------- // ofBuffer //---------------------------------------------------------- @@ -24,19 +20,22 @@ class ofBuffer{ ofBuffer(); ofBuffer(const char * buffer, std::size_t size); ofBuffer(const string & text); - ofBuffer(istream & stream); + ofBuffer(istream & stream, size_t ioBlockSize = 1024); void set(const char * _buffer, std::size_t _size); - void set(const string & text); - bool set(istream & stream); + void set(const string & text); + bool set(istream & stream, size_t ioBlockSize = 1024); + void setall(char mem); void append(const string& _buffer); void append(const char * _buffer, std::size_t _size); + void reserve(size_t size); bool writeTo(ostream & stream) const; void clear(); void allocate(std::size_t _size); + void resize(std::size_t _size); char * getData(); const char * getData() const; @@ -47,8 +46,7 @@ class ofBuffer{ operator string() const; // cast to string, to use a buffer as a string ofBuffer & operator=(const string & text); - long size() const; - static void setIOBufferSize(size_t ioSize); + std::size_t size() const; OF_DEPRECATED_MSG("use a lines iterator instead",string getNextLine()); OF_DEPRECATED_MSG("use a lines iterator instead",string getFirstLine()); @@ -84,7 +82,7 @@ class ofBuffer{ }; struct Lines{ - Lines(vector & buffer); + Lines(vector::iterator begin, vector::iterator end); Line begin(); Line end(); @@ -97,7 +95,6 @@ class ofBuffer{ private: vector buffer; Line currentLine; - static size_t ioSize; }; //-------------------------------------------------- @@ -133,6 +130,8 @@ class ofFilePath{ static string getCurrentExeDir(); static string getUserHomeDir(); + + static string makeRelative(const std::string & from, const std::string & to); }; class ofFile: public fstream{ @@ -182,7 +181,7 @@ class ofFile: public fstream{ void setExecutable(bool executable=true); //these all work for files and directories - bool copyTo(const std::string& path, bool bRelativeToData = true, bool overwrite = false); + bool copyTo(const std::string& path, bool bRelativeToData = true, bool overwrite = false) const; bool moveTo(const std::string& path, bool bRelativeToData = true, bool overwrite = false); bool renameTo(const std::string& path, bool bRelativeToData = true, bool overwrite = false); @@ -223,6 +222,10 @@ class ofFile: public fstream{ operator std::filesystem::path(){ return myFile; } + + operator const std::filesystem::path() const{ + return myFile; + } //------- @@ -297,23 +300,28 @@ class ofDirectory{ void reset(); //equivalent to close, just here for bw compatibility with ofxDirList void sort(); + ofDirectory getSorted(); std::size_t size() const; OF_DEPRECATED_MSG("Use size() instead.", int numFiles()); //this allows to compare dirs by their paths, also provides sorting and use as key in stl containers - bool operator==(const ofDirectory & dir); - bool operator!=(const ofDirectory & dir); - bool operator<(const ofDirectory & dir); - bool operator<=(const ofDirectory & dir); - bool operator>(const ofDirectory & dir); - bool operator>=(const ofDirectory & dir); + bool operator==(const ofDirectory & dir) const; + bool operator!=(const ofDirectory & dir) const; + bool operator<(const ofDirectory & dir) const; + bool operator<=(const ofDirectory & dir) const; + bool operator>(const ofDirectory & dir) const; + bool operator>=(const ofDirectory & dir) const; operator std::filesystem::path(){ return myDir; } + operator const std::filesystem::path() const{ + return myDir; + } + //------- //static helpers //------- diff --git a/libs/openFrameworks/utils/ofLog.h b/libs/openFrameworks/utils/ofLog.h index dc103adf412..7d0f0d0f62d 100644 --- a/libs/openFrameworks/utils/ofLog.h +++ b/libs/openFrameworks/utils/ofLog.h @@ -438,7 +438,7 @@ class ofLog{ /// This allows the class to use the << std::ostream to catch function /// pointers such as std::endl and std::hex. /// - /// \param A function pointer that takes a std::ostream as an argument. + /// \param func A function pointer that takes a std::ostream as an argument. /// \returns A reference to itself. ofLog& operator<<(std::ostream& (*func)(std::ostream&)){ func(message); diff --git a/libs/openFrameworks/utils/ofSystemUtils.cpp b/libs/openFrameworks/utils/ofSystemUtils.cpp index 507d282bee2..ffb81fd7981 100644 --- a/libs/openFrameworks/utils/ofSystemUtils.cpp +++ b/libs/openFrameworks/utils/ofSystemUtils.cpp @@ -374,27 +374,23 @@ ofFileDialogResult ofSystemLoadDialog(string windowTitle, bool bFolderSelection, ofn.lStructSize = sizeof(ofn); HWND hwnd = WindowFromDC(wglGetCurrentDC()); ofn.hwndOwner = hwnd; -#ifdef __MINGW32__ - char szFileName[MAX_PATH]; - memset(szFileName,0,260); - if(defaultPath!=""){ - strcpy(szFileName,ofToDataPath(defaultPath).c_str()); - } - ofn.lpstrFilter = "All\0"; - ofn.lpstrFile = szFileName; -#else // Visual Studio + //the file name and path wchar_t szFileName[MAX_PATH]; + memset(szFileName, 0, sizeof(szFileName)); + + //the dir, if specified + wchar_t szDir[MAX_PATH]; + + //the title if specified wchar_t szTitle[MAX_PATH]; if(defaultPath!=""){ - wcscpy_s(szFileName,convertNarrowToWide(ofToDataPath(defaultPath)).c_str()); - }else{ - //szFileName = L""; - memset(szFileName, 0, sizeof(szFileName)); + wcscpy(szDir,convertNarrowToWide(ofToDataPath(defaultPath)).c_str()); + ofn.lpstrInitialDir = szDir; } if (windowTitle != "") { - wcscpy_s(szTitle, convertNarrowToWide(windowTitle).c_str()); + wcscpy(szTitle, convertNarrowToWide(windowTitle).c_str()); ofn.lpstrTitle = szTitle; } else { ofn.lpstrTitle = nullptr; @@ -402,24 +398,17 @@ ofFileDialogResult ofSystemLoadDialog(string windowTitle, bool bFolderSelection, ofn.lpstrFilter = L"All\0"; ofn.lpstrFile = szFileName; -#endif ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = 0; - -#ifdef __MINGW32__ - ofn.lpstrTitle = windowTitle.c_str(); -#else ofn.lpstrTitle = windowTitleW.c_str(); -#endif if(GetOpenFileName(&ofn)) { -#ifdef __MINGW32__ - results.filePath = string(szFileName); -#else results.filePath = convertWideToNarrow(szFileName); -#endif - + } + else { + //this should throw an error on failure unless its just the user canceling out + DWORD err = CommDlgExtendedError(); } } else { @@ -630,9 +619,6 @@ string ofSystemTextBoxDialog(string question, string text){ WNDCLASSEX wc; MSG Msg; - //we have to do this because mingw wants non wide strings and vs wants wide strings - #ifdef _MSC_VER - #define TMP_STR_CONVERT LPCWSTR const LPCWSTR g_szClassName = L"myWindowClass\0"; @@ -753,131 +739,6 @@ string ofSystemTextBoxDialog(string question, string text){ DestroyWindow(dialog); EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - #else - - const LPCSTR g_szClassName = "myWindowClass\0"; - - //Step 1: Registering the Window Class - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle(0); - wc.lpszClassName = g_szClassName; - wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wc.lpszMenuName = nullptr; - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); - wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION); - if(!RegisterClassEx(&wc)) - { - - DWORD err=GetLastError(); - if ((err==ERROR_CLASS_ALREADY_EXISTS)){ - ; // we are ok - // http://stackoverflow.com/questions/5791996/re-registering-user-defined-window-class-c - } else { - MessageBox(nullptr, "Window Registration Failed!\0", "Error!\0", - MB_ICONEXCLAMATION | MB_OK); - return text; - } - - - } - - HWND dialog = CreateWindowEx(WS_EX_DLGMODALFRAME, - g_szClassName, - question.c_str(), - WS_POPUP | WS_CAPTION | DS_MODALFRAME | WS_SYSMENU, - CW_USEDEFAULT, CW_USEDEFAULT, 240, 140, - WindowFromDC(wglGetCurrentDC()), nullptr, GetModuleHandle(0),nullptr); - - if(dialog == nullptr) - { - MessageBox(nullptr, "Window Creation Failed!\0", "Error!\0", - MB_ICONEXCLAMATION | MB_OK); - return text; - } - - EnableWindow(WindowFromDC(wglGetCurrentDC()), FALSE); - HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT\0", text.c_str(), - WS_CHILD | WS_VISIBLE | WS_TABSTOP, - 10, 10, 210, 40, dialog, (HMENU)101, GetModuleHandle(nullptr), nullptr); - - - HWND okButton = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON\0", "OK\0", - WS_CHILD | WS_VISIBLE | WS_TABSTOP, - 10, 60, 60, 30, dialog, (HMENU)IDOK, GetModuleHandle(nullptr), nullptr); - - HWND cancelButton = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON\0", "Cancel\0", - WS_CHILD | WS_VISIBLE, - 80, 60, 60, 30, dialog, (HMENU)IDCANCEL, GetModuleHandle(nullptr), nullptr); - - SetFocus( hEdit ); - - ShowWindow(dialog, SW_SHOWNORMAL); - bool bFirstEmpty = true; - while (true){ - if (!PeekMessageW( &Msg, 0, 0, 0, PM_REMOVE )){ - if (bFirstEmpty){ - // ShowWindow the first time the queue goes empty - ShowWindow( dialog, SW_SHOWNORMAL ); - bFirstEmpty = FALSE; - } - if (!(GetWindowLongW( dialog, GWL_STYLE ) & DS_NOIDLEMSG)){ - // No message present -> send ENTERIDLE and wait - SendMessageW( WindowFromDC(wglGetCurrentDC()), WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)dialog ); - } - GetMessageW( &Msg, 0, 0, 0 ); - } - - if (Msg.message == WM_QUIT){ - PostQuitMessage( Msg.wParam ); - if (!IsWindow( dialog )){ - EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - return text; - } - break; - } - - if (!IsWindow( dialog )){ - EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - return text; - } - - TranslateMessage( &Msg ); - DispatchMessageW( &Msg ); - - if((Msg.hwnd == okButton && Msg.message==WM_LBUTTONUP) || (Msg.message==WM_KEYUP && Msg.wParam==13)){ - break; - }else if((Msg.hwnd == cancelButton && Msg.message==WM_LBUTTONUP) || (Msg.message==WM_KEYUP && Msg.wParam==27)){ - EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - DestroyWindow(dialog); - return text; - } - - if (!IsWindow( dialog )){ - EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - return text; - } - - if (bFirstEmpty && Msg.message == WM_TIMER){ - ShowWindow( dialog, SW_SHOWNORMAL ); - bFirstEmpty = FALSE; - } - } - - char buf[16384]; - GetDlgItemTextA( dialog, 101, buf, 16384 ); - text = buf; - - DestroyWindow(dialog); - EnableWindow(WindowFromDC(wglGetCurrentDC()), TRUE); - - #endif - - #endif #ifdef TARGET_ANDROID diff --git a/libs/openFrameworks/utils/ofThread.cpp b/libs/openFrameworks/utils/ofThread.cpp index 6ed3e625ccb..93c417304ee 100644 --- a/libs/openFrameworks/utils/ofThread.cpp +++ b/libs/openFrameworks/utils/ofThread.cpp @@ -7,63 +7,67 @@ #include "ofxAndroidUtils.h" #endif - //------------------------------------------------- ofThread::ofThread() -:_threadRunning(false) -,_mutexBlocks(true) -,threadBeingWaitedFor(false){ - thread.setName("Thread " + ofToString(thread.id())); +:threadRunning(false) +,threadDone(true) +,mutexBlocks(true) +,name(""){ } - -//------------------------------------------------- -ofThread::~ofThread(){ -} - - //------------------------------------------------- bool ofThread::isThreadRunning() const{ - return _threadRunning; + return threadRunning; } - //------------------------------------------------- -int ofThread::getThreadId() const{ - return thread.id(); +std::thread::id ofThread::getThreadId() const{ + return thread.get_id(); } - //------------------------------------------------- std::string ofThread::getThreadName() const{ - return thread.name(); + return name; } +//------------------------------------------------- +void ofThread::setThreadName(const std::string & name){ + this->name = name; +} //------------------------------------------------- -void ofThread::startThread(bool mutexBlocks){ - if(thread.isRunning()){ +void ofThread::startThread(){ + std::unique_lock lck(mutex); + if(threadRunning || !threadDone){ ofLogWarning("ofThread") << "- name: " << getThreadName() << " - Cannot start, thread already running."; return; } - _threadRunning = true; - _mutexBlocks = mutexBlocks; + threadDone = false; + threadRunning = true; + this->mutexBlocks = false; - thread.start(*this); + thread = std::thread(std::bind(&ofThread::run,this)); } - //------------------------------------------------- -void ofThread::startThread(bool mutexBlocks, bool verbose){ - ofLogWarning("ofThread") << "- name: " << getThreadName() << " - Calling startThread with verbose is deprecated."; - startThread(mutexBlocks); -} +void ofThread::startThread(bool mutexBlocks){ + std::unique_lock lck(mutex); + if(threadRunning || !threadDone){ + ofLogWarning("ofThread") << "- name: " << getThreadName() << " - Cannot start, thread already running."; + return; + } + + threadDone = false; + threadRunning = true; + this->mutexBlocks = mutexBlocks; + thread = std::thread(std::bind(&ofThread::run,this)); +} //------------------------------------------------- bool ofThread::lock(){ - if(_mutexBlocks){ + if(mutexBlocks){ mutex.lock(); }else{ if(!mutex.try_lock()){ @@ -73,27 +77,27 @@ bool ofThread::lock(){ return true; } +//------------------------------------------------- +bool ofThread::tryLock(){ + return mutex.try_lock(); +} //------------------------------------------------- void ofThread::unlock(){ mutex.unlock(); } - //------------------------------------------------- void ofThread::stopThread(){ - _threadRunning = false; + threadRunning = false; } - //------------------------------------------------- void ofThread::waitForThread(bool callStopThread, long milliseconds){ - if(thread.isRunning()){ - threadBeingWaitedFor = true; - + if(!threadDone){ // tell thread to stop - if(callStopThread){ - stopThread(); // signalled to stop + if(callStopThread){ + stopThread(); } // wait for the thread to finish @@ -102,73 +106,49 @@ void ofThread::waitForThread(bool callStopThread, long milliseconds){ } if (INFINITE_JOIN_TIMEOUT == milliseconds){ - thread.join(); + try{ + thread.join(); + }catch(...){} }else{ // Wait for "joinWaitMillis" milliseconds for thread to finish - if(!thread.tryJoin(milliseconds)){ + std::unique_lock lck(mutex); + if(!threadDone && condition.wait_for(lck,std::chrono::milliseconds(milliseconds))==std::cv_status::timeout){ // unable to completely wait for thread } } } } - //------------------------------------------------- void ofThread::sleep(long milliseconds){ - Poco::Thread::sleep(milliseconds); + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); } - //------------------------------------------------- void ofThread::yield(){ - Poco::Thread::yield(); + std::this_thread::yield(); } - //------------------------------------------------- bool ofThread::isCurrentThread() const{ - return ofThread::getCurrentPocoThread() == &getPocoThread(); + return std::this_thread::get_id() == thread.get_id(); } - //------------------------------------------------- -Poco::Thread& ofThread::getPocoThread(){ +std::thread & ofThread::getNativeThread(){ return thread; } - //------------------------------------------------- -const Poco::Thread& ofThread::getPocoThread() const{ +const std::thread & ofThread::getNativeThread() const{ return thread; } - -//------------------------------------------------- -bool ofThread::isMainThread(){ - return !Poco::Thread::current(); -} - - -//------------------------------------------------- -ofThread* ofThread::getCurrentThread(){ - // assumes all created threads are ofThreads ... - // might be dangerous if people are using Poco::Threads directly - return (ofThread*) Poco::Thread::current(); -} - - -//------------------------------------------------- -Poco::Thread* ofThread::getCurrentPocoThread(){ - return Poco::Thread::current(); -} - - //------------------------------------------------- void ofThread::threadedFunction(){ ofLogWarning("ofThread") << "- name: " << getThreadName() << " - Override ofThread::threadedFunction() in your ofThread subclass."; } - //------------------------------------------------- void ofThread::run(){ #ifdef TARGET_ANDROID @@ -178,27 +158,23 @@ void ofThread::run(){ ofLogWarning() << "couldn't attach new thread to java vm"; } #endif + // user function // should loop endlessly. try{ threadedFunction(); - }catch(const Poco::Exception& exc){ - ofLogFatalError("ofThreadErrorLogger::exception") << exc.displayText(); }catch(const std::exception& exc){ ofLogFatalError("ofThreadErrorLogger::exception") << exc.what(); }catch(...){ ofLogFatalError("ofThreadErrorLogger::exception") << "Unknown exception."; } - - _threadRunning = false; - -#if !defined(TARGET_WIN32) - // FIXME: this won't be needed once we update POCO https://github.com/pocoproject/poco/issues/79 - if(!threadBeingWaitedFor){ //if threadedFunction() ended and the thread is not being waited for, detach it before exiting. - pthread_detach(pthread_self()); - } -#endif + thread.detach(); #ifdef TARGET_ANDROID attachResult = ofGetJavaVMPtr()->DetachCurrentThread(); #endif + + std::unique_lock lck(mutex); + threadRunning = false; + threadDone = true; + condition.notify_all(); } diff --git a/libs/openFrameworks/utils/ofThread.h b/libs/openFrameworks/utils/ofThread.h index 51b25171c7a..8efc90ef17e 100644 --- a/libs/openFrameworks/utils/ofThread.h +++ b/libs/openFrameworks/utils/ofThread.h @@ -2,9 +2,10 @@ #include "ofConstants.h" #ifndef TARGET_NO_THREADS -#include "Poco/AtomicCounter.h" -#include "Poco/Thread.h" -#include "Poco/Runnable.h" +#include +#include +#include +#include #include "ofTypes.h" @@ -66,59 +67,58 @@ /// and only allows the user to receive more valuable debugging information /// about the uncaught exception. Users should design ofThread subclasses to /// catch and respond to all anticipated exceptions. -class ofThread: protected Poco::Runnable { +class ofThread { public: /// \brief Create an ofThread. ofThread(); - /// \brief Destroy the ofThread. - /// \warning The destructor WILL NOT stop the thread or wait for - /// the underlying Poco::Thread to finish. For threads that - /// require the correct deallocation of resources, the user - /// MUST call waitForThread(...); to ensure that the thread - /// is stopped and the thread's resources are released. - /// Improper release of resources or memory can lead to - /// segementation faults and other errors. - virtual ~ofThread(); - /// \brief Check the running status of the thread. /// \returns true iff the thread is currently running. bool isThreadRunning() const; /// \brief Get the unique thread id. /// \note This is NOT the the same as the operating thread id! - int getThreadId() const; + std::thread::id getThreadId() const; /// \brief Get the unique thread name, in the form of "Thread id#" /// \returns the Thread ID string. std::string getThreadName() const; - /// \deprecated - /// \brief Start the thread with options. - /// - /// \param mutexesBlock Set blocking to true if you want the mutex to - /// block when lock() is called. - /// \param verbose use verbose logging methods. - OF_DEPRECATED_MSG("Use startThread(bool blocking = true) instead.", - void startThread(bool mutexesBlock, bool verbose) ); - - /// \brief Start the thread with options. - /// \param mutexBlocks Set blocking to true if you want the mutex to - /// block when lock() is called. + void setThreadName(const std::string & name); + + /// \brief Start the thread. /// \note Subclasses can directly access the mutex and employ thier /// own locking strategy. - void startThread(bool mutexBlocks = true); + void startThread(); - /// \brief Try to lock the mutex. + /// \brief Start the thread with options. + /// \param mutexBlocks Set blocking to true if you want the mutex to + /// block when lock() is called. + /// \note Subclasses can directly access the mutex and employ thier + /// own locking strategy. + OF_DEPRECATED_MSG("Use tryLock instead of setting the type of lock on startThread", + void startThread(bool mutexBlocks)); + + /// \brief Lock the mutex. /// /// If the thread was started startThread(true), then this call will wait /// until the mutex is available and return true. If the thread was started /// startThread(false), this call will return true iff the mutex is /// was successfully acquired. /// - /// \returns true iff the lock was successfully acquired. + /// \returns true if the lock was successfully acquired. bool lock(); + /// \brief Tries to lock the mutex. + /// + /// If the thread was started startThread(true), then this call will wait + /// until the mutex is available and return true. If the thread was started + /// startThread(false), this call will return true iff the mutex is + /// was successfully acquired. + /// + /// \returns true if the lock was successfully acquired. + bool tryLock(); + /// \brief Unlock the mutex. /// /// This will only unlocks the mutex if it was previously by the same @@ -256,7 +256,7 @@ class ofThread: protected Poco::Runnable { /// underlying Poco::Thread directly. /// /// \returns A reference to the backing Poco thread. - Poco::Thread& getPocoThread(); + std::thread& getNativeThread(); /// \brief Get a const reference to the underlying Poco thread. /// @@ -265,42 +265,8 @@ class ofThread: protected Poco::Runnable { /// underlying Poco::Thread directly. /// /// \returns A reference to the backing Poco thread. - const Poco::Thread& getPocoThread() const; + const std::thread & getNativeThread() const; - /// \brief A query to see if the current thread is the main thread. - /// - /// Some functions (e.g. OpenGL calls) can only be executed - /// the main thread. This static function will tell the user - /// what thread is currently active at the moment the method - /// is called. - /// - /// if (ofThread::isMainThread()) - /// { - /// ofLogNotice() << "This is the main thread!"; - /// } - /// else - /// { - /// ofLogNotice() << "This is NOT the main thread."; - /// } - /// - /// \returns true iff the current thread is the main thread. - static bool isMainThread(); - - /// \deprecated - /// \warning This function is dangerous and should no longer be used. - OF_DEPRECATED_MSG("use ofThread::getCurrentPocoThread() == &yourThread.getPocoThread() to compare threads.", - static ofThread* getCurrentThread()); - - /// \brief Get the current Poco thread. - /// - /// In most cases, it is more appropriate to query the current - /// thread by calling isCurrentThread() on an active thread or - /// by calling ofThread::isMainThread(). See the method - /// documentation for more information on those methods. - /// - /// \returns A pointer to the current active thread OR 0 iff the main - /// application thread is active. - static Poco::Thread* getCurrentPocoThread(); enum { INFINITE_JOIN_TIMEOUT = -1 @@ -347,28 +313,31 @@ class ofThread: protected Poco::Runnable { virtual void threadedFunction(); /// \brief The Poco::Thread that runs the Poco::Runnable. - Poco::Thread thread; + std::thread thread; /// \brief The internal mutex called through lock() & unlock(). /// - /// This mutext can also be used with ofScopedLock within the threaded - /// function by calling: + /// This mutext can also be used with std::unique_lock or lock_guard + /// within the threaded function by calling: /// - /// ofScopedLock lock(mutex); + /// std::unique_lock lock(mutex); /// - mutable std::mutex mutex; + std::mutex mutex; private: + ///< \brief Implements Poco::Runnable::run(). void run(); - ///< \brief Implements Poco::Runnable::run(). - Poco::AtomicCounter _threadRunning; - ///< \brief Is the thread running? + ///< \brief Is the thread running? + std::atomic threadRunning; + std::atomic threadDone; + + ///< \brief Should the mutex block? + std::atomic mutexBlocks; - Poco::AtomicCounter _mutexBlocks; - ///< \brief Should the mutex block? + std::string name; + std::condition_variable condition; - bool threadBeingWaitedFor; }; diff --git a/libs/openFrameworks/utils/ofThreadChannel.h b/libs/openFrameworks/utils/ofThreadChannel.h index c85f37b5449..e8e2debd78b 100644 --- a/libs/openFrameworks/utils/ofThreadChannel.h +++ b/libs/openFrameworks/utils/ofThreadChannel.h @@ -1,28 +1,72 @@ #pragma once + + #include #include #include #include "ofUtils.h" -/// Communication channel between different threads -/// allows for multithreaded programming without using -/// mutexes or other synchronization structures. -/// Instead of using some shared memory send a message -/// through a channel whenever one thread needs to send -/// some data to another. -/// Usually a second channel can be used to send the -/// processed data back to the first thread. + +/// \brief Safely send data between threads without additional synchronization. +/// +/// ofThreadChannel makes it easy to safely and efficiently share data between +/// threads without the need for shared memory, mutexes, or other +/// synchronization techniques. Additionally, ofThreadChannel employs a +/// signalling system that allows receiving threads to sleep until new data +/// arrives or the ofThreadChannel is closed. +/// +/// A single ofThreadChannel class is desgined for one-way communication. In +/// most cases an additional ofThreadChannel can be used for two-way +/// communication. +/// +/// Data is sent through the ofThreadChannel in a FIFO (first in, first out) +/// order, guaranteeing that that data will be received in the same order that +/// it was sent. +/// +/// If multiple threads attempt to send data using the same ofThreadChannel, the +/// send method will block the calling thread until it is free. +/// +/// \sa https://github.com/openframeworks/ofBook/blob/master/chapters/threads/chapter.md +/// \tparam T The data type sent by the ofThreadChannel. template class ofThreadChannel{ public: + /// \brief Create a default ofThreadChannel. + /// + /// ofThreadChannel must be instantiated with a template parameter such as: + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// ~~~~ ofThreadChannel() :closed(false){} - /// block until a new value is available - /// and receive it in the passed parameter. - /// returns true if there was a new value - /// or false if the channel was closed - bool receive(T & ret){ + /// \brief Block the receiving thread until a new sent value is available. + /// + /// The receiving thread will block until a new sent value is available. In + /// order to receive data, the user must create an instance of the data + /// type, and pass it to the receive method to be set. + /// + /// ofThreadChannel::receive will not make a copy or reallocate data. + /// + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// + /// // ofThreadChannel declared elsewhere. + /// + /// ofPixels myPixelsToSet; + /// + /// if (myThreadChannel.receive(myPixelsToSet)) { + /// // If true, `myPixelsToSet` can be used. + /// } else { + /// // If false, thread channel was closed and the value of + /// // `myPixelsToSet` may be invalid depending on the scope of + /// // `myPixelsToSet`. + /// } + /// ~~~~ + /// + /// \param sentValue A reference to a sent value. + /// \returns True if a new value was received or false if the ofThreadChannel was closed. + bool receive(T & sentValue){ std::unique_lock lock(mutex); if(closed){ return false; @@ -31,7 +75,7 @@ class ofThreadChannel{ condition.wait(lock); } if(!closed){ - swap(ret,queue.front()); + std::swap(sentValue,queue.front()); queue.pop(); return true; }else{ @@ -39,16 +83,43 @@ class ofThreadChannel{ } } - /// receives a new value in the passed parameter - /// and returns true or returns false if there - /// is no data available or the channel was closed - bool tryReceive(T & ret){ + /// \brief If available, receive a new sent value without blocking. + /// + /// ofThreadChannel::tryReceive is similar to ofThreadChannel::receive, + /// except that it will not block the receiving thread. If no data is + /// available, it will return false and continue immediately. + /// + /// ofThreadChannel::tryReceive will not make a copy or reallocate data. + /// + /// Like ofThreadChannel::receive, in order to receive data, the user must + /// create an instance of the data type, and pass it to the receive method + /// to be set. + /// + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// + /// // ofThreadChannel initialized elsewhere. + /// + /// ofPixels myPixelsToSet; + /// + /// if (myThreadChannel.tryReceive(myPixelsToSet)) { + /// // If true, `myPixelsToSet` can be used. + /// } else { + /// // If false, there was no new data OR the thread channel was closed. + /// // Either way, the value of `myPixelsToSet` may be invalid depending + /// // on the scope of `myPixelsToSet`. + /// } + /// ~~~~ + /// + /// \param sentValue A reference to a sent value. + /// \returns True if a new value was received or false if the ofThreadChannel was closed. + bool tryReceive(T & sentValue){ std::unique_lock lock(mutex); if(closed){ return false; } if(!queue.empty()){ - swap(ret,queue.front()); + std::swap(sentValue,queue.front()); queue.pop(); return true; }else{ @@ -56,11 +127,39 @@ class ofThreadChannel{ } } - /// receives a new value in the passed parameter - /// and returns true or returns false if there - /// after the specified timeout in ms there is - /// no data available or the channel was closed - bool tryReceive(T & ret, int64_t timeoutMs){ + /// \brief If available, receive a new sent value or wait for a user-specified duration. + /// + /// ofThreadChannel::tryReceive is similar to ofThreadChannel::receive, + /// except that it will block the receiving thread for a maximum of + /// `timeoutMs` while it waits for sent data. If no data is available + /// during that time, it will return false and continue. + /// + /// ofThreadChannel::tryReceive will not make a copy or reallocate data. + /// + /// Like ofThreadChannel::receive, in order to receive data, the user must + /// create an instance of the data type, and pass it to the receive method + /// to be set. + /// + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// + /// // ofThreadChannel initialized elsewhere. + /// + /// ofPixels myPixelsToSet; + /// + /// if (myThreadChannel.tryReceive(myPixelsToSet)) { + /// // If true, `myPixelsToSet` can be used. + /// } else { + /// // If false, there was no new data OR the thread channel was closed. + /// // Either way, the value of `myPixelsToSet` may be invalid depending + /// // on the scope of `myPixelsToSet`. + /// } + /// ~~~~ + /// + /// \param sentValue A reference to a sent value. + /// \param timeoutMs The number of milliseconds to wait for new data before continuing. + /// \returns True if a new value was received or false if the ofThreadChannel was closed. + bool tryReceive(T & sentValue, int64_t timeoutMs){ std::unique_lock lock(mutex); if(closed){ return false; @@ -72,7 +171,7 @@ class ofThreadChannel{ } if(!closed){ - swap(ret,queue.front()); + std::swap(sentValue,queue.front()); queue.pop(); return true; }else{ @@ -80,48 +179,116 @@ class ofThreadChannel{ } } - /// sends a copy of the passed value - /// returns true if it was sent successfully - /// or false if the channel was closed - bool send(const T & val){ + /// \brief Send a value to the receiver by making a copy. + /// + /// This method copies the contents of the sent value, leaving the original + /// data unchanged. + /// + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// + /// // ofThreadChannel initialized elsewhere. + /// + /// ofPixels myPixelsToSend; + /// + /// // Fill the pixels with valid data, an image for example. + /// + /// ofLoadImage(myPixelsToSend, "myImage.jpg"); + /// + /// // Send `myPixelsToSend` by copying it. `myPixelsToSend` is still valid + /// // after sending. + /// if (myThreadChannel.send(myPixelsToSend)) { + /// // If true, `myPixelsToSend` was sent successfully. + /// } else { + /// // If false, the thread channel was closed. + /// } + /// ~~~~ + /// + /// \returns true if the value was sent successfully or false if the channel was closed. + bool send(const T & value){ std::unique_lock lock(mutex); if(closed){ return false; } - queue.push(val); + queue.push(value); condition.notify_all(); return true; } - /// sends a value by moving it to avoid a copy. - /// the original is invalidated. use like: + /// \brief Send a value to the receiver without making a copy. + /// + /// This method moves the contents of the sent value using `std::move` + /// semantics. This avoids copying the data, but the original data data will + /// be invalidated. Note that the original data will be invalideated even if + /// the send fails because the channel is already closed. + /// + /// ~~~~{.cpp} + /// ofThreadChannel myThreadChannel; + /// + /// // ofThreadChannel initialized elsewhere. + /// + /// ofPixels myPixelsToSend; /// - /// channel.send(std::move(value)) + /// // Fill the pixels with valid data, an image for example. /// - /// only c++11 - bool send(T && val){ + /// ofLoadImage(myPixelsToSend, "myImage.jpg"); + /// + /// // Send `myPixelsToSend` by moving it. `myPixelsToSend` will no longer + /// // be valid, even if the send fails because the channel is closed. + /// if (myThreadChannel.send(std::move(myPixelsToSend))) { + /// // If true, `myPixelsToSend` was sent successfully. + /// // `myPixelsToSend` is no longer valid because it was moved. + /// } else { + /// // If false, the thread channel was closed. + /// // `myPixelsToSend` is no longer valid because it was moved. + /// } + /// + /// ~~~~ + /// + /// \returns true if the value was sent successfully or false if the channel was closed. + bool send(T && value){ std::unique_lock lock(mutex); if(closed){ return false; } - queue.push(val); + queue.push(value); condition.notify_all(); return true; } - /// closes the channel, from here on - /// no new messages can be sent or received - /// and any threads waiting to receive a value - /// are awaken and return false + /// \brief Close the ofThreadChannel. + /// + /// Closing the ofThreadChannel means that no new messages can be sent or + /// received. All threads waiting to receive new values will be notified and + /// all ofThreadChannel::receive and ofThreadChannel::tryReceive methods + /// will return false. void close(){ std::unique_lock lock(mutex); closed = true; condition.notify_all(); } + + /// \brief Queries empty channel. + /// + /// This call is only an approximation, since messages come from a different + /// thread the channel can return true when calling empty() and then receive + /// a message right afterwards + bool empty() const{ + return queue.empty(); + } + private: + /// \brief The FIFO data queue. std::queue queue; + + /// \brief The mutext to protect the data. std::mutex mutex; + + /// \brief The condition even to notify receivers. std::condition_variable condition; + + /// \brief True if the channel is closed. bool closed; + }; diff --git a/libs/openFrameworks/utils/ofURLFileLoader.cpp b/libs/openFrameworks/utils/ofURLFileLoader.cpp index 2882b65b55e..730c51f5127 100644 --- a/libs/openFrameworks/utils/ofURLFileLoader.cpp +++ b/libs/openFrameworks/utils/ofURLFileLoader.cpp @@ -139,7 +139,7 @@ void ofURLFileLoaderImpl::stop() { } void ofURLFileLoaderImpl::threadedFunction() { - thread.setName("ofURLFileLoader " + thread.name()); + setThreadName("ofURLFileLoader " + ofToString(getThreadId())); while( isThreadRunning() ){ int cancelled; while(cancelRequestQueue.tryReceive(cancelled)){ @@ -171,41 +171,51 @@ ofHttpResponse ofURLFileLoaderImpl::handleRequest(ofHttpRequest request) { URI uri(request.url); std::string path(uri.getPathAndQuery()); if (path.empty()) path = "/"; - - HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1); + std::string pocoMethod; + if(request.method==ofHttpRequest::GET){ + pocoMethod = HTTPRequest::HTTP_GET; + }else{ + pocoMethod = HTTPRequest::HTTP_POST; + } + HTTPRequest req(pocoMethod, path, HTTPMessage::HTTP_1_1); for(map::iterator it = request.headers.begin(); it!=request.headers.end(); it++){ req.add(it->first,it->second); } HTTPResponse res; - shared_ptr session; - istream * rs; + std::unique_ptr session; if(uri.getScheme()=="https"){ //const Poco::Net::Context::Ptr context( new Poco::Net::Context( Poco::Net::Context::CLIENT_USE, "", "", "rootcert.pem" ) ); - HTTPSClientSession * httpsSession = new HTTPSClientSession(uri.getHost(), uri.getPort());//,context); - httpsSession->setTimeout(Poco::Timespan(120,0)); - httpsSession->sendRequest(req); - rs = &httpsSession->receiveResponse(res); - session = shared_ptr(httpsSession); + session.reset(new HTTPSClientSession(uri.getHost(), uri.getPort()));//,context); }else{ - HTTPClientSession * httpSession = new HTTPClientSession(uri.getHost(), uri.getPort()); - httpSession->setTimeout(Poco::Timespan(120,0)); - httpSession->sendRequest(req); - rs = &httpSession->receiveResponse(res); - session = shared_ptr(httpSession); + session.reset(new HTTPClientSession(uri.getHost(), uri.getPort())); + } + session->setTimeout(Poco::Timespan(120,0)); + if(request.contentType!=""){ + req.setContentType(request.contentType); } + if(request.body!=""){ + req.setContentLength( request.body.length() ); + auto & send = session->sendRequest(req); + send.write(request.body.c_str(), request.body.size()); + send << std::flush; + }else{ + session->sendRequest(req); + } + + auto & rs = session->receiveResponse(res); if(!request.saveTo){ - return ofHttpResponse(request,*rs,res.getStatus(),res.getReason()); + return ofHttpResponse(request,rs,res.getStatus(),res.getReason()); }else{ ofFile saveTo(request.name,ofFile::WriteOnly,true); char aux_buffer[1024]; - rs->read(aux_buffer, 1024); - std::streamsize n = rs->gcount(); + rs.read(aux_buffer, 1024); + std::streamsize n = rs.gcount(); while (n > 0){ // we resize to size+1 initialized to 0 to have a 0 at the end for strings saveTo.write(aux_buffer,n); - if (rs->good()){ - rs->read(aux_buffer, 1024); - n = rs->gcount(); + if (rs.good()){ + rs.read(aux_buffer, 1024); + n = rs.gcount(); } else n = 0; } @@ -284,6 +294,7 @@ static ofURLFileLoader & getFileLoader(){ ofHttpRequest::ofHttpRequest() :saveTo(false) +,method(GET) ,id(nextID++) { } @@ -292,6 +303,7 @@ ofHttpRequest::ofHttpRequest(const string& url, const string& name,bool saveTo) :url(url) ,name(name) ,saveTo(saveTo) +,method(GET) ,id(nextID++) { } diff --git a/libs/openFrameworks/utils/ofURLFileLoader.h b/libs/openFrameworks/utils/ofURLFileLoader.h index e2189dad64b..8eb9aa47f3a 100644 --- a/libs/openFrameworks/utils/ofURLFileLoader.h +++ b/libs/openFrameworks/utils/ofURLFileLoader.h @@ -12,10 +12,17 @@ class ofHttpRequest{ string name; bool saveTo; map headers; + string body; // usually only for post + string contentType; int getId() const; OF_DEPRECATED_MSG("Use ofGetId().", int getID()); + enum Method{ + GET, + POST + } method; + private: int id; static int nextID; diff --git a/libs/openFrameworks/utils/ofUtils.cpp b/libs/openFrameworks/utils/ofUtils.cpp index b16b091e605..7105b9d50b9 100644 --- a/libs/openFrameworks/utils/ofUtils.cpp +++ b/libs/openFrameworks/utils/ofUtils.cpp @@ -52,10 +52,64 @@ #define MAXPATHLEN 1024 #endif -static bool enableDataPath = true; -static uint64_t startTimeSeconds; // better at the first frame ?? (currently, there is some delay from static init, to running. -static uint64_t startTimeNanos; +namespace{ + bool enableDataPath = true; + uint64_t startTimeSeconds; // better at the first frame ?? (currently, there is some delay from static init, to running. + uint64_t startTimeNanos; +#ifdef TARGET_OSX + clock_serv_t cs; +#endif + + //-------------------------------------------------- + string defaultDataPath(){ + #if defined TARGET_OSX + try{ + return std::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(), "../../../data/")).string(); + }catch(...){ + return ofFilePath::join(ofFilePath::getCurrentExeDir(), "../../../data/"); + } + #elif defined TARGET_ANDROID + return string("sdcard/"); + #else + try{ + return std::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/")).string(); + }catch(...){ + return ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/"); + } + #endif + } + + //-------------------------------------------------- + std::filesystem::path & defaultWorkingDirectory(){ + static auto * defaultWorkingDirectory = new std::filesystem::path(); + return * defaultWorkingDirectory; + } + + //-------------------------------------------------- + std::filesystem::path & dataPathRoot(){ + static auto * dataPathRoot = new std::filesystem::path(defaultDataPath()); + return *dataPathRoot; + } +} +namespace of{ +namespace priv{ + void initutils(){ +#ifdef TARGET_OSX + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs); +#endif + defaultWorkingDirectory() = std::filesystem::absolute(std::filesystem::current_path()); + ofResetElapsedTimeCounter(); + ofSeedRandom(); + } + + void endutils(){ +#ifdef TARGET_OSX + mach_port_deallocate(mach_task_self(), cs); +#endif + } +} +} //-------------------------------------- void ofGetMonotonicTime(uint64_t & seconds, uint64_t & nanoseconds){ @@ -65,11 +119,8 @@ void ofGetMonotonicTime(uint64_t & seconds, uint64_t & nanoseconds){ seconds = now.tv_sec; nanoseconds = now.tv_nsec; #elif defined(TARGET_OSX) - clock_serv_t cs; - mach_timespec_t now; - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs); - clock_get_time(cs, &now); - mach_port_deallocate(mach_task_self(), cs); + mach_timespec_t now; + clock_get_time(cs, &now); seconds = now.tv_sec; nanoseconds = now.tv_nsec; #elif defined( TARGET_WIN32 ) @@ -179,13 +230,13 @@ string ofGetTimestampString(const string& timestampFormat){ // so we have to filter out %i (which is not supported by vs) // earlier. auto tmpTimestampFormat = timestampFormat; - ofStringReplace(tmpTimestampFormat, "%i", ofToString(ms)); - + ofStringReplace(tmpTimestampFormat, "%i", ofToString(ms, 3, '0')); + if (strftime(buf,bufsize, tmpTimestampFormat.c_str(),&tm) != 0){ str << buf; } auto ret = str.str(); - + return ret; } @@ -266,49 +317,15 @@ void ofDisableDataPath(){ } //-------------------------------------------------- -string defaultDataPath(){ -#if defined TARGET_OSX - return string("../../../data/"); -#elif defined TARGET_ANDROID - return string("sdcard/"); -#elif defined(TARGET_LINUX) || defined(TARGET_WIN32) - return string(ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/")); -#else - return string("data/"); -#endif -} - -//-------------------------------------------------- -static std::filesystem::path & defaultWorkingDirectory(){ - static auto * defaultWorkingDirectory = new std::filesystem::path(); - return * defaultWorkingDirectory; -} - -//-------------------------------------------------- -static std::filesystem::path & dataPathRoot(){ - static auto * dataPathRoot = new std::filesystem::path(defaultDataPath()); - return *dataPathRoot; +bool ofRestoreWorkingDirectoryToDefault(){ + try{ + std::filesystem::current_path(defaultWorkingDirectory()); + return true; + }catch(...){ + return false; + } } -//-------------------------------------------------- -void ofSetWorkingDirectoryToDefault(){ -#ifdef TARGET_OSX - #ifndef TARGET_OF_IOS - char path[MAXPATHLEN]; - uint32_t size = sizeof(path); - - if (_NSGetExecutablePath(path, &size) == 0){ - std::filesystem::path classPath(path); - classPath = classPath.parent_path(); - chdir( classPath.native().c_str() ); - }else{ - ofLogFatalError("ofUtils") << "ofSetDataPathRoot(): path buffer too small, need size " << (unsigned int) size; - } - #endif -#endif - defaultWorkingDirectory() = std::filesystem::absolute(std::filesystem::current_path()); -} - //-------------------------------------------------- void ofSetDataPathRoot(const string& newRoot){ dataPathRoot() = newRoot; @@ -318,50 +335,79 @@ void ofSetDataPathRoot(const string& newRoot){ string ofToDataPath(const string& path, bool makeAbsolute){ if (!enableDataPath) return path; - + + bool hasTrailingSlash = !path.empty() && std::filesystem::path(path).generic_string().back()=='/'; + // if our Current Working Directory has changed (e.g. file open dialog) #ifdef TARGET_WIN32 if (defaultWorkingDirectory() != std::filesystem::current_path()) { // change our cwd back to where it was on app load - int ret = chdir(defaultWorkingDirectory().string().c_str()); - if(ret==-1){ + bool ret = ofRestoreWorkingDirectoryToDefault(); + if(!ret){ ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory(); } } #endif + // this could be performed here, or wherever we might think we accidentally change the cwd, e.g. after file dialogs on windows - const auto & dataPath = dataPathRoot(); std::filesystem::path inputPath(path); std::filesystem::path outputPath; - + // if path is already absolute, just return it if (inputPath.is_absolute()) { - return path; + try { + auto outpath = std::filesystem::canonical(inputPath); + if(std::filesystem::is_directory(outpath) && hasTrailingSlash){ + return ofFilePath::addTrailingSlash(outpath.string()); + }else{ + return outpath.string(); + } + } + catch (...) { + return inputPath.string(); + } } - + // here we check whether path already refers to the data folder by looking for common elements // if the path begins with the full contents of dataPathRoot then the data path has already been added // we compare inputPath.toString() rather that the input var path to ensure common formatting against dataPath.toString() - auto strippedDataPath = dataPath.string(); + auto dirDataPath = dataPath.string(); // also, we strip the trailing slash from dataPath since `path` may be input as a file formatted path even if it is a folder (i.e. missing trailing slash) - strippedDataPath = ofFilePath::removeTrailingSlash(strippedDataPath); - - if (inputPath.string().find(strippedDataPath) != 0) { + dirDataPath = ofFilePath::addTrailingSlash(dirDataPath); + + auto relativeDirDataPath = ofFilePath::makeRelative(std::filesystem::current_path().string(),dataPath.string()); + relativeDirDataPath = ofFilePath::addTrailingSlash(relativeDirDataPath); + + if (inputPath.string().find(dirDataPath) != 0 && inputPath.string().find(relativeDirDataPath)!=0) { // inputPath doesn't contain data path already, so we build the output path as the inputPath relative to the dataPath - outputPath = dataPath / inputPath; + if(makeAbsolute){ + outputPath = dirDataPath / inputPath; + }else{ + outputPath = relativeDirDataPath / inputPath; + } } else { // inputPath already contains data path, so no need to change outputPath = inputPath; } - - // finally, if we do want an absolute path and we don't already have one - if (makeAbsolute) { - // then we return the absolute form of the path - return std::filesystem::absolute(outputPath).string(); - } else { + + // finally, if we do want an absolute path and we don't already have one + if(makeAbsolute){ + // then we return the absolute form of the path + try { + auto outpath = std::filesystem::canonical(std::filesystem::absolute(outputPath)); + if(std::filesystem::is_directory(outpath) && hasTrailingSlash){ + return ofFilePath::addTrailingSlash(outpath.string()); + }else{ + return outpath.string(); + } + } + catch (std::exception &) { + return std::filesystem::absolute(outputPath).string(); + } + }else{ // or output the relative path - return outputPath.string(); + return outputPath.string(); } } @@ -400,10 +446,7 @@ string ofToHex(const char* value) { //---------------------------------------- int ofToInt(const string& intString) { - int x = 0; - istringstream cur(intString); - cur >> x; - return x; + return ofTo(intString); } //---------------------------------------- @@ -457,26 +500,17 @@ string ofHexToString(const string& stringHexString) { //---------------------------------------- float ofToFloat(const string& floatString) { - float x = 0; - istringstream cur(floatString); - cur >> x; - return x; + return ofTo(floatString); } //---------------------------------------- double ofToDouble(const string& doubleString) { - double x = 0; - istringstream cur(doubleString); - cur >> x; - return x; + return ofTo(doubleString); } //---------------------------------------- int64_t ofToInt64(const string& intString) { - int64_t x = 0; - istringstream cur(intString); - cur >> x; - return x; + return ofTo(intString); } //---------------------------------------- @@ -496,10 +530,7 @@ bool ofToBool(const string& boolString) { //---------------------------------------- char ofToChar(const string& charString) { - char x = '\0'; - istringstream cur(charString); - cur >> x; - return x; + return ofTo(charString); } //---------------------------------------- @@ -507,7 +538,7 @@ template <> string ofToBinary(const string& value) { stringstream out; std::size_t numBytes = value.size(); for(std::size_t i = 0; i < numBytes; i++) { - bitset<8> bitBuffer(value[i]); + std::bitset<8> bitBuffer(value[i]); out << bitBuffer; } return out.str(); @@ -523,21 +554,21 @@ string ofToBinary(const char* value) { //---------------------------------------- int ofBinaryToInt(const string& value) { const int intSize = sizeof(int) * 8; - bitset binaryString(value); + std::bitset binaryString(value); return (int) binaryString.to_ulong(); } //---------------------------------------- char ofBinaryToChar(const string& value) { const int charSize = sizeof(char) * 8; - bitset binaryString(value); + std::bitset binaryString(value); return (char) binaryString.to_ulong(); } //---------------------------------------- float ofBinaryToFloat(const string& value) { const int floatSize = sizeof(float) * 8; - bitset binaryString(value); + std::bitset binaryString(value); union ulongFloatUnion { unsigned long result; float f; @@ -549,7 +580,7 @@ float ofBinaryToFloat(const string& value) { string ofBinaryToString(const string& value) { ostringstream out; stringstream stream(value); - bitset<8> byteString; + std::bitset<8> byteString; std::size_t numBytes = value.size() / 8; for(std::size_t i = 0; i < numBytes; i++) { stream >> byteString; @@ -584,15 +615,23 @@ vector ofSplitString(const string & source, const string & delimiter, b } //-------------------------------------------------- -string ofJoinString(const vector& stringElements, const string & delimiter){ +string ofJoinString(const vector& stringElements, const string& delimiter){ + string str; if(stringElements.empty()){ - return ""; + return str; } - return std::accumulate(stringElements.cbegin() + 1, stringElements.cend(), stringElements[0], - [delimiter](std::string a, std::string b) -> const char *{ - return (a + delimiter + b).c_str(); - } - ); + auto numStrings = stringElements.size(); + string::size_type strSize = delimiter.size() * (numStrings - 1); + for (const string &s : stringElements) { + strSize += s.size(); + } + str.reserve(strSize); + str += stringElements[0]; + for (decltype(numStrings) i = 1; i < numStrings; ++i) { + str += delimiter; + str += stringElements[i]; + } + return str; } //-------------------------------------------------- @@ -716,31 +755,27 @@ string ofToUpper(const string & src, const string & locale){ //-------------------------------------------------- string ofTrimFront(const string & src, const string& locale){ - std::locale loc = getLocale(locale); - auto it = ofUTF8Iterator(src); - auto front = std::find_if_not(it.begin(),it.end(),[&loc](uint32_t c){return std::isspace(c,loc);}); - return std::string(front,it.end()); + auto dst = src; + std::locale loc = getLocale(locale); + dst.erase(dst.begin(),std::find_if_not(dst.begin(),dst.end(),[&](char & c){return std::isspace(c,loc);})); + return dst; } //-------------------------------------------------- string ofTrimBack(const string & src, const string& locale){ - std::locale loc = getLocale(locale); - auto it = ofUTF8Iterator(src); - auto back = std::find_if_not(it.rbegin(),it.rend(),[&loc](uint32_t c){return std::isspace(c,loc);}).base().base(); - return std::string(it.begin().base(),back); + auto dst = src; + std::locale loc = getLocale(locale); + dst.erase(std::find_if_not(dst.rbegin(),dst.rend(),[&](char & c){return std::isspace(c,loc);}).base(), dst.end()); + return dst; } //-------------------------------------------------- string ofTrim(const string & src, const string& locale){ - std::locale loc = getLocale(locale); - auto it = ofUTF8Iterator(src); - auto front = std::find_if_not(it.begin(),it.end(),[&loc](uint32_t c){return std::isspace(c,loc);}).base(); - auto back = std::find_if_not(it.rbegin(), it.rend(),[&loc](uint32_t c){return std::isspace(c,loc);}).base().base(); - return (back<=front ? std::string() : std::string(front,back)); + return ofTrimFront(ofTrimBack(src)); } //-------------------------------------------------- -void ofAppendUTF8(string & str, int utf8){ +void ofAppendUTF8(string & str, uint32_t utf8){ try{ utf8::append(utf8, back_inserter(str)); }catch(...){} @@ -808,11 +843,11 @@ void ofLaunchBrowser(const string& url, bool uriEncodeQuery){ ofLogError("ofUtils") << "ofLaunchBrowser(): malformed url \"" << url << "\": " << exc.what(); return; } - + if(uriEncodeQuery) { uri.setQuery(uri.getRawQuery()); // URI encodes during set } - + // http://support.microsoft.com/kb/224816 // make sure it is a properly formatted url: // some platforms, like Android, require urls to start with lower-case http/https @@ -823,14 +858,8 @@ void ofLaunchBrowser(const string& url, bool uriEncodeQuery){ } #ifdef TARGET_WIN32 - #if (_MSC_VER) - // microsoft visual studio yaks about strings, wide chars, unicode, etc ShellExecuteA(nullptr, "open", uri.toString().c_str(), nullptr, nullptr, SW_SHOWNORMAL); - #else - ShellExecute(nullptr, "open", uri.toString().c_str(), - nullptr, nullptr, SW_SHOWNORMAL); - #endif #endif #ifdef TARGET_OSX @@ -936,10 +965,10 @@ string ofSystem(const string& command){ FILE * ret = nullptr; #ifdef TARGET_WIN32 ret = _popen(command.c_str(),"r"); -#else +#else ret = popen(command.c_str(),"r"); #endif - + string strret; int c; @@ -980,7 +1009,7 @@ ofTargetPlatform ofGetTargetPlatform(){ #if (_MSC_VER) return OF_TARGET_WINVS; #else - return OF_TARGET_WINGCC; + return OF_TARGET_MINGW; #endif #elif defined(TARGET_ANDROID) return OF_TARGET_ANDROID; @@ -990,3 +1019,23 @@ ofTargetPlatform ofGetTargetPlatform(){ return OF_TARGET_EMSCRIPTEN; #endif } + +std::string ofGetEnv(const std::string & var){ +#ifdef TARGET_WIN32 + const size_t BUFSIZE = 4096; + std::vector pszOldVal(BUFSIZE, 0); + auto size = GetEnvironmentVariableA(var.c_str(), pszOldVal.data(), BUFSIZE); + if(size>0){ + return std::string(pszOldVal.begin(), pszOldVal.begin()+size); + }else{ + return ""; + } +#else + auto value = getenv(var.c_str()); + if(value){ + return value; + }else{ + return ""; + } +#endif +} diff --git a/libs/openFrameworks/utils/ofUtils.h b/libs/openFrameworks/utils/ofUtils.h index c0163834dd0..ba10fdde133 100644 --- a/libs/openFrameworks/utils/ofUtils.h +++ b/libs/openFrameworks/utils/ofUtils.h @@ -185,9 +185,12 @@ string ofToDataPath(const string& path, bool absolute=false); /// \brief Reset the working directory to the platform default. /// -/// The default working directory is usually in a data/ folder next to the -/// openFrameworks application. -void ofSetWorkingDirectoryToDefault(); +/// The default working directory is where the application was started from +/// or the exe directory in case of osx bundles. GLUT might change the default +/// working directory to the resources directory in the bundle in osx. This +/// will restore it to the exe dir or whatever was the current dir when the +/// application was started +bool ofRestoreWorkingDirectoryToDefault(); /// \brief Set the relative path to the data/ folder from the executable. /// @@ -308,8 +311,8 @@ void ofSort(vector& values) { /// 9, 8, 7, 6, 5, 4, 3, 2, 1, 0. /// /// \tparam T the type contained by the vector. -/// \param The vector of values to be sorted. -/// \param The comparison function. +/// \param values The vector of values to be sorted. +/// \param compare The comparison function. /// \sa http://www.cplusplus.com/reference/algorithm/sort/ template void ofSort(vector& values, BoolFunction compare) { @@ -345,7 +348,7 @@ bool ofContains(const vector& values, const T& target) { /// \name String Manipulation /// \{ -/// \brief Splits a string using a delimiter. +/// \brief Splits a string using a delimiter. /// /// ofSplitString splits a string and returns the collection of string /// tokens inside of a std::vector. @@ -436,7 +439,7 @@ string ofTrimFront(const string & src, const string & locale = ""); string ofTrimBack(const string & src, const string & locale = ""); string ofTrim(const string & src, const string & locale = ""); -void ofAppendUTF8(string & str, int utf8); +void ofAppendUTF8(string & str, uint32_t utf8); /// \brief Convert a variable length argument to a string. /// \param format a printf-style format string. @@ -581,6 +584,13 @@ const char * ofFromString(const string & value); /// \} +template T ofTo(const std::string & str){ + T x; + istringstream cur(str); + cur >> x; + return x; +} + // -------------------------------------------- /// \name Number conversion /// \{ @@ -590,7 +600,7 @@ const char * ofFromString(const string & value); /// Converts a `std::string` representation of an int (e.g., `"3"`) to an actual /// `int`. /// -/// \param The string representation of the integer. +/// \param intString The string representation of the integer. /// \returns the integer represented by the string or 0 on failure. int ofToInt(const string& intString); @@ -603,7 +613,7 @@ int ofToInt(const string& intString); /// Converts a `std::string` representation of a long integer /// (e.g., `"9223372036854775807"`) to an actual `int64_t`. /// -/// \param The string representation of the long integer. +/// \param intString The string representation of the long integer. /// \returns the long integer represented by the string or 0 on failure. int64_t ofToInt64(const string& intString); @@ -612,7 +622,7 @@ int64_t ofToInt64(const string& intString); /// Converts a std::string representation of a float (e.g., `"3.14"`) to an /// actual `float`. /// -/// \param The string representation of the float. +/// \param floatString string representation of the float. /// \returns the float represented by the string or 0 on failure. float ofToFloat(const string& floatString); @@ -621,7 +631,7 @@ float ofToFloat(const string& floatString); /// Converts a std::string representation of a double (e.g., `"3.14"`) to an /// actual `double`. /// -/// \param The string representation of the double. +/// \param doubleString The string representation of the double. /// \returns the double represented by the string or 0 on failure. double ofToDouble(const string& doubleString); @@ -631,7 +641,7 @@ double ofToDouble(const string& doubleString); /// actual `bool` using a case-insensitive comparison against the words `"true"` /// and `"false"`. /// -/// \param The string representation of the boolean. +/// \param boolString The string representation of the boolean. /// \returns the boolean represented by the string or 0 on failure. bool ofToBool(const string& boolString); @@ -734,16 +744,7 @@ char ofToChar(const string& charString); /// \returns a binary string. template string ofToBinary(const T& value) { - ostringstream out; - const char* data = (const char*) &value; - // the number of bytes is determined by the datatype - int numBytes = sizeof(T); - // the bytes are stored backwards (least significant first) - for(int i = numBytes - 1; i >= 0; i--) { - bitset<8> cur(data[i]); - out << cur; - } - return out.str(); + return std::bitset<8 * sizeof(T)>(*reinterpret_cast(&value)).to_string(); } /// \brief Converts a string value to a string of only 1s and 0s. @@ -911,6 +912,8 @@ string ofSystem(const string& command); ofTargetPlatform ofGetTargetPlatform(); +std::string ofGetEnv(const std::string & var); + /// Allows to iterate over a string's utf8 codepoints. /// The easiest way to use it is with a c++11 range style /// for loop like: @@ -934,3 +937,15 @@ class ofUTF8Iterator{ }; /// \} + + + +/*! \cond PRIVATE */ +namespace of{ +namespace priv{ + void setWorkingDirectoryToDefault(); + void initutils(); + void endutils(); +} +} +/*! \endcond */ diff --git a/libs/openFrameworks/utils/ofXml.cpp b/libs/openFrameworks/utils/ofXml.cpp index fc41711fe9a..883256fbc4e 100644 --- a/libs/openFrameworks/utils/ofXml.cpp +++ b/libs/openFrameworks/utils/ofXml.cpp @@ -1,19 +1,18 @@ - #include "ofXml.h" #include "Poco/AutoPtr.h" -ofXml::~ofXml() { +ofXml::~ofXml(){ releaseAll(); } -ofXml::ofXml( const string & path ) { - document = new Poco::XML::Document(); // we create this so that they can be merged later - element = document->documentElement(); - load(path); -} -ofXml::ofXml( const ofXml& rhs ) { +ofXml::ofXml(const string & path){ + document = new Poco::XML::Document(); // we create this so that they can be merged later + element = document->documentElement(); + load(path); +} +ofXml::ofXml(const ofXml & rhs){ document = new Poco::XML::Document(); Poco::XML::Node *n = document->importNode(rhs.getPocoDocument()->documentElement(), true); document->appendChild(n); @@ -21,24 +20,28 @@ ofXml::ofXml( const ofXml& rhs ) { element = document->documentElement(); } -const ofXml& ofXml::operator =( const ofXml& rhs ) { - if(&rhs==this) return *this; +const ofXml & ofXml::operator=(const ofXml & rhs){ + if(&rhs == this){ + return *this; + } releaseAll(); - document = (Poco::XML::Document*) rhs.document->cloneNode(true); - element = document->documentElement(); - return *this; + document = (Poco::XML::Document *)rhs.document->cloneNode(true); + element = document->documentElement(); + return *this; } -ofXml::ofXml() { - document = new Poco::XML::Document(); // we create this so that they can be merged later - element = document->documentElement(); + +ofXml::ofXml(){ + document = new Poco::XML::Document(); // we create this so that they can be merged later + element = document->documentElement(); } + bool ofXml::load(const string & path){ ofFile file(path, ofFile::ReadOnly); - if(!file.exists()) { + if(!file.exists()){ ofLogError("ofXml") << "couldn't load, \"" << file.getFileName() << "\" not found"; return false; } @@ -46,26 +49,32 @@ bool ofXml::load(const string & path){ return loadFromBuffer(xmlBuffer); } + bool ofXml::save(const string & path){ ofBuffer buffer(toString()); ofFile file(path, ofFile::WriteOnly); return file.writeFromBuffer(buffer); } + void ofXml::serialize(const ofAbstractParameter & parameter){ - if(!parameter.isSerializable()) return; + if(!parameter.isSerializable()){ + return; + } string name = parameter.getEscapedName(); - if(name=="") name="UnknownName"; - if(parameter.type()==typeid(ofParameterGroup).name()){ - const ofParameterGroup & group = static_cast(parameter); + if(name == ""){ + name = "UnknownName"; + } + if(parameter.type() == typeid(ofParameterGroup).name()){ + const ofParameterGroup & group = static_cast (parameter); if(!exists(name)){ addChild(name); ofLogVerbose("ofXml") << "creating group " << name; } setTo(name); ofLogVerbose("ofXml") << "group " << name; - for(int i=0;i(parameter); + if(parameter.type() == typeid(ofParameterGroup).name()){ + ofParameterGroup & group = static_cast (parameter); if(setTo(name)){ - for(int i=0;i).name()){ - parameter.cast() = getIntValue(name); - }else if(parameter.type()==typeid(ofParameter).name()){ - parameter.cast() = getFloatValue(name); - }else if(parameter.type()==typeid(ofParameter).name()){ - parameter.cast() = getBoolValue(name); - }else if(parameter.type()==typeid(ofParameter).name()){ - parameter.cast() = getInt64Value(name); - }else if(parameter.type()==typeid(ofParameter).name()){ - parameter.cast() = getValue(name); + if(parameter.type() == typeid(ofParameter ).name()){ + parameter.cast () = getIntValue(name); + }else if(parameter.type() == typeid(ofParameter ).name()){ + parameter.cast () = getFloatValue(name); + }else if(parameter.type() == typeid(ofParameter ).name()){ + parameter.cast () = getBoolValue(name); + }else if(parameter.type() == typeid(ofParameter ).name()){ + parameter.cast () = getInt64Value(name); + }else if(parameter.type() == typeid(ofParameter ).name()){ + parameter.cast () = getValue(name); }else{ parameter.fromString(getValue(name)); } @@ -111,128 +123,123 @@ void ofXml::deserialize(ofAbstractParameter & parameter){ } -int ofXml::getNumChildren() const -{ - if(!element) return 0; +int ofXml::getNumChildren() const{ + if(!element){ + return 0; + } int numberOfChildren = 0; Poco::XML::NodeList *list = element->childNodes(); - for(int i=0; i < (int)list->length(); i++) { - if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE) { + for(unsigned long i=0; i < list->length(); i++){ + if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE){ numberOfChildren++; } } return numberOfChildren; } -int ofXml::getNumChildren(const string& path) const -{ - if(!element) return 0; +int ofXml::getNumChildren(const string& path) const{ + if(!element){ + return 0; + } int numberOfChildren = 0; Poco::XML::NodeList *list = element->childNodes(); - for(int i=0; i < (int)list->length(); i++) { - if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE) { + for(unsigned long i=0; i < list->length(); i++){ + if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE){ string nodeName = list->item(i)->localName(); - if(path.compare(nodeName) == 0) { + if(path.compare(nodeName) == 0){ numberOfChildren++; } } } - + return numberOfChildren; - } -string ofXml::toString() const -{ +string ofXml::toString() const{ ostringstream stream; - + Poco::XML::DOMWriter writer; writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT); - if(document) { - try { + if(document){ + try{ writer.writeNode( stream, getPocoDocument() ); - } catch( exception & e ) { + }catch( exception & e ){ ofLogError("ofXml") << "toString(): " << e.what(); } } else if(element){ element->normalize(); writer.writeNode( stream, element ); } - + string tmp = stream.str(); - + // don't know how else to get rid of the hidden <#text> nodes :/ ofStringReplace(tmp, "<#text>", ""); ofStringReplace(tmp, "", ""); - + return tmp; } -void ofXml::addXml( ofXml& xml, bool copyAll ) { - - Poco::XML::Node *n = 0; - if(copyAll) { +void ofXml::addXml(ofXml& xml, bool copyAll){ + Poco::XML::Node *n = NULL; + if(copyAll){ n = document->importNode(xml.getPocoDocument()->documentElement(), true); - } else { - if(xml.getPocoElement() == 0 || xml.getPocoElement() == xml.getPocoDocument()->documentElement()) { + }else{ + if(xml.getPocoElement() == 0 || xml.getPocoElement() == xml.getPocoDocument()->documentElement()){ n = document->importNode(xml.getPocoDocument()->documentElement(), true); - } else { + }else{ n = document->importNode( xml.getPocoElement(), true); } } // we have an element, i.e. the document has child nodes // or we don't, so append it directly to the document - if( element ) { + if(element){ element->appendChild(n); - } else { + }else{ document->appendChild(n); } - } -bool ofXml::addChild( const string& path ) -{ +bool ofXml::addChild(const string& path){ vector tokens; - - if(path.find('/') != string::npos) { + + if(path.find('/') != string::npos){ tokens = tokenize(path, "/"); } // is this a tokenized tag? - if(tokens.size() > 1) - { + if(tokens.size() > 1){ // don't 'push' down into the new nodes Poco::XML::Element *el = element; - + vector toBeReleased; - - for(int i = 0; i < (int)tokens.size(); i++) - { + + for(std::size_t i = 0; i < tokens.size(); i++){ Poco::XML::Element *pe = getPocoDocument()->createElement(tokens.at(i)); el->appendChild(pe); toBeReleased.push_back(pe); el = pe; } - - if(element) { + + if(element){ element->appendChild(el); - } else { + }else{ element = el; } return true; - - } else { + + }else{ Poco::XML::Element* pe = getPocoDocument()->createElement(path); - - if(element) { + + if(element){ element->appendChild(pe); - } else { + }else{ document->appendChild(pe); element = document->documentElement(); } @@ -240,53 +247,71 @@ bool ofXml::addChild( const string& path ) return true; } -string ofXml::getValue() const -{ - if(element && element->firstChild()->nodeType() == Poco::XML::Node::TEXT_NODE) { - return element->innerText(); - } - return ""; +string ofXml::getValue() const{ + //if we don't have a DOM element, return the default value + if(!element){ + return ""; + } + + // firstChild() may return a NULL pointer + if(NULL == element->firstChild()){ + // return default value in this case + return ""; + } + // no NULL pointer -> save to call nodeType() + if(element->firstChild()->nodeType() == Poco::XML::Node::TEXT_NODE) { + return element->innerText(); + } + return ""; } string ofXml::getValue(const string & path) const{ - return getValue(path, ""); + return getValue (path, ""); } -int ofXml::getIntValue() const{ + +int ofXml::getIntValue() const { return ofToInt(getValue()); } -int ofXml::getIntValue(const string & path) const{ - return getValue(path,0); + +int ofXml::getIntValue(const string & path) const { + return getValue (path, 0); } -float ofXml::getFloatValue() const{ + +float ofXml::getFloatValue() const { return ofToFloat(getValue()); } -float ofXml::getFloatValue(const string & path) const{ - return getValue(path,0.0); + +float ofXml::getFloatValue(const string & path) const { + return getValue (path, 0.0); } -bool ofXml::getBoolValue() const{ + +bool ofXml::getBoolValue() const { return ofToBool(getValue()); } -bool ofXml::getBoolValue(const string & path) const{ - return getValue(path,false); + +bool ofXml::getBoolValue(const string & path) const { + return getValue (path, false); } -int64_t ofXml::getInt64Value() const{ + +int64_t ofXml::getInt64Value() const { return ofToInt64(getValue()); } -int64_t ofXml::getInt64Value(const string & path) const{ - return getValue(path,0); + +int64_t ofXml::getInt64Value(const string & path) const { + return getValue (path, 0); } -bool ofXml::reset() { - if(element) { +bool ofXml::reset(){ + if(element){ element = document->documentElement(); return true; } @@ -294,109 +319,110 @@ bool ofXml::reset() { return false; } -bool ofXml::setToChild(int index) -{ - - if(!element) { - if((Poco::XML::Element*) document->documentElement()->firstChild()) { +bool ofXml::setToChild(unsigned long index){ + if(!element){ + if((Poco::XML::Element*) document->documentElement()->firstChild()){ element = (Poco::XML::Element*) document->documentElement()->firstChild(); - } else { + }else{ ofLogWarning("ofXml") << "setToChild(): no element created yet"; return false; } } - int numberOfChildren = 0; + unsigned long numberOfChildren = 0; Poco::XML::NodeList *list = element->childNodes(); - for(int i=0; i < (int)list->length() && numberOfChildren < index + 1; i++) { - if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE) { - if(numberOfChildren == index) { + for(unsigned long i=0; i < list->length() && numberOfChildren < index + 1; i++){ + if(list->item(i) && list->item(i)->nodeType() == Poco::XML::Node::ELEMENT_NODE){ + if(numberOfChildren == index){ element = (Poco::XML::Element*) list->item(i); return true; } numberOfChildren++; } } - + return false; - } -bool ofXml::setToParent() -{ - if(element->parentNode()) { +bool ofXml::setToParent(){ + if(element->parentNode()){ element = (Poco::XML::Element*) element->parentNode(); - } else { + }else{ ofLogWarning("ofXml") << "setToParent(): current element has no parent"; return false; } return true; - } -bool ofXml::setToParent(int numLevelsUp) { - if(element) { - +bool ofXml::setToParent(int numLevelsUp){ + if(element){ int i = 0; - while( i < numLevelsUp ) { - if(element->parentNode()) { + while( i < numLevelsUp ){ + if(element->parentNode()){ element = (Poco::XML::Element*) element->parentNode(); - } else { + }else{ ofLogWarning("ofXml") << "setToParent(): too many parents: " << numLevelsUp; return false; } i++; } - + return true; } - + ofLogWarning("ofXml") << "setToParent(): no element set yet"; - return false; - + return false; } -bool ofXml::setToSibling() -{ +bool ofXml::setToSibling(){ Poco::XML::Element *node; - if(element) { + if(element){ node = (Poco::XML::Element*) element->nextSibling(); - } else { + }else{ ofLogWarning("ofXml") << "setToSibling() << no element set yet"; return false; } - - // empty space in the XML doc is treated as text nodes. blerg. - while(node && node->nodeType() == Poco::XML::Node::TEXT_NODE) { - node = (Poco::XML::Element*) node->nextSibling(); - } - - if(!node || node->nodeType() == Poco::XML::Node::TEXT_NODE) { - return false; - } - - // we're cool + + /* If we get NULL for node, then we do not have a sibling. + We can only savely check the type on a non-Null node (thus + avoiding NULL-pointer dereferences). Empty space is treated + as a text node and we do not want that. We are also not + interessted in comments. If we find a non-TEXT_NODE or + non-COMMENT_NODE, we do not look further for a sibling. */ + while(NULL != node){ + if((node->nodeType() == Poco::XML::Node::TEXT_NODE) + || (node->nodeType() == Poco::XML::Node::COMMENT_NODE)){ + node = (Poco::XML::Element*) node->nextSibling(); + }else{ + break; + } + } + // make sure we actually got a sibling + if(NULL == node){ + return false; + } + + // we're cool now element = node; return true; } -bool ofXml::setToPrevSibling() -{ +bool ofXml::setToPrevSibling(){ Poco::XML::Element *node; - if(element) { + if(element){ node = (Poco::XML::Element*) element->previousSibling(); - } else { + }else{ ofLogWarning("ofXml") << "setToPrevSibling(): no element set yet"; return false; } - + // empty space in the XML doc is treated as text nodes. blerg. - while(node && node->nodeType() == Poco::XML::Node::TEXT_NODE) { + while(node && node->nodeType() == Poco::XML::Node::TEXT_NODE){ node = (Poco::XML::Element*) node->previousSibling(); } - - if(!node || node->nodeType() == Poco::XML::Node::TEXT_NODE) { + + if(!node || node->nodeType() == Poco::XML::Node::TEXT_NODE){ return false; } @@ -404,17 +430,16 @@ bool ofXml::setToPrevSibling() return true; } -bool ofXml::setValue(const string& path, const string& value) -{ +bool ofXml::setValue(const string& path, const string& value){ Poco::XML::Element *e; - if(element) { + if(element){ e = (Poco::XML::Element*) element->getNodeByPath(path); - } else { + }else{ ofLogWarning("ofXml") << "setValue(): no element set yet"; return false; } - - if(!e) { + + if(!e){ ofLogWarning("ofXml") << "setValue(): path \"" + path + "\" doesn't exist"; return false; } @@ -426,7 +451,7 @@ bool ofXml::setValue(const string& path, const string& value) return true; } - if(e->firstChild()->nodeType() == Poco::XML::Node::TEXT_NODE) { + if(e->firstChild()->nodeType() == Poco::XML::Node::TEXT_NODE){ Poco::XML::Text *node = getPocoDocument()->createTextNode(ofToString(value)); e->replaceChild( (Poco::XML::Node*) node, e->firstChild()); // swap out node->release(); @@ -436,159 +461,143 @@ bool ofXml::setValue(const string& path, const string& value) } } -string ofXml::getAttribute(const string& path) const { - +string ofXml::getAttribute(const string& path) const{ Poco::XML::Node *e; - if(element) { - - if(path.find("[@") == string::npos) { + if(element){ + if(path.find("[@") == string::npos){ // we need to create a proper path string attributePath = "[@" + path + "]"; e = element->getNodeByPath(attributePath); - } else { + }else{ e = element->getNodeByPath(path); } - } else { + }else{ ofLogWarning("ofXml") << "getAttribute(): no element set yet"; return ""; } - - if(e) { + + if(e){ return e->getNodeValue(); // this will be the value of the attribute } return ""; } -bool ofXml::removeAttribute(const string& path) -{ - +bool ofXml::removeAttribute(const string& path){ string attributeName, pathToAttribute; Poco::XML::Element *e; - if(element) { - + if(element){ bool hasPath = false; - // you can pass either /node[@attr] or just attr - if(path.find("[@") != string::npos) - { + if(path.find("[@") != string::npos){ int attrBegin = path.find("[@"); int start = attrBegin + 2; int end = path.find("]", start); attributeName = path.substr( start, end - start ); pathToAttribute = path.substr(0, attrBegin); hasPath = true; - } - else - { + }else{ attributeName = path; } - - if(hasPath) { + + if(hasPath){ e = (Poco::XML::Element*) element->getNodeByPath(pathToAttribute); - } else { + }else{ e = element; } - } else { + }else{ ofLogWarning("ofXml") << "clearAttributes(): no element set yet"; return false; } - - if(e) { + + if(e){ Poco::XML::NamedNodeMap *map = e->attributes(); - - for(int i = 0; i < (int)map->length(); i++) { - if(map->item(i)->nodeName() == attributeName) { + + for(unsigned long i = 0; i < map->length(); i++){ + if(map->item(i)->nodeName() == attributeName){ e->removeAttribute(map->item(i)->nodeName()); } } - + map->release(); return true; } return false; } -bool ofXml::removeAttributes(const string& path) -{ +bool ofXml::removeAttributes(const string& path){ Poco::XML::Element *e; - if(element) { - if(path.find("[@") == string::npos) { + if(element){ + if(path.find("[@") == string::npos){ // we need to create a proper path string attributePath = "[@" + path + "]"; e = (Poco::XML::Element*) element->getNodeByPath(attributePath); - } else { + }else{ e = (Poco::XML::Element*) element->getNodeByPath(path); } - - } else { + }else{ ofLogWarning("ofXml") << "clearAttributes(): no element set yet"; return false; } - - if(e) { + + if(e){ Poco::XML::NamedNodeMap *map = e->attributes(); - - for(int i = 0; i < (int)map->length(); i++) { + + for(unsigned long i = 0; i < map->length(); i++){ e->removeAttribute(map->item(i)->nodeName()); } - + map->release(); return true; } return false; } -bool ofXml::removeAttributes() -{ +bool ofXml::removeAttributes(){ - if(element) { + if(element){ Poco::XML::NamedNodeMap *map = element->attributes(); - - for(int i = 0; i < (int)map->length(); i++) { + + for(unsigned long i = 0; i < map->length(); i++){ element->removeAttribute(map->item(i)->nodeName()); } - + map->release(); return true; } ofLogWarning("ofXml") << "clearAttributes(): no element set yet"; return false; - } -bool ofXml::removeContents() { - if(element && element->hasChildNodes()) - { +bool ofXml::removeContents(){ + if(element && element->hasChildNodes()){ Poco::XML::Node* swap; Poco::XML::Node* n = element->firstChild(); - while(n->nextSibling() != nullptr) - { + while(n->nextSibling() != nullptr){ swap = n->nextSibling(); element->removeChild(n); n = swap; } - + return true; } return false; } -bool ofXml::removeContents(const string& path) { - +bool ofXml::removeContents(const string& path){ Poco::XML::Element *e; - if(element) { + if(element){ e = (Poco::XML::Element*) element->getNodeByPath(path); - } else { + }else{ ofLogWarning("ofXml") << "clearContents(): no element set yet"; return false; } - - if(e) { + + if(e){ Poco::XML::NodeList *list = e->childNodes(); - for( int i = 0; i < (int)list->length(); i++) { + for(unsigned long i = 0; i < list->length(); i++) { element->removeChild(list->item(i)); } list->release(); @@ -600,35 +609,35 @@ bool ofXml::removeContents(const string& path) { void ofXml::clear(){ releaseAll(); - document = new Poco::XML::Document(); // we create this so that they can be merged later - element = document->documentElement(); + document = new Poco::XML::Document(); // we create this so that they can be merged later + element = document->documentElement(); } + void ofXml::releaseAll(){ - if(document) { - document->release(); - document = 0; - } - - element = 0; + if(document){ + document->release(); + document = NULL; + } + element = NULL; } -bool ofXml::remove(const string& path) // works for both attributes and tags -{ - Poco::XML::Node *node; - if(element) { - node = element->getNodeByPath(path); - } else { - ofLogWarning("ofXml") << "remove(): no element set yet"; - return false; - } - - if(node) { - Poco::XML::Node *n = node->parentNode()->removeChild(node); - n->release(); - return true; - } - return false; + +bool ofXml::remove(const string & path){ // works for both attributes and tags + Poco::XML::Node * node; + if(element){ + node = element->getNodeByPath(path); + }else{ + ofLogWarning("ofXml") << "remove(): no element set yet"; + return false; + } + + if(node){ + Poco::XML::Node * n = node->parentNode()->removeChild(node); + n->release(); + return true; + } + return false; } @@ -637,137 +646,119 @@ void ofXml::remove(){ if(parent){ parent->removeChild(element); element->release(); - element = (Poco::XML::Element*)parent; + element = (Poco::XML::Element *)parent; }else{ clear(); } } -bool ofXml::exists(const string& path) const // works for both attributes and tags -{ - Poco::XML::Node *node; - if(element) { - node = element->getNodeByPath(path); - } else { - return false; - } - - if(node) { - return true; - } - return false; + +bool ofXml::exists(const string & path) const{ // works for both attributes and tags + Poco::XML::Node * node; + if(element){ + node = element->getNodeByPath(path); + }else{ + return false; + } + + if(node){ + return true; + } + return false; } -map ofXml::getAttributes() const // works for both attributes and tags -{ - +map ofXml::getAttributes() const{ // works for both attributes and tags map attrMap; - + if(element){ - Poco::AutoPtr attr = element->attributes(); - for( int i = 0; i < (int)attr->length(); i++) { + for(unsigned long i = 0; i < attr->length(); i++){ attrMap[attr->item(i)->nodeName()] = attr->item(i)->nodeValue(); } - } else { + }else{ ofLogWarning("ofXml") << "getAttribute(): no element set"; } - return attrMap; + return attrMap; } -//--------------------------------------------------------- -bool ofXml::setAttribute(const string& path, const string& value) -{ - +bool ofXml::setAttribute(const string& path, const string& value){ + string attributeName, pathToAttribute; bool hasPath = false; // you can pass either /node[@attr] or just attr - if(path.find("[@") != string::npos) - { - int attrBegin = path.find("[@"); - int start = attrBegin + 2; - int end = path.find("]", start); + if(path.find("[@") != string::npos){ + size_t attrBegin = path.find("[@"); + size_t start = attrBegin + 2; + size_t end = path.find("]", start); attributeName = path.substr( start, end - start ); pathToAttribute = path.substr(0, attrBegin); hasPath = true; - } - else - { + }else{ attributeName = path; } - + // we don't have a path to resolve Poco::AutoPtr attr = getPocoDocument()->createAttribute(attributeName); attr->setValue(value); - if(!hasPath) { + if(!hasPath){ Poco::AutoPtr map = element->attributes(); map->setNamedItem(attr); return true; // and we're done } - + // we have a path to resolve Poco::XML::Element* curElement = getPocoElement(pathToAttribute); - - if(!curElement) { // if it doesn't exist - + + if(!curElement){ // if it doesn't exist vector tokens; - - if(path.find('/') != string::npos) { + + if(path.find('/') != string::npos){ tokens = tokenize(pathToAttribute, "/"); } - + // is this a tokenized tag? - if(tokens.size() > 1) - { + if(tokens.size() > 1){ // don't 'push' down into the new nodes curElement = element; - + // find the last existing tag - int lastExistingTag = 0; - + size_t lastExistingTag = 0; + // can't use reverse_iterator b/c accumulate doesn't like it - for(vector::iterator it = tokens.end(); it != tokens.begin(); it--) - { + for(vector::iterator it = tokens.end(); it != tokens.begin(); it--){ string empty = ""; string concat = accumulate(tokens.begin(), it, std::string()); Poco::XML::Element* testElement = getPocoElement(concat); - if(testElement) { + if(testElement){ lastExistingTag++; curElement = testElement; break; } } - + // create all the tags that don't exist - for(int i = lastExistingTag; i < (int)tokens.size(); i++) - { + for(size_t i = lastExistingTag; i < tokens.size(); i++){ Poco::XML::Element *newElement = getPocoDocument()->createElement(tokens.at(i)); curElement->appendChild(newElement); curElement = newElement; - } - + curElement->setAttribute(attributeName, value); return true; - } - else - { + }else{ Poco::XML::Element* testElement = getPocoElement(pathToAttribute); - if(testElement) - { + if(testElement){ curElement = testElement; - } - else - { + }else{ Poco::XML::Element *newElement = getPocoDocument()->createElement(pathToAttribute); curElement->appendChild(newElement); curElement = newElement; } - + curElement->setAttribute(attributeName, value); return true; } @@ -775,126 +766,113 @@ bool ofXml::setAttribute(const string& path, const string& value) return false; } -//--------------------------------------------------------- -bool ofXml::loadFromBuffer( const string& buffer ) -{ - Poco::XML::DOMParser parser; - - // release and nullptr out if we already have a document - if(document) { - document->release(); - } - - try { - document = parser.parseString(buffer); - element = (Poco::XML::Element*) document->firstChild(); - document->normalize(); - return true; - } catch( const Poco::XML::SAXException & e ) { + +bool ofXml::loadFromBuffer(const string & buffer){ + Poco::XML::DOMParser parser; + + // release and null out if we already have a document + if(document){ + document->release(); + } + + try{ + document = parser.parseString(buffer); + element = (Poco::XML::Element *)document->firstChild(); + document->normalize(); + return true; + } + catch(const Poco::XML::SAXException & e){ ofLogError("ofXml") << "parse error: " << e.message(); - document = new Poco::XML::Document; - element = document->documentElement(); - return false; - } catch( const exception & e ) { - short msg = atoi(e.what()); - ofLogError("ofXml") << "parse error: " << DOMErrorMessage(msg); - document = new Poco::XML::Document; - element = document->documentElement(); - return false; - } + document = new Poco::XML::Document; + element = document->documentElement(); + return false; + } + catch(const exception & e){ + short msg = atoi(e.what()); + ofLogError("ofXml") << "parse error: " << DOMErrorMessage(msg); + document = new Poco::XML::Document; + element = document->documentElement(); + return false; + } } -string ofXml::getName() const -{ - if(element) - { - return element->nodeName(); - } - return ""; +string ofXml::getName() const { + if(element){ + return element->nodeName(); + } + return ""; } -bool ofXml::setTo(const string& path) -{ - - if(!element) { +bool ofXml::setTo(const string& path){ + if(!element){ if(document->documentElement()) { element = document->documentElement(); - } else { + }else{ ofLogWarning("ofXml") << "setTo(): empty document"; return false; } } - - + + // one case: we're at the root, but we don't know it yet: - if(element == document->documentElement() && element->nodeName() == path ) { + if(element == document->documentElement() && element->nodeName() == path ){ return true; } - + //ofLogNotice("ofXml") << path << " " << path.find("../"); - + // another: let's go up a little - if( path.find("../") != string::npos) - { - + if(path.find("../") != string::npos){ + Poco::XML::Element* prev = element; Poco::XML::Element* parent = nullptr; - int count = 0; + size_t count = 0; size_t offset; for (offset = path.find("../"); offset != std::string::npos; - offset = path.find("../", offset + 3)) - { - - if(count == 0) { + offset = path.find("../", offset + 3)){ + + if(count == 0){ parent = (Poco::XML::Element*) element->parentNode(); - } else { + }else{ parent = (Poco::XML::Element*) parent->parentNode(); } ++count; } - + //ofLogNotice("ofXml") << (count * 3) << " " << path.size(); - - if( (count * 3) > (int)path.size() - 1 ) { - + + if( (count * 3) > path.size() - 1 ){ element = parent; return true; - - } else if (parent) { - + }else if (parent){ string remainingPath = path.substr((count * 3), path.size() - (count * 3)); - element = (Poco::XML::Element*) parent->getNodeByPath(remainingPath); - if(!element) { + if(!element){ element = prev; ofLogWarning("ofXml") << "setCurrentElement(): passed invalid path \"" << remainingPath << "\""; return false; } - } - else - { + }else{ ofLogWarning("ofXml") << "setCurrentElement(): parent is nullptr."; return false; } - } else if(path.find("//") != string::npos) { - + }else if(path.find("//") != string::npos){ // another: we're looking all over Poco::XML::Element* prev = element; element = (Poco::XML::Element*) document->getNodeByPath(path); - if(!element) { + if(!element){ element = prev; ofLogWarning("ofXml") << "setCurrentElement(): passed invalid path \"" << path << "\""; return false; } - - } else { + }else{ // another: we're actually looking down into the thing :) Poco::XML::Element* prev = element; element = (Poco::XML::Element*) element->getNodeByPath(path); - if(!element) { + if(!element){ element = prev; ofLogWarning("ofXml") << "setCurrentElement(): passed invalid path \"" << path << "\""; return false; @@ -903,112 +881,107 @@ bool ofXml::setTo(const string& path) return true; } -const Poco::XML::Element* ofXml::getPocoElement() const -{ - return element; + +const Poco::XML::Element * ofXml::getPocoElement() const { + return element; } -Poco::XML::Element* ofXml::getPocoElement() -{ + +Poco::XML::Element * ofXml::getPocoElement(){ return element; } -Poco::XML::Element* ofXml::getPocoElement(const string& path) -{ +Poco::XML::Element* ofXml::getPocoElement(const string& path){ string copy = path; // does it have an attribute? just in case - int ind = copy.find("[@"); - if(ind != (int)string::npos) { + std::size_t ind = copy.find("[@"); + if(ind != string::npos){ copy = path.substr(0, ind); } - - if(element) { + + if(element){ return (Poco::XML::Element*) element->getNodeByPath(copy); - } else { + }else{ ofLogWarning("ofXml") << "getPocoElement(): no element to get yet "; return nullptr; } - } -const Poco::XML::Element* ofXml::getPocoElement(const string& path) const -{ +const Poco::XML::Element* ofXml::getPocoElement(const string& path) const{ string copy = path; // does it have an attribute? just in case - int ind = copy.find("[@"); - if(ind != (int)string::npos) { + std::size_t ind = copy.find("[@"); + if(ind != string::npos){ copy = path.substr(0, ind); } - if(element) { + if(element){ return (Poco::XML::Element*) element->getNodeByPath(copy); - } else { + }else{ ofLogWarning("ofXml") << "getPocoElement(): no element to get yet "; return nullptr; } - } -Poco::XML::Document* ofXml::getPocoDocument() { - - return document; -} - -const Poco::XML::Document* ofXml::getPocoDocument() const { - - return document; -} - -string ofXml::DOMErrorMessage(short msg) -{ - switch(msg) { - case 1: - return "INDEX_SIZE_ERR"; - break;/// index or size is negative or greater than allowed value - case 2: - return "DOMSTRING_SIZE_ERR"; /// the specified range of text does not fit into a DOMString (not used) - break; - case 3: - return "HIERARCHY_REQUEST_ERR"; /// a node is inserted somewhere it doesn't belong - break; - case 4: - return "WRONG_DOCUMENT_ERR"; /// a node is used in a different document than the one that created it - break; - case 5: - return "INVALID_CHARACTER_ERR"; /// an invalid character is specified (not used) - break; - case 6: - return "NO_DATA_ALLOWED_ERR"; /// data is specified for a node which does not support data - break; - case 7: - return "NO_MODIFICATION_ALLOWED_ERR"; /// an attempt is made to modify an object where modifications are not allowed - break; - case 8: - return "NOT_FOUND_ERR"; /// an attempt was made to reference a node in a context where it does not exist - break; - case 9: - return "NOT_SUPPORTED_ERR"; /// the implementation does not support the type of object requested - break; - case 10: - return "INUSE_ATTRIBUTE_ERR"; /// an attempt is made to add an attribute that is already in use elsewhere - break; - case 11: - return "INVALID_STATE_ERR"; /// a parameter or an operation is not supported by the underlying object - break; - case 12: - return "SYNTAX_ERR"; /// an invalid or illegal string is specified - break; - case 13: - return "INVALID_MODIFICATION_ERR"; /// an attempt is made to modify the type of the underlying object - break; - case 14: - return "NAMESPACE_ERR"; /// an attempt is made to create or change an object in a way which is incorrect with regard to namespaces - break; - case 15: - return "INVALID_ACCESS_ERR"; /// an attempt is made to use an object that is not or is no longer usable - break; - } - - return "DOM ERROR"; - + +Poco::XML::Document * ofXml::getPocoDocument(){ + return document; +} + + +const Poco::XML::Document * ofXml::getPocoDocument() const { + return document; +} + + +string ofXml::DOMErrorMessage(short msg){ + switch(msg){ + case 1: + return "INDEX_SIZE_ERR"; + break; /// index or size is negative or greater than allowed value + case 2: + return "DOMSTRING_SIZE_ERR"; /// the specified range of text does not fit into a DOMString (not used) + break; + case 3: + return "HIERARCHY_REQUEST_ERR"; /// a node is inserted somewhere it doesn't belong + break; + case 4: + return "WRONG_DOCUMENT_ERR"; /// a node is used in a different document than the one that created it + break; + case 5: + return "INVALID_CHARACTER_ERR"; /// an invalid character is specified (not used) + break; + case 6: + return "NO_DATA_ALLOWED_ERR"; /// data is specified for a node which does not support data + break; + case 7: + return "NO_MODIFICATION_ALLOWED_ERR"; /// an attempt is made to modify an object where modifications are not allowed + break; + case 8: + return "NOT_FOUND_ERR"; /// an attempt was made to reference a node in a context where it does not exist + break; + case 9: + return "NOT_SUPPORTED_ERR"; /// the implementation does not support the type of object requested + break; + case 10: + return "INUSE_ATTRIBUTE_ERR"; /// an attempt is made to add an attribute that is already in use elsewhere + break; + case 11: + return "INVALID_STATE_ERR"; /// a parameter or an operation is not supported by the underlying object + break; + case 12: + return "SYNTAX_ERR"; /// an invalid or illegal string is specified + break; + case 13: + return "INVALID_MODIFICATION_ERR"; /// an attempt is made to modify the type of the underlying object + break; + case 14: + return "NAMESPACE_ERR"; /// an attempt is made to create or change an object in a way which is incorrect with regard to namespaces + break; + case 15: + return "INVALID_ACCESS_ERR"; /// an attempt is made to use an object that is not or is no longer usable + break; + } + + return "DOM ERROR"; } diff --git a/libs/openFrameworks/utils/ofXml.h b/libs/openFrameworks/utils/ofXml.h index 382f6b14cec..fe3045c9c68 100644 --- a/libs/openFrameworks/utils/ofXml.h +++ b/libs/openFrameworks/utils/ofXml.h @@ -1,4 +1,3 @@ - #pragma once #include "ofConstants.h" @@ -25,7 +24,7 @@ #include #include #include -#include +#include #include class ofXml: public ofBaseFileSerializer { @@ -81,7 +80,7 @@ class ofXml: public ofBaseFileSerializer { string getName() const; bool reset(); - bool setToChild(int index); + bool setToChild(unsigned long index); bool setTo(const string& path); bool setToParent(); bool setToParent(int numLevelsUp); @@ -101,16 +100,13 @@ class ofXml: public ofBaseFileSerializer { ////////////////////////////////////////////////////////////////// // a pretty useful tokenization system: - static vector tokenize(const string & str, const string & delim) - { + static vector tokenize(const string & str, const string & delim){ vector tokens; - + size_t p0 = 0, p1 = string::npos; - while(p0 != string::npos) - { + while(p0 != string::npos){ p1 = str.find_first_of(delim, p0); - if(p1 != p0) - { + if(p1 != p0){ string token = str.substr(p0, p1 - p0); tokens.push_back(token); } @@ -120,109 +116,98 @@ class ofXml: public ofBaseFileSerializer { } // templated to be anything - template bool addValue(const string& path, T data=T(), bool createEntirePath = false) - { + template bool addValue(const string& path, T data=T(), bool createEntirePath = false){ string value = ofToString(data); vector tokens; - if(path.find('/') != string::npos) { + if(path.find('/') != string::npos){ tokens = tokenize(path, "/"); } - + // is this a tokenized tag? - if(tokens.size() > 1) - { + if(tokens.size() > 1){ // don't 'push' down into the new nodes Poco::XML::Element* firstElement=nullptr, *lastElement=nullptr; - if(element) { + if(element){ lastElement = element; } - - if(!firstElement) { + + if(!firstElement){ firstElement = lastElement; } - for(int i = 0; i < (int)tokens.size(); i++) - { + for(std::size_t i = 0; i < tokens.size(); i++){ Poco::XML::Element* newElement = getPocoDocument()->createElement(tokens.at(i)); - + //ofLogVerbose("ofxXml") << "addValue(): creating " << newElement->nodeName(); - - if(lastElement) { + + if(lastElement){ lastElement->appendChild(newElement); } - + lastElement = newElement; } - if(value != "") - { - + if(value != ""){ Poco::XML::Text *text = getPocoDocument()->createTextNode(value); try { - lastElement->appendChild( text ); - - } catch ( Poco::XML::DOMException &e ) { + } catch ( Poco::XML::DOMException &e ){ ofLogError("ofxXml") << "addValue(): couldn't set node value: " << DOMErrorMessage(e.code()); return false; } } - - if(!element) { + + if(!element){ element = firstElement; document->appendChild(element); } return true; - } else { - + }else{ Poco::XML::Element *newElement = getPocoDocument()->createElement(path); - - if(value != "") { - + + if(value != ""){ Poco::XML::Text *text = getPocoDocument()->createTextNode(value); try { newElement->appendChild(text); text->release(); - } catch ( Poco::XML::DOMException &e ) { + } catch ( Poco::XML::DOMException &e ){ ofLogError("ofxXml") << "addValue(): couldn't set node value: " << DOMErrorMessage(e.code()); return false; } } - if(element) { + if(element){ element->appendChild(newElement); - } else { + }else{ element = newElement; } - } return true; } // templated to be anything - template T getValue(const string& path, T returnVal=T()) const - { + template T getValue(const string& path, T returnVal=T()) const{ if(element){ if(path == ""){ if(element->firstChild() && element->firstChild()->nodeType() == Poco::XML::Node::TEXT_NODE) { return ofFromString(element->innerText()); - } else { + }else{ ofLogWarning("ofXml") << "getValue(): path \"" << path<< "\" not found when getting value"; return returnVal; // hmm. this could be a problem } - } else { + }else{ Poco::XML::Element *e = (Poco::XML::Element*) element->getNodeByPath(path); - if(e) { + if(e){ return ofFromString(e->innerText()); } } } - + return T(); } @@ -232,16 +217,15 @@ class ofXml: public ofBaseFileSerializer { Poco::XML::Element* getPocoElement(const string& path); const Poco::XML::Element* getPocoElement() const; const Poco::XML::Element* getPocoElement(const string& path) const; - + Poco::XML::Document* getPocoDocument(); const Poco::XML::Document* getPocoDocument() const; - + protected: void releaseAll(); string DOMErrorMessage(short msg); Poco::XML::Document *document; Poco::XML::Element *element; - }; diff --git a/libs/openFrameworks/video/ofAVFoundationPlayer.h b/libs/openFrameworks/video/ofAVFoundationPlayer.h index 514ee110ee5..69bb5e52d13 100644 --- a/libs/openFrameworks/video/ofAVFoundationPlayer.h +++ b/libs/openFrameworks/video/ofAVFoundationPlayer.h @@ -77,6 +77,8 @@ class ofAVFoundationPlayer : public ofBaseVideoPlayer { void nextFrame(); void previousFrame(); + ofAVFoundationPlayer& operator=(ofAVFoundationPlayer other); + #ifdef __OBJC__ ofAVFoundationVideoPlayer * getAVFoundationVideoPlayer(); #else @@ -92,6 +94,7 @@ class ofAVFoundationPlayer : public ofBaseVideoPlayer { bool loadPlayer(string name, bool bAsync); void disposePlayer(); + bool isReady() const; #ifdef __OBJC__ ofAVFoundationVideoPlayer * videoPlayer; @@ -103,7 +106,7 @@ class ofAVFoundationPlayer : public ofBaseVideoPlayer { bool bResetPixels; bool bUpdatePixels; bool bUpdateTexture; - bool bTextureCacheSupported; + bool bUseTextureCache; ofPixels pixels; ofPixelFormat pixelFormat; diff --git a/libs/openFrameworks/video/ofAVFoundationPlayer.mm b/libs/openFrameworks/video/ofAVFoundationPlayer.mm index b6d8818a387..c81dc4910d0 100644 --- a/libs/openFrameworks/video/ofAVFoundationPlayer.mm +++ b/libs/openFrameworks/video/ofAVFoundationPlayer.mm @@ -8,6 +8,10 @@ #import "ofAVFoundationPlayer.h" #import "ofAVFoundationVideoPlayer.h" +#ifdef TARGET_OSX + #include "ofTexture.h" +#endif + //-------------------------------------------------------------- ofAVFoundationPlayer::ofAVFoundationPlayer() { videoPlayer = nullptr; @@ -17,18 +21,32 @@ bResetPixels = false; bUpdatePixels = false; bUpdateTexture = false; - bTextureCacheSupported = false; -#ifdef TARGET_OF_IOS - bTextureCacheSupported = (CVOpenGLESTextureCacheCreate != nullptr); -#endif -#if defined(TARGET_OSX) && defined(MAC_OS_X_VERSION_10_4) - bTextureCacheSupported = true; -#endif + bUseTextureCache = true; } //-------------------------------------------------------------- ofAVFoundationPlayer::~ofAVFoundationPlayer() { - close(); + disposePlayer(); +} + +//-------------------------------------------------------------- +ofAVFoundationPlayer& ofAVFoundationPlayer::operator=(ofAVFoundationPlayer other) +{ + // clear pixels + pixels.clear(); + videoTexture.clear(); + + // get rid of the textures + killTextureCache(); + + bFrameNew = false; + bResetPixels = false; + bUpdatePixels = false; + bUpdateTexture = false; + bUseTextureCache = true; + + std::swap(videoPlayer, other.videoPlayer); + return *this; } //-------------------------------------------------------------- @@ -43,57 +61,49 @@ //-------------------------------------------------------------- bool ofAVFoundationPlayer::loadPlayer(string name, bool bAsync) { - - // dispose videoplayer, clear pixels, clear texture + if( ofGetUsingArbTex() == false ){ + killTextureCache(); + bUseTextureCache = false; + } + + NSString * videoPath = [NSString stringWithUTF8String:name.c_str()]; + NSString * videoLocalPath = [NSString stringWithUTF8String:ofToDataPath(name).c_str()]; + + BOOL bStream = NO; + + bStream = bStream || (ofIsStringInString(name, "http://")); + bStream = bStream || (ofIsStringInString(name, "https://")); + bStream = bStream || (ofIsStringInString(name, "rtsp://")); + + NSURL * url = nil; + if(bStream == YES) { + url = [NSURL URLWithString:videoPath]; + } else { + url = [NSURL fileURLWithPath:videoLocalPath]; + } + + bFrameNew = false; + bResetPixels = true; + bUpdatePixels = true; + bUpdateTexture = true; + + // reuse videoplayer if(videoPlayer != nullptr) { - - pixels.clear(); - videoTexture.clear(); - - // dispose videoplayer - disposePlayer(); - - if (_videoTextureRef != nullptr) { - killTexture(); - } - - videoPlayer = nullptr; + // use existing player + return [videoPlayer loadWithURL:url async:bAsync]; } - bFrameNew = false; - // create a new player videoPlayer = [[ofAVFoundationVideoPlayer alloc] init]; [videoPlayer setWillBeUpdatedExternally:YES]; - - - NSString * videoPath = [NSString stringWithUTF8String:name.c_str()]; - NSString * videoLocalPath = [NSString stringWithUTF8String:ofToDataPath(name).c_str()]; - - BOOL bStream = NO; - - bStream = bStream || (ofIsStringInString(name, "http://")); - bStream = bStream || (ofIsStringInString(name, "https://")); - bStream = bStream || (ofIsStringInString(name, "rtsp://")); - - NSURL * url = nil; - if(bStream == YES) { - url = [NSURL URLWithString:videoPath]; - } else { - url = [NSURL fileURLWithPath:videoLocalPath]; - } - bool bLoaded = [videoPlayer loadWithURL:url async:bAsync]; - bResetPixels = true; - bUpdatePixels = true; - bUpdateTexture = true; - - bool bCreateTextureCache = true; - bCreateTextureCache = bCreateTextureCache && (bTextureCacheSupported == true); - bCreateTextureCache = bCreateTextureCache && (_videoTextureCache == nullptr); - + pixels.clear(); + videoTexture.clear(); + + bool bCreateTextureCache = bUseTextureCache && (_videoTextureCache == nullptr); + if(bCreateTextureCache == true) { CVReturn err; @@ -128,27 +138,43 @@ } } + if( bAsync == false ){ + pixels.allocate(getWidth(), getHeight(), getPixelFormat()); + } + return bLoaded; } //-------------------------------------------------------------- void ofAVFoundationPlayer::disposePlayer() { - if (videoPlayer == nullptr) - return; - - // pause player, stop updates - [videoPlayer pause]; + if (videoPlayer != nullptr) { - // dispose videoplayer - __block ofAVFoundationVideoPlayer *currentPlayer = videoPlayer; + // clear pixels + pixels.clear(); + videoTexture.clear(); + + // dispose videoplayer + __block ofAVFoundationVideoPlayer *currentPlayer = videoPlayer; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + @autoreleasepool { + [currentPlayer unloadVideo]; // synchronious call to unload video + [currentPlayer autorelease]; // release + } + }); + + videoPlayer = nullptr; + } + + // get rid of the textures + killTextureCache(); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - - @autoreleasepool { - [currentPlayer autorelease]; - } - }); + + bFrameNew = false; + bResetPixels = false; + bUpdatePixels = false; + bUpdateTexture = false; + bUseTextureCache = true; } //-------------------------------------------------------------- @@ -156,23 +182,16 @@ if(videoPlayer != nullptr) { pixels.clear(); - videoTexture.clear(); - - disposePlayer(); - - videoPlayer = nullptr; - } - - // in any case get rid of the textures - if(bTextureCacheSupported == true) { - killTextureCache(); + + [videoPlayer close]; } bFrameNew = false; bResetPixels = false; bUpdatePixels = false; bUpdateTexture = false; + bUseTextureCache = true; } //-------------------------------------------------------------- @@ -206,7 +225,7 @@ bFrameNew = false; // default. - if(!isLoaded()) { + if(!isLoaded() || !isReady()) { return; } @@ -239,8 +258,14 @@ } void ofAVFoundationPlayer::draw(float x, float y, float w, float h) { - if(videoPlayer != nullptr) { - getTexturePtr()->draw(x, y, w, h); + if(isLoaded() && isReady()) { + + ofTexture * texturePtr = getTexturePtr(); + if( texturePtr != NULL ){ + if( texturePtr->isAllocated() ){ + texturePtr->draw(x, y, w, h); + } + } } } @@ -277,7 +302,7 @@ } ofPixels & ofAVFoundationPlayer::getPixels() { - if(isLoaded() == false) { + if(isLoaded() == false || pixels.size() == 0) { ofLogError("ofAVFoundationPlayer") << "getPixels(): Returning pixels that may be unallocated. Make sure to initialize the video player before calling getPixels."; return pixels; } @@ -357,8 +382,12 @@ //-------------------------------------------------------------- ofTexture * ofAVFoundationPlayer::getTexturePtr() { - - if(isLoaded() == false) { + + if( bUseTextureCache == false ){ + return NULL; + } + + if(isLoaded() == false || isReady() == false) { return &videoTexture; } @@ -366,28 +395,7 @@ return &videoTexture; } - if(bTextureCacheSupported == true) { - - initTextureCache(); - - } else { - - /** - * no video texture cache. - * load texture from pixels. - * this method is the slower alternative. - */ - - int maxTextureSize = 0; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - - if(getWidth() > maxTextureSize || getHeight() > maxTextureSize) { - ofLogWarning("ofAVFoundationPlayer") << "getTexturePtr(): " << getWidth() << "x" << getHeight() << " video image is bigger then max supported texture size " << maxTextureSize << "."; - return nullptr; - } - - videoTexture.loadData(getPixels()); - } + initTextureCache(); bUpdateTexture = false; @@ -396,7 +404,11 @@ //-------------------------------------------------------------- texture cache void ofAVFoundationPlayer::initTextureCache() { - + //just in case - we return here if we shouldn't be using a texture cache + if( bUseTextureCache == false ){ + return; + } + CVImageBufferRef imageBuffer = [videoPlayer getCurrentFrame]; if(imageBuffer == nil) { return; @@ -569,6 +581,15 @@ return false; } + return [videoPlayer isLoaded]; +} + +//-------------------------------------------------------------- +bool ofAVFoundationPlayer::isReady() const { + if(videoPlayer == nullptr) { + return false; + } + return [videoPlayer isReady]; } diff --git a/libs/openFrameworks/video/ofAVFoundationVideoPlayer.h b/libs/openFrameworks/video/ofAVFoundationVideoPlayer.h index 1c4a4d77562..7e57707b129 100644 --- a/libs/openFrameworks/video/ofAVFoundationVideoPlayer.h +++ b/libs/openFrameworks/video/ofAVFoundationVideoPlayer.h @@ -19,6 +19,9 @@ #define TARGET_OSX #endif + +#define USE_VIDEO_OUTPUT (defined(MAC_OS_X_VERSION_10_8) || defined(iOS6)) + // so we are independend from oF in this class typedef enum _playerLoopType{ LOOP_NONE=0x01, @@ -28,12 +31,23 @@ typedef enum _playerLoopType{ //---------------------------------------------------------- video player. -@interface ofAVFoundationVideoPlayer : NSObject { +@interface ofAVFoundationVideoPlayer : NSObject { AVPlayer * _player; AVAsset * _asset; AVPlayerItem * _playerItem; + + AVAssetReader * _assetReader; + AVAssetReaderTrackOutput * _assetReaderVideoTrackOutput; + AVAssetReaderTrackOutput * _assetReaderAudioTrackOutput; + +#if USE_VIDEO_OUTPUT + CMVideoFormatDescriptionRef _videoInfo; + AVPlayerItemVideoOutput * _videoOutput; +#endif + + id timeObserver; CMSampleBufferRef videoSampleBuffer; @@ -66,15 +80,30 @@ typedef enum _playerLoopType{ BOOL bSeeking; BOOL bSampleVideo; // default to YES BOOL bSampleAudio; // default to NO + BOOL bIsUnloaded; + + NSLock* asyncLock; + NSCondition* deallocCond; } @property (nonatomic, retain) AVPlayer * player; @property (nonatomic, retain) AVAsset * asset; @property (nonatomic, retain) AVPlayerItem * playerItem; + +@property (nonatomic, retain) AVAssetReader * assetReader; +@property (nonatomic, retain) AVAssetReaderTrackOutput * assetReaderVideoTrackOutput; +@property (nonatomic, retain) AVAssetReaderTrackOutput * assetReaderAudioTrackOutput; + +#if USE_VIDEO_OUTPUT +@property (nonatomic, retain) AVPlayerItemVideoOutput *videoOutput; +#endif + + - (BOOL)loadWithFile:(NSString*)file async:(BOOL)bAsync; - (BOOL)loadWithPath:(NSString*)path async:(BOOL)bAsync; - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync; +- (void)unloadVideoAsync; - (void)unloadVideo; - (void)update; @@ -91,6 +120,7 @@ typedef enum _playerLoopType{ - (void)seekToTime:(CMTime)time withTolerance:(CMTime)tolerance; - (BOOL)isReady; +- (BOOL)isLoaded; - (BOOL)isPlaying; - (BOOL)isNewFrame; - (BOOL)isFinished; @@ -99,6 +129,7 @@ typedef enum _playerLoopType{ - (void)setEnableAudioSampling:(BOOL)value; - (void)setSynchSampleTime:(CMTime)time; - (void)setSynchSampleTimeInSec:(double)time; + - (CMTime)getVideoSampleTime; - (double)getVideoSampleTimeInSec; - (CMTime)getAudioSampleTime; @@ -116,6 +147,7 @@ typedef enum _playerLoopType{ - (int)getDurationInFrames; - (int)getCurrentFrameNum; - (float)getFrameRate; + - (void)setFrame:(int)frame; - (void)setPosition:(float)position; - (float)getPosition; @@ -128,5 +160,6 @@ typedef enum _playerLoopType{ - (void)setAutoplay:(BOOL)bAutoplay; - (BOOL)getAutoplay; - (void)setWillBeUpdatedExternally:(BOOL)value; +- (void)close; @end diff --git a/libs/openFrameworks/video/ofAVFoundationVideoPlayer.m b/libs/openFrameworks/video/ofAVFoundationVideoPlayer.m index b4ea5b2ff28..82c33b15cf5 100644 --- a/libs/openFrameworks/video/ofAVFoundationVideoPlayer.m +++ b/libs/openFrameworks/video/ofAVFoundationVideoPlayer.m @@ -8,51 +8,29 @@ #define IS_OS_6_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) -#define USE_VIDEO_OUTPUT (defined(MAC_OS_X_VERSION_10_8) || defined(iOS6)) + static NSString * const kTracksKey = @"tracks"; -static NSString * const kPlayableKey = @"playable"; static NSString * const kStatusKey = @"status"; static NSString * const kRateKey = @"rate"; -static NSString * const kCurrentItemKey = @"currentItem"; - -@interface ofAVFoundationVideoPlayer () -{ - AVAssetReader * _assetReader; - AVAssetReaderTrackOutput * _assetReaderVideoTrackOutput; - AVAssetReaderTrackOutput * _assetReaderAudioTrackOutput; - - CMVideoFormatDescriptionRef _videoInfo; - dispatch_queue_t _myVideoOutputQueue; -} - -@property (nonatomic, retain) AVAssetReader * assetReader; -@property (nonatomic, retain) AVAssetReaderTrackOutput * assetReaderVideoTrackOutput; -@property (nonatomic, retain) AVAssetReaderTrackOutput * assetReaderAudioTrackOutput; - -#if USE_VIDEO_OUTPUT -@property (nonatomic, retain) AVPlayerItemVideoOutput *videoOutput; -#endif - -@end - - //---------------------------------------------------------- video player. @implementation ofAVFoundationVideoPlayer @synthesize player = _player; +@synthesize asset = _asset; @synthesize playerItem = _playerItem; @synthesize assetReader = _assetReader; @synthesize assetReaderVideoTrackOutput = _assetReaderVideoTrackOutput; @synthesize assetReaderAudioTrackOutput = _assetReaderAudioTrackOutput; #if USE_VIDEO_OUTPUT -@synthesize videoOutput; +@synthesize videoOutput = _videoOutput; #endif -static const NSString * ItemStatusContext; +static const void *ItemStatusContext = &ItemStatusContext; +static const void *PlayerRateContext = &ItemStatusContext; - (id)init { @@ -60,25 +38,18 @@ - (id)init { if(self) { // create avplayer - self.player = [[[AVPlayer alloc] init] autorelease]; - - [_player addObserver:self - forKeyPath:kRateKey - options:NSKeyValueObservingOptionNew - context:nil]; + _player = nil; - - // create videooutput queue - _myVideoOutputQueue = dispatch_queue_create(NULL, NULL); + asyncLock = [[NSLock alloc] init]; + deallocCond = nil; #if USE_VIDEO_OUTPUT // create videooutput - [self createVideoOutput]; + _videoOutput = nil; + _videoInfo = nil; #endif - - _videoInfo = nil; timeObserver = nil; videoSampleBuffer = nil; @@ -108,6 +79,7 @@ - (id)init { loop = LOOP_NONE; bSeeking = NO; bSampleVideo = YES; + bIsUnloaded = NO; // do not sample audio by default // we are lacking interfaces for audiodata @@ -117,21 +89,21 @@ - (id)init { } #if USE_VIDEO_OUTPUT -- (void)createVideoOutput { +- (void)createVideoOutput +{ #ifdef TARGET_IOS NSDictionary *pixBuffAttributes = @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}; #elif defined(TARGET_OSX) NSDictionary *pixBuffAttributes = @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32ARGB)}; #endif - self.videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:pixBuffAttributes]; + self.videoOutput = [[[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:pixBuffAttributes] autorelease]; if (!self.videoOutput) { NSLog(@"error creating video output"); return; } self.videoOutput.suppressesPlayerRendering = YES; - [self.videoOutput setDelegate:self queue:_myVideoOutputQueue]; } #endif @@ -139,25 +111,22 @@ - (void)createVideoOutput { //---------------------------------------------------------- cleanup / dispose. - (void)dealloc { - // unload current video - [self unloadVideo]; - - // destroy player - if(self.player != nil) { - [_player removeObserver:self forKeyPath:kRateKey]; - - self.player = nil; - [_player release]; + if (_player != nil){ + [self unloadVideo]; } -#if USE_VIDEO_OUTPUT - if (self.videoOutput != nil) { - self.videoOutput = nil; - } -#endif + [asyncLock lock]; + [asyncLock unlock]; + + // release locks + [asyncLock autorelease]; + + if (deallocCond != nil) { + [deallocCond release]; + deallocCond = nil; + } - dispatch_release(_myVideoOutputQueue); [super dealloc]; } @@ -180,16 +149,27 @@ - (BOOL)loadWithPath:(NSString*)path async:(BOOL)bAsync{ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { - [self unloadVideo]; // unload video if one is already loaded. - NSDictionary *options = @{(id)AVURLAssetPreferPreciseDurationAndTimingKey:@(YES)}; - self.asset = [AVURLAsset URLAssetWithURL:url options:options]; + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:options]; - if(self.asset == nil) { + if(asset == nil) { NSLog(@"error loading asset: %@", [url description]); return NO; } + + // store state + BOOL _bReady = bReady; + BOOL _bLoaded = bLoaded; + BOOL _bPlayStateBeforeLoad = bPlayStateBeforeLoad; + + // set internal state + bIsUnloaded = NO; + bReady = NO; + bLoaded = NO; + bPlayStateBeforeLoad = NO; + + // going to load dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_queue_t queue; if(bAsync == YES){ @@ -199,22 +179,31 @@ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { } dispatch_async(queue, ^{ - [self.asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:kTracksKey] completionHandler:^{ + [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:kTracksKey] completionHandler:^{ + NSError * error = nil; - AVKeyValueStatus status = [self.asset statusOfValueForKey:kTracksKey error:&error]; + AVKeyValueStatus status = [asset statusOfValueForKey:kTracksKey error:&error]; if(status != AVKeyValueStatusLoaded) { NSLog(@"error loading asset tracks: %@", [error localizedDescription]); + // reset + bReady = _bReady; + bLoaded = _bLoaded; + bPlayStateBeforeLoad = _bPlayStateBeforeLoad; if(bAsync == NO){ dispatch_semaphore_signal(sema); } return; } - duration = [self.asset duration]; + CMTime _duration = [asset duration]; - if(CMTimeCompare(duration, kCMTimeZero) == 0) { + if(CMTimeCompare(_duration, kCMTimeZero) == 0) { NSLog(@"track loaded with zero duration."); + // reset + bReady = _bReady; + bLoaded = _bLoaded; + bPlayStateBeforeLoad = _bPlayStateBeforeLoad; if(bAsync == NO){ dispatch_semaphore_signal(sema); } @@ -224,32 +213,67 @@ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { // TODO // why not reading infinite media? // how about playing back HLS streams? - if(isfinite([self getDurationInSec]) == NO) { + if(isfinite(CMTimeGetSeconds(duration)) == NO) { NSLog(@"track loaded with infinite duration."); + // reset + bReady = _bReady; + bLoaded = _bLoaded; + bPlayStateBeforeLoad = _bPlayStateBeforeLoad; if(bAsync == NO){ dispatch_semaphore_signal(sema); } return; } - BOOL bOk = [self createAssetReaderWithTimeRange:CMTimeRangeMake(kCMTimeZero, duration)]; - if(bOk == NO) { - NSLog(@"problem with creating asset reader."); + NSArray * videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; + if([videoTracks count] == 0) { + NSLog(@"no video tracks found."); + // reset + bReady = _bReady; + bLoaded = _bLoaded; + bPlayStateBeforeLoad = _bPlayStateBeforeLoad; if(bAsync == NO){ dispatch_semaphore_signal(sema); } return; } - NSArray * videoTracks = [self.asset tracksWithMediaType:AVMediaTypeVideo]; - if([videoTracks count] == 0) { - NSLog(@"no video tracks found."); + //------------------------------------------------------------ + //------------------------------------------------------------ use asset + // good to go + [asyncLock lock]; + + if (bIsUnloaded) { + // player was unloaded before we could load everting + bIsUnloaded = NO; + if(bAsync == NO){ + dispatch_semaphore_signal(sema); + } + [asyncLock unlock]; + return; + } + + // clean up + [self unloadVideoAsync]; // unload video if one is already loaded. + + bIsUnloaded = NO; + + // set asset + self.asset = asset; + duration = _duration; + + // create asset reader + BOOL bOk = [self createAssetReaderWithTimeRange:CMTimeRangeMake(kCMTimeZero, duration)]; + if(bOk == NO) { + NSLog(@"problem with creating asset reader."); if(bAsync == NO){ dispatch_semaphore_signal(sema); } + [asyncLock unlock]; return; } + AVAssetTrack * videoTrack = [videoTracks objectAtIndex:0]; frameRate = videoTrack.nominalFrameRate; videoWidth = [videoTrack naturalSize].width; @@ -257,57 +281,83 @@ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { NSLog(@"video loaded at %li x %li @ %f fps", (long)videoWidth, (long)videoHeight, frameRate); - currentTime = CMTimeMakeWithSeconds((1.0/frameRate), NSEC_PER_SEC);//kCMTimeZero; +// currentTime = CMTimeMakeWithSeconds((1.0/frameRate), NSEC_PER_SEC);//kCMTimeZero; + currentTime = CMTimeMakeWithSeconds(0.0, NSEC_PER_SEC);//kCMTimeZero; //------------------------------------------------------------ create player item. - self.playerItem = [AVPlayerItem playerItemWithAsset:self.asset]; + AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:self.asset]; - if (self.playerItem) { - - [self.playerItem addObserver:self - forKeyPath:kStatusKey - options:0 - context:&ItemStatusContext]; - - NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter]; - [notificationCenter addObserver:self - selector:@selector(playerItemDidReachEnd) - name:AVPlayerItemDidPlayToEndTimeNotification - object:self.playerItem]; - - - [notificationCenter addObserver:self - selector:@selector(playerItemDidStall) - name:AVPlayerItemPlaybackStalledNotification - object:self.playerItem]; - -#if USE_VIDEO_OUTPUT - // safety - if (self.videoOutput == nil) { - [self createVideoOutput]; + if (!playerItem) { + NSLog(@"could not create AVPlayerItem"); + if(bAsync == NO){ + dispatch_semaphore_signal(sema); } - - // add video output - [self.playerItem addOutput:self.videoOutput]; + [asyncLock unlock]; + return; + } + + //------------------------------------------------------------ player item. + self.playerItem = playerItem; + [self.playerItem addObserver:self + forKeyPath:kStatusKey + options:0 + context:&ItemStatusContext]; + + NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(playerItemDidReachEnd) + name:AVPlayerItemDidPlayToEndTimeNotification + object:self.playerItem]; + + //AVPlayerItemPlaybackStalledNotification only exists from OS X 10.9 or iOS 6.0 and up +#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000) + [notificationCenter addObserver:self + selector:@selector(playerItemDidStall) + name:AVPlayerItemPlaybackStalledNotification + object:self.playerItem]; #endif - - // set playerItem - [_player replaceCurrentItemWithPlayerItem:self.playerItem]; - - // add timeobserver? - [self addTimeObserverToPlayer]; - - // loaded - bLoaded = true; - - } else { - NSLog(@"could not create AVPlayerItem"); + +#if USE_VIDEO_OUTPUT + // safety + if (self.videoOutput == nil) { + [self createVideoOutput]; + } + + // add video output + [self.playerItem addOutput:self.videoOutput]; +#endif + + + //------------------------------------------------------------ recreate player. + // destroy player if any - should never be the case!! + if(_player != nil) { + [self removeTimeObserverFromPlayer]; + [self.player removeObserver:self forKeyPath:kRateKey context:&PlayerRateContext]; + self.player = nil; + [_player release]; } + // create new player + _player = [[AVPlayer playerWithPlayerItem:self.playerItem] retain]; + [self.player addObserver:self + forKeyPath:kRateKey + options:NSKeyValueObservingOptionNew + context:&PlayerRateContext]; + // add timeobserver? + [self addTimeObserverToPlayer]; + + _player.volume = volume; + + // loaded + bLoaded = true; + if(bAsync == NO){ dispatch_semaphore_signal(sema); } + + [asyncLock unlock]; + }]; }); @@ -315,7 +365,6 @@ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { if(bAsync == NO){ dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); - return bLoaded; } else { dispatch_release(sema); @@ -324,14 +373,209 @@ - (BOOL)loadWithURL:(NSURL*)url async:(BOOL)bAsync { } -#pragma mark - AVPlayerItemOutputPullDelegate +#pragma mark - unload video +- (void)unloadVideoAsync { + + bIsUnloaded = YES; + bReady = NO; + bLoaded = NO; +// bPlayStateBeforeLoad = NO; + bUpdateFirstFrame = YES; + bNewFrame = NO; + bPlaying = NO; + bFinished = NO; + bWasPlayingBackwards = NO; + + videoSampleTime = kCMTimeNegativeInfinity; + audioSampleTime = kCMTimeNegativeInfinity; + synchSampleTime = kCMTimeInvalid; + duration = kCMTimeZero; + currentTime = kCMTimeZero; + + videoWidth = 0; + videoHeight = 0; + + + // a reference to all the variables for the block + __block AVAsset* currentAsset = _asset; + __block AVAssetReader* currentReader = _assetReader; + __block AVAssetReaderTrackOutput* currentVideoTrack = _assetReaderVideoTrackOutput; + __block AVAssetReaderTrackOutput* currentAudioTrack = _assetReaderAudioTrackOutput; + __block AVPlayerItem* currentItem = _playerItem; + __block AVPlayer* currentPlayer = _player; + __block id currentTimeObserver = timeObserver; + + __block CMSampleBufferRef currentVideoSampleBuffer = videoSampleBuffer; + __block CMSampleBufferRef currentAudioSampleBuffer = audioSampleBuffer; + +#if USE_VIDEO_OUTPUT + __block AVPlayerItemVideoOutput* currentVideoOutput = _videoOutput; + __block CMVideoFormatDescriptionRef currentVideoInfo = _videoInfo; + + _videoOutput = nil; + self.videoOutput = nil; + + _videoInfo = nil; +#endif + + // set all to nil + // cleanup happens in the block + _asset = nil; + self.asset = nil; + + _assetReader = nil; + self.assetReader = nil; + + _assetReaderVideoTrackOutput = nil; + self.assetReaderVideoTrackOutput = nil; + + _assetReaderAudioTrackOutput = nil; + self.assetReaderAudioTrackOutput = nil; + + _playerItem = nil; + self.playerItem = nil; + + _player = nil; + self.player = nil; + timeObserver = nil; + + videoSampleBuffer = nil; + audioSampleBuffer = nil; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + @autoreleasepool { + + [asyncLock lock]; + + // relase assetreader + if (currentReader != nil) { + [currentReader cancelReading]; + [currentReader autorelease]; + currentReader = nil; + + if (currentVideoTrack != nil) { + [currentVideoTrack autorelease]; + currentVideoTrack = nil; + } + + if (currentAudioTrack != nil) { + [currentAudioTrack autorelease]; + currentAudioTrack = nil; + } + } + + // release asset + if (currentAsset != nil) { + [currentAsset cancelLoading]; + [currentAsset autorelease]; + currentAsset = nil; + } + + + // release current player item + if(currentItem != nil) { + + [currentItem cancelPendingSeeks]; + [currentItem removeObserver:self forKeyPath:kStatusKey context:&ItemStatusContext]; + + NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter removeObserver:self + name:AVPlayerItemDidPlayToEndTimeNotification + object:currentItem]; + + //AVPlayerItemPlaybackStalledNotification only exists from OS X 10.9 or iOS 6.0 and up +#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000) + [notificationCenter removeObserver:self + name:AVPlayerItemPlaybackStalledNotification + object:currentItem]; +#endif + +#if USE_VIDEO_OUTPUT + // remove output + [currentItem removeOutput:currentVideoOutput]; + + // release videouOutput + if (currentVideoOutput != nil) { + [currentVideoOutput autorelease]; + currentVideoOutput = nil; + } + + // destroy video info + if (currentVideoInfo != nil) { + CFRelease(currentVideoInfo); + currentVideoInfo = nil; + } +#endif + + [currentItem autorelease]; + currentItem = nil; + } + + + // destroy current player + if (currentPlayer != nil) { + [currentPlayer removeObserver:self forKeyPath:kRateKey context:&PlayerRateContext]; + + if (currentTimeObserver != nil) { + [currentPlayer removeTimeObserver:currentTimeObserver]; + [currentTimeObserver autorelease]; + currentTimeObserver = nil; + } + + [currentPlayer autorelease]; + currentPlayer = nil; + } + + + if(currentVideoSampleBuffer) { + CFRelease(currentVideoSampleBuffer); + currentVideoSampleBuffer = nil; + } + + if(currentAudioSampleBuffer) { + CFRelease(currentAudioSampleBuffer); + currentAudioSampleBuffer = nil; + } + + [asyncLock unlock]; + + if (deallocCond != nil) { + [deallocCond lock]; + [deallocCond signal]; + [deallocCond unlock]; + } + } + }); + +} + +- (void)unloadVideo +{ + // create a condition + deallocCond = [[NSCondition alloc] init]; + [deallocCond lock]; + + // unload current video + [self unloadVideoAsync]; + + // wait for unloadVideoAsync to finish + [deallocCond wait]; + [deallocCond unlock]; + + [deallocCond release]; + deallocCond = nil; +} -- (void)outputMediaDataWillChange:(AVPlayerItemOutput *)sender +- (void)close { - NSLog(@"outputMediaDataWillChange"); + [asyncLock lock]; + [self unloadVideoAsync]; + [asyncLock unlock]; } +#pragma mark - - (BOOL)createAssetReaderWithTimeRange:(CMTimeRange)timeRange { videoSampleTime = videoSampleTimePrev = kCMTimeNegativeInfinity; @@ -459,92 +703,60 @@ - (BOOL)createAssetReaderWithTimeRange:(CMTimeRange)timeRange { } - - -- (void)unloadVideo { - - bReady = NO; - bLoaded = NO; - bPlayStateBeforeLoad = NO; - bUpdateFirstFrame = YES; - bNewFrame = NO; - bPlaying = NO; - bFinished = NO; - bWasPlayingBackwards = NO; - - videoSampleTime = kCMTimeNegativeInfinity; - audioSampleTime = kCMTimeNegativeInfinity; - synchSampleTime = kCMTimeInvalid; - duration = kCMTimeZero; - currentTime = kCMTimeZero; - - videoWidth = 0; - videoHeight = 0; - - if(self.playerItem != nil) { - [self.playerItem removeObserver:self forKeyPath:kStatusKey]; - - NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter]; - [notificationCenter removeObserver:self - name:AVPlayerItemDidPlayToEndTimeNotification - object:self.playerItem]; - [notificationCenter removeObserver:self - name:AVPlayerItemPlaybackStalledNotification - object:self.playerItem]; - - self.playerItem = nil; - } - - - if(videoSampleBuffer) { - CFRelease(videoSampleBuffer); - videoSampleBuffer = nil; - } - - if(audioSampleBuffer) { - CFRelease(audioSampleBuffer); - audioSampleBuffer = nil; - } - - [self removeTimeObserverFromPlayer]; - - // destroy video info - if (_videoInfo) { - CFRelease(_videoInfo); - } -} - //---------------------------------------------------------- player callbacks. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if(context == &ItemStatusContext) { - dispatch_async(dispatch_get_main_queue(), ^{ - bReady = true; - - [self update]; // update as soon is ready so pixels are loaded. - [self setVolume:volume]; // set volume for current video. + + if (object == self.playerItem) { - if(bAutoPlayOnLoad || bPlayStateBeforeLoad) { - [self play]; + if ([self.playerItem status] == AVPlayerItemStatusReadyToPlay) { + + if (bReady) { + return; + } + + bReady = true; + + [self setVolume:volume]; // set volume for current video. + if(bAutoPlayOnLoad || bPlayStateBeforeLoad) { + [self play]; + } + + [self update]; // update as soon is ready so pixels are loaded. + + + } else if ([self.playerItem status] == AVPlayerItemStatusUnknown) { + NSLog(@"AVPlayerItemStatusUnknown"); + } else if ([self.playerItem status] == AVPlayerItemStatusFailed) { + NSLog(@"AVPlayerItemStatusFailed"); + } else { + NSLog(@"AVPlayerItem: such status: %ld", (long)[self.playerItem status]); } - }); - return; - } - - if(![self isReady]) { + + } else { + // ignore other objects + } + return; - } - - BOOL b1 = _player != nil; - BOOL b2 = object == _player; - BOOL b3 = [keyPath isEqualToString:kRateKey]; - - if(b1 && b2 && b3) { - float rate = [[change objectForKey:@"new"] floatValue]; - bPlaying = rate != 0; + } else if (context == &PlayerRateContext) { + + if (object == self.player) { + + if (bReady && + [keyPath isEqualToString:kRateKey]) + { + float rate = [[change objectForKey:@"new"] floatValue]; + bPlaying = (rate != 0); + } + } else { + // ignore other object + } + return; } + // push it up the observer chain [super observeValueForKeyPath:keyPath ofObject:object change:change @@ -597,7 +809,7 @@ - (void)update { * video is not yet loaded, * video is finished playing. */ - if(![self isReady] || [self isFinished]) { + if(!bReady || bFinished) { bNewFrame = NO; return; } @@ -622,13 +834,13 @@ - (void)update { #endif } -- (void)updateFromVideoOutput { #if USE_VIDEO_OUTPUT +- (void)updateFromVideoOutput { OSStatus err = noErr; // get time from player CMTime time = [_player currentTime]; - + if ([self.videoOutput hasNewPixelBufferForItemTime:time]) { bNewFrame = YES; @@ -645,8 +857,10 @@ - (void)updateFromVideoOutput { err = CMVideoFormatDescriptionCreateForImageBuffer(NULL, buffer, &_videoInfo); } if (err) { - NSLog(@"Error at CMVideoFormatDescriptionCreateForImageBuffer %d", err); + NSLog(@"Error at CMVideoFormatDescriptionCreateForImageBuffer %ld", (long)err); bNewFrame = NO; + // release temp buffer + CVBufferRelease(buffer); return; } @@ -674,11 +888,16 @@ - (void)updateFromVideoOutput { &sampleTimingInfo, &videoSampleBuffer); if (err) { - NSLog(@"Error at CMSampleBufferCreateForImageBuffer %d", err); + NSLog(@"Error at CMSampleBufferCreateForImageBuffer %ld", (long)err); bNewFrame = NO; + // release temp buffer + CVBufferRelease(buffer); return; } + // release temp buffer + CVBufferRelease(buffer); + videoSampleTime = time; @@ -686,8 +905,8 @@ - (void)updateFromVideoOutput { // no new frame for time bNewFrame = NO; } -#endif } +#endif - (void)updateFromAssetReader { @@ -749,7 +968,12 @@ - (void)updateFromAssetReader { [self createAssetReaderWithTimeRange:CMTimeRangeMake(currentTime, duration)]; } - if(self.assetReader.status != AVAssetReaderStatusReading) { + if (self.assetReader.status == AVAssetReaderStatusFailed) { + NSLog(@"assetReader error: %@", self.assetReader.error); + } + + if(self.assetReader.status != AVAssetReaderStatusReading) + { bNewFrame = NO; return; } @@ -767,6 +991,7 @@ - (void)updateFromAssetReader { @try { videoBufferTemp = [self.assetReaderVideoTrackOutput copyNextSampleBuffer]; } @catch (NSException * e) { + NSLog(@"error: %@", e); break; } @@ -781,6 +1006,9 @@ - (void)updateFromAssetReader { bCopiedNewSamples = YES; } else { + bNewFrame = NO; + videoSampleTime = videoSampleTimePrev = kCMTimeNegativeInfinity; + bUpdateFirstFrame = YES; break; } } @@ -808,12 +1036,14 @@ - (void)updateFromAssetReader { audioSampleTime = CMSampleBufferGetPresentationTimeStamp(audioSampleBuffer); } else { + audioSampleTime = kCMTimeNegativeInfinity; break; } } if(bCopiedNewSamples == true) { bNewFrame = CMTimeCompare(videoSampleTime, videoSampleTimePrev) == 1; + if(bNewFrame) { videoSampleTimePrev = videoSampleTime; } @@ -894,7 +1124,7 @@ - (void)stepByCount:(long)frames if (frames < 0) { double timeSec = CMTimeGetSeconds(currentTime) - (1.0/frameRate); - [self seekToTime:CMTimeMakeWithSeconds(timeSec, NSEC_PER_SEC)]; + [self seekToTime:CMTimeMakeWithSeconds(timeSec, NSEC_PER_SEC) withTolerance:kCMTimeZero]; } else if (![self isFinished] && frames > 0) { @@ -933,7 +1163,6 @@ - (void)seekToTime:(CMTime)time withTolerance:(CMTime)tolerance { if(![self isReady]) { - NSLog(@"not ready"); return; } @@ -971,6 +1200,10 @@ - (BOOL)isReady { return bReady; } +- (BOOL)isLoaded { + return bLoaded; +} + - (BOOL)isPlaying { return bPlaying; } @@ -1052,26 +1285,30 @@ - (double)getDurationInSec { return CMTimeGetSeconds(duration); } -- (float)getFrameRate{ +- (float)getFrameRate { return frameRate; } -- (int)getDurationInFrames{ +- (int)getDurationInFrames { return [self getDurationInSec] * [self getFrameRate]; } -- (int)getCurrentFrameNum{ +- (int)getCurrentFrameNum { return [self getCurrentTimeInSec] * [self getFrameRate]; } - (void)setPosition:(float)position { - double time = [self getDurationInSec] * position; - [self seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)]; + if ([self isReady]) { + double time = [self getDurationInSec] * position; + [self seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)]; + } } -- (void)setFrame:(int)frame{ - float position = frame / (float)[self getDurationInFrames]; - [self setPosition:position]; +- (void)setFrame:(int)frame { + if ([self isReady]) { + float position = frame / (float)[self getDurationInFrames]; + [self setPosition:position]; + } } - (float)getPosition { @@ -1080,28 +1317,17 @@ - (float)getPosition { - (void)setVolume:(float)value { - if (self.playerItem == nil) { - return; - } + volume = value; + if(![self isReady]) { return; } - - volume = value; - NSArray * audioTracks = [self.playerItem.asset tracksWithMediaType:AVMediaTypeAudio]; - NSMutableArray * allAudioParams = [NSMutableArray array]; - for(AVAssetTrack * track in audioTracks) { - AVMutableAudioMixInputParameters * audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; - [audioInputParams setVolume:volume atTime:kCMTimeZero]; - [audioInputParams setTrackID:[track trackID]]; - [allAudioParams addObject:audioInputParams]; + if (self.playerItem == nil) { + return; } - AVMutableAudioMix * audioMix = [AVMutableAudioMix audioMix]; - [audioMix setInputParameters:allAudioParams]; - - [self.playerItem setAudioMix:audioMix]; + _player.volume = volume; } - (float)getVolume { @@ -1118,6 +1344,14 @@ - (playerLoopType)getLoop { - (void)setSpeed:(float)value { + if(![self isReady]) { + return; + } + + if (_player == nil) { + return; + } + if (!bSeeking && bWasPlayingBackwards && value > 0.0) { // create assetReaders if we played backwards earlier [self createAssetReaderWithTimeRange:CMTimeRangeMake(currentTime, duration)]; diff --git a/libs/openFrameworks/video/ofDirectShowPlayer.cpp b/libs/openFrameworks/video/ofDirectShowPlayer.cpp index 95ae546b050..46a6036d891 100644 --- a/libs/openFrameworks/video/ofDirectShowPlayer.cpp +++ b/libs/openFrameworks/video/ofDirectShowPlayer.cpp @@ -1,9 +1,3 @@ -//DirectShowVideo and ofDirectShowPlayer written by Theodore Watson, Jan 2014 -//Code is based off of examples provided by MSDN, the videoInput library, http://www.codeproject.com/Articles/30450/A-simple-console-DirectShow-player -//and http://www.geekpage.jp/en/programming/directshow/ -//This code is free to be used in any manner with or without attribution. -//No warrenty is offered or implied. - #include "ofDirectShowPlayer.h" @@ -270,24 +264,31 @@ HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) //------------------------------------------------------------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------------------------------------------------- -static int comRefCount = 0; +namespace{ + int comRefCount = 0; -static void retainCom(){ - if( comRefCount == 0 ){ - //printf("com is initialized!\n"); - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + void retainCom(){ + if( comRefCount == 0 ){ + //printf("com is initialized!\n"); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + } + comRefCount++; } - comRefCount++; -} -static void releaseCom(){ - comRefCount--; - if( comRefCount == 0 ){ - //printf("com is uninitialized!\n"); - CoUninitialize(); + void releaseCom(){ + comRefCount--; + if( comRefCount == 0 ){ + //printf("com is uninitialized!\n"); + CoUninitialize(); + } + } + + void releaseSample(IMediaSample * sample){ + sample->Release(); } } + class DirectShowVideo : public ISampleGrabberCB{ public: @@ -299,6 +300,8 @@ class DirectShowVideo : public ISampleGrabberCB{ ~DirectShowVideo(){ tearDown(); + middleSample.reset(); + backSample.reset(); releaseCom(); DeleteCriticalSection(&critSection); } @@ -339,10 +342,6 @@ class DirectShowVideo : public ISampleGrabberCB{ if( m_pPosition ){ m_pPosition->Release(); } - - if(rawBuffer){ - delete rawBuffer; - } clearValues(); } @@ -361,8 +360,6 @@ class DirectShowVideo : public ISampleGrabberCB{ m_pSourceFile = NULL; m_pPosition = NULL; - rawBuffer = NULL; - timeNow = 0; lPositionInSecs = 0; lDurationInNanoSecs = 0; @@ -372,7 +369,6 @@ class DirectShowVideo : public ISampleGrabberCB{ lvolume = -1000; evCode = 0; width = height = 0; - videoSize = 0; bVideoOpened = false; bLoop = true; bPaused = false; @@ -407,9 +403,10 @@ class DirectShowVideo : public ISampleGrabberCB{ if(hr == S_OK){ long latestBufferLength = pSample->GetActualDataLength(); - if(latestBufferLength == videoSize ){ + if(latestBufferLength == pixels.getTotalBytes() ){ EnterCriticalSection(&critSection); - memcpy(rawBuffer, ptrBuffer, latestBufferLength); + pSample->AddRef(); + backSample = std::unique_ptr>(pSample, releaseSample); bNewPixels = true; //this is just so we know if there is a new frame @@ -417,7 +414,7 @@ class DirectShowVideo : public ISampleGrabberCB{ LeaveCriticalSection(&critSection); }else{ - printf("ERROR: SampleCB() - buffer sizes do not match\n"); + printf("ERROR: SampleCB() - buffer sizes do not match %d %d\n", latestBufferLength, pixels.getTotalBytes()); } } @@ -429,9 +426,9 @@ class DirectShowVideo : public ISampleGrabberCB{ return E_NOTIMPL; } - bool loadMovie(string path){ + bool loadMovie(string path, ofPixelFormat format){ tearDown(); - + this->pixelFormat = format; // Create the Filter Graph Manager and query for interfaces. @@ -497,7 +494,7 @@ class DirectShowVideo : public ISampleGrabberCB{ return false; } - m_pGrabber->SetCallback(this, 0); + hr = m_pGrabber->SetCallback(this, 0); if (FAILED(hr)){ tearDown(); return false; @@ -509,9 +506,21 @@ class DirectShowVideo : public ISampleGrabberCB{ ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; - mt.subtype = MEDIASUBTYPE_RGB24; - mt.formattype = FORMAT_VideoInfo; + switch (format) { + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + mt.subtype = MEDIASUBTYPE_RGB24; + break; + case OF_PIXELS_BGRA: + case OF_PIXELS_RGBA: + mt.subtype = MEDIASUBTYPE_RGB32; + break; + default: + ofLogError("DirectShowPlayer") << "Trying to set unsupported format this is an internal bug, using default RGB"; + mt.subtype = MEDIASUBTYPE_RGB24; + } + mt.formattype = FORMAT_VideoInfo; //printf("step 5.5\n"); hr = m_pGrabber->SetMediaType(&mt); if (FAILED(hr)){ @@ -583,8 +592,8 @@ class DirectShowVideo : public ISampleGrabberCB{ AM_MEDIA_TYPE mt; ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE)); - - m_pGrabber->GetConnectedMediaType(&mt); + + hr = m_pGrabber->GetConnectedMediaType(&mt); if (FAILED(hr)){ printf("unable to call GetConnectedMediaType\n"); tearDown(); @@ -594,9 +603,9 @@ class DirectShowVideo : public ISampleGrabberCB{ VIDEOINFOHEADER * infoheader = (VIDEOINFOHEADER*)mt.pbFormat; width = infoheader->bmiHeader.biWidth; height = infoheader->bmiHeader.biHeight; - averageTimePerFrame = infoheader->AvgTimePerFrame / 10000000.0; + averageTimePerFrame = infoheader->AvgTimePerFrame / 10000000.0; + pixels.allocate(width, height, pixelFormat); - videoSize = width * height * 3; //printf("video dimensions are %i %i\n", width, height); //we need to manually change the output from the renderer window to the null renderer @@ -604,7 +613,7 @@ class DirectShowVideo : public ISampleGrabberCB{ IPin* pinIn = 0; IPin* pinOut = 0; - m_pGraph->FindFilterByName(L"Video Renderer", &m_pVideoRenderer); + hr = m_pGraph->FindFilterByName(L"Video Renderer", &m_pVideoRenderer); if (FAILED(hr)){ printf("failed to find the video renderer\n"); tearDown(); @@ -668,9 +677,6 @@ class DirectShowVideo : public ISampleGrabberCB{ tearDown(); printf("Error occured while playing or pausing or opening the file\n"); return false; - }else{ - rawBuffer = new unsigned char[videoSize]; - //printf("success!\n"); } }else{ tearDown(); @@ -730,7 +736,10 @@ class DirectShowVideo : public ISampleGrabberCB{ if( volPct < 0 ) volPct = 0.0; if( volPct > 1 ) volPct = 1.0; - long vol = log10(volPct) * 4000.0; + long vol = log10(volPct) * 4000.0; + if(vol < -8000){ + vol = -10000; + } m_pAudio->put_Volume(vol); } } @@ -801,65 +810,51 @@ class DirectShowVideo : public ISampleGrabberCB{ return movieRate; } - void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){ - - int widthInBytes = width * 3; - int numBytes = widthInBytes * height; - - if(!bRGB){ - - int x = 0; - int y = 0; - - if(bFlip){ - for(int y = 0; y < height; y++){ - memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes); - } - - }else{ - memcpy(dst, src, numBytes); - } - }else{ - if(bFlip){ - - int x = 0; - int y = (height - 1) * widthInBytes; - src += y; - - for(int i = 0; i < numBytes; i+=3){ - if(x >= width){ - x = 0; - src -= widthInBytes*2; - } - - *dst = *(src+2); - dst++; - - *dst = *(src+1); - dst++; - - *dst = *src; - dst++; - - src+=3; - x++; - } - } - else{ - for(int i = 0; i < numBytes; i+=3){ - *dst = *(src+2); - dst++; - - *dst = *(src+1); - dst++; - - *dst = *src; - dst++; - - src+=3; - } - } - } + bool needsRBSwap(ofPixelFormat srcFormat, ofPixelFormat dstFormat) { + return + (srcFormat == OF_PIXELS_BGR || srcFormat == OF_PIXELS_BGRA) && (dstFormat == OF_PIXELS_RGB || dstFormat == OF_PIXELS_RGBA) || + (srcFormat == OF_PIXELS_RGB || srcFormat == OF_PIXELS_RGBA) && (dstFormat == OF_PIXELS_BGR || dstFormat == OF_PIXELS_BGRA); + } + + void processPixels(ofPixels & src, ofPixels & dst){ + auto format = src.getPixelFormat(); + + if(needsRBSwap(src.getPixelFormat(), dst.getPixelFormat())){ + if (src.getPixelFormat() == OF_PIXELS_BGR) { + dst.allocate(src.getWidth(), src.getHeight(), OF_PIXELS_RGB); + auto dstLine = dst.getLines().begin(); + auto srcLine = --src.getLines().end(); + auto endLine = dst.getLines().end(); + for (; dstLine != endLine; dstLine++, srcLine--) { + auto dstPixel = dstLine.getPixels().begin(); + auto srcPixel = srcLine.getPixels().begin(); + auto endPixel = dstLine.getPixels().end(); + for (; dstPixel != endPixel; dstPixel++, srcPixel++) { + dstPixel[0] = srcPixel[2]; + dstPixel[1] = srcPixel[1]; + dstPixel[2] = srcPixel[0]; + } + } + } + else if (src.getPixelFormat() == OF_PIXELS_BGRA) { + dst.allocate(src.getWidth(), src.getHeight(), OF_PIXELS_RGBA); + auto dstLine = dst.getLines().begin(); + auto srcLine = --src.getLines().end(); + auto endLine = dst.getLines().end(); + for (; dstLine != endLine; dstLine++, srcLine--) { + auto dstPixel = dstLine.getPixels().begin(); + auto srcPixel = srcLine.getPixels().begin(); + auto endPixel = dstLine.getPixels().end(); + for (; dstPixel != endPixel; dstPixel++, srcPixel++) { + dstPixel[0] = srcPixel[2]; + dstPixel[1] = srcPixel[1]; + dstPixel[2] = srcPixel[0]; + } + } + } + } else { + src.mirrorTo(dst, true, false); + } } void play(){ @@ -1004,16 +999,29 @@ class DirectShowVideo : public ISampleGrabberCB{ return 0; } - void getPixels(unsigned char * dstBuffer){ - + ofPixels & getPixels(){ if(bVideoOpened && bNewPixels){ - EnterCriticalSection(&critSection); - processPixels(rawBuffer, dstBuffer, width, height, true, true); - bNewPixels = false; - LeaveCriticalSection(&critSection); - + std::swap(backSample, middleSample); + bNewPixels = false; + LeaveCriticalSection(&critSection); + BYTE * ptrBuffer = NULL; + HRESULT hr = middleSample->GetPointer(&ptrBuffer); + ofPixels srcBuffer; + switch (pixelFormat) { + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + srcBuffer.setFromExternalPixels(ptrBuffer, width, height, OF_PIXELS_BGR); + break; + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + srcBuffer.setFromExternalPixels(ptrBuffer, width, height, OF_PIXELS_BGRA); + break; + } + + processPixels(srcBuffer, pixels); } + return pixels; } //this is the non-callback approach @@ -1060,7 +1068,6 @@ class DirectShowVideo : public ISampleGrabberCB{ long evCode; // event variable, used to in file to complete wait. long width, height; - long videoSize; double averageTimePerFrame; @@ -1076,7 +1083,10 @@ class DirectShowVideo : public ISampleGrabberCB{ int frameCount; CRITICAL_SECTION critSection; - unsigned char * rawBuffer; + std::unique_ptr> backSample; + std::unique_ptr> middleSample; + ofPixels pixels; + ofPixelFormat pixelFormat; }; @@ -1088,39 +1098,45 @@ class DirectShowVideo : public ISampleGrabberCB{ //---------------------------------------------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------------------------------------------- +ofDirectShowPlayer::ofDirectShowPlayer() { -ofDirectShowPlayer::ofDirectShowPlayer(){ - player = NULL; } -ofDirectShowPlayer::~ofDirectShowPlayer(){ - close(); +ofDirectShowPlayer::ofDirectShowPlayer(ofDirectShowPlayer && other) +:player(std::move(other.player)) +,pixelFormat(std::move(other.pixelFormat)){ + +} + +ofDirectShowPlayer & ofDirectShowPlayer::operator=(ofDirectShowPlayer&& other) { + if (&other == this) { + return *this; + } + + player = std::move(other.player); + pixelFormat = std::move(other.pixelFormat); + return *this; } bool ofDirectShowPlayer::load(string path){ path = ofToDataPath(path); close(); - player = new DirectShowVideo(); - return player->loadMovie(path); + player.reset(new DirectShowVideo()); + bool loadOk = player->loadMovie(path, pixelFormat); + if( !loadOk ){ + ofLogError("ofDirectShowPlayer") << " Cannot load video of this file type. Make sure you have codecs installed on your system. OF recommends the free K-Lite Codec pack. " << endl; + } + return loadOk; } void ofDirectShowPlayer::close(){ - if( player ){ - delete player; - player = NULL; - } + player.reset(); } void ofDirectShowPlayer::update(){ if( player && player->isLoaded() ){ player->update(); - - if( pix.getWidth() != player->getWidth() ){ - pix.allocate(player->getWidth(), player->getHeight(), OF_IMAGE_COLOR); - } - - player->getPixels(pix.getPixels()); } } @@ -1141,11 +1157,11 @@ bool ofDirectShowPlayer::isFrameNew() const{ } const ofPixels & ofDirectShowPlayer::getPixels() const{ - return pix; + return player->getPixels(); } ofPixels & ofDirectShowPlayer::getPixels(){ - return pix; + return player->getPixels(); } float ofDirectShowPlayer::getWidth() const{ @@ -1175,11 +1191,20 @@ bool ofDirectShowPlayer::isPlaying() const{ } bool ofDirectShowPlayer::setPixelFormat(ofPixelFormat pixelFormat){ - return (pixelFormat == OF_PIXELS_RGB); + switch (pixelFormat) { + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_BGRA: + case OF_PIXELS_RGBA: + this->pixelFormat = pixelFormat; + return true; + default: + return false; + } } ofPixelFormat ofDirectShowPlayer::getPixelFormat() const{ - return OF_PIXELS_RGB; + return this->pixelFormat; } //should implement! diff --git a/libs/openFrameworks/video/ofDirectShowPlayer.h b/libs/openFrameworks/video/ofDirectShowPlayer.h index 8266688a1fe..07b84a0f7dd 100644 --- a/libs/openFrameworks/video/ofDirectShowPlayer.h +++ b/libs/openFrameworks/video/ofDirectShowPlayer.h @@ -9,13 +9,14 @@ class DirectShowVideo; class ofDirectShowPlayer : public ofBaseVideoPlayer{ public: - - ofDirectShowPlayer(); - ~ofDirectShowPlayer(); + ofDirectShowPlayer(); + ofDirectShowPlayer(const ofDirectShowPlayer&) = delete; + ofDirectShowPlayer & operator=(const ofDirectShowPlayer&) = delete; + ofDirectShowPlayer(ofDirectShowPlayer &&); + ofDirectShowPlayer & operator=(ofDirectShowPlayer&&); bool load(string path); void update(); - void draw(float x, float y); void close(); @@ -58,6 +59,6 @@ class ofDirectShowPlayer : public ofBaseVideoPlayer{ void previousFrame(); protected: - DirectShowVideo * player; - ofPixels pix; + std::shared_ptr player; + ofPixelFormat pixelFormat = OF_PIXELS_RGB; }; \ No newline at end of file diff --git a/libs/openFrameworks/video/ofGstUtils.cpp b/libs/openFrameworks/video/ofGstUtils.cpp index bb07de87db3..ec672d6eac0 100644 --- a/libs/openFrameworks/video/ofGstUtils.cpp +++ b/libs/openFrameworks/video/ofGstUtils.cpp @@ -695,6 +695,8 @@ bool ofGstUtils::gstHandleMessage(GstBus * bus, GstMessage * msg){ g_free (name); break; } + +#if GST_VERSION_MAJOR==1 case GST_MESSAGE_HAVE_CONTEXT:{ GstContext *context; const gchar *context_type; @@ -711,6 +713,7 @@ bool ofGstUtils::gstHandleMessage(GstBus * bus, GstMessage * msg){ gst_context_unref (context); break; } +#endif default: ofLogVerbose("ofGstUtils") << "gstHandleMessage(): unhandled message from " << GST_MESSAGE_SRC_NAME(msg); break; @@ -796,7 +799,10 @@ void ofGstVideoUtils::close(){ bBackPixelsChanged = false; frontBuffer.reset(); backBuffer.reset(); + +#if GST_VERSION_MAJOR==1 while(!bufferQueue.empty()) bufferQueue.pop(); +#endif } bool ofGstVideoUtils::isInitialized() const{ @@ -848,20 +854,7 @@ void ofGstVideoUtils::update(){ } }else{ #if GST_VERSION_MAJOR==0 - GstBuffer *buffer; - - //get the buffer from appsink - if(isPaused()) buffer = gst_app_sink_pull_preroll (GST_APP_SINK (getSink())); - else buffer = gst_app_sink_pull_buffer (GST_APP_SINK (getSink())); - - if(buffer){ - if(pixels.isAllocated()){ - pixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); - prevBuffer = shared_ptr(buffer,gst_buffer_unref);; - bHavePixelsChanged=true; - } - } - } + ofLogError() << "frame by frame doesn't work any more in 0.10"; #else GstBuffer * buffer; GstSample * sample; @@ -884,8 +877,8 @@ void ofGstVideoUtils::update(){ gst_buffer_unmap(buffer,&mapinfo); } } - } #endif + } }else{ ofLogWarning("ofGstVideoUtils") << "update(): ofGstVideoUtils not loaded"; } @@ -1188,7 +1181,9 @@ void ofGstVideoUtils::reallocateOnNextFrame(){ bBackPixelsChanged = false; frontBuffer.reset(); backBuffer.reset(); +#if GST_VERSION_MAJOR==1 while(!bufferQueue.empty()) bufferQueue.pop(); +#endif } #if GST_VERSION_MAJOR==0 @@ -1204,13 +1199,13 @@ GstFlowReturn ofGstVideoUtils::process_buffer(shared_ptr _buffer){ } mutex.lock(); if(pixels.isAllocated()){ - buffer = _buffer; + backBuffer = _buffer; if(stride > 0) { - backPixels.setFromAlignedPixels(GST_BUFFER_DATA (buffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),stride); + backPixels.setFromAlignedPixels(GST_BUFFER_DATA (backBuffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),stride); } else { - backPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); - eventPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); + backPixels.setFromExternalPixels(GST_BUFFER_DATA (backBuffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); + eventPixels.setFromExternalPixels(GST_BUFFER_DATA (backBuffer.get()),pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); } bBackPixelsChanged=true; mutex.unlock(); @@ -1305,7 +1300,13 @@ GstFlowReturn ofGstVideoUtils::process_sample(shared_ptr sample){ if(pixels.isAllocated()){ if(stride > 0) { - backPixels.setFromAlignedPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),stride); + if(pixels.getPixelFormat() == OF_PIXELS_I420){ + GstVideoInfo v_info = getVideoInfo(sample.get()); + std::vector strides{v_info.stride[0],v_info.stride[1],v_info.stride[2]}; + backPixels.setFromAlignedPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),strides); + } else { + backPixels.setFromAlignedPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat(),stride); + } } else if(!copyPixels){ backPixels.setFromExternalPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); eventPixels.setFromExternalPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getPixelFormat()); diff --git a/libs/openFrameworks/video/ofGstVideoGrabber.cpp b/libs/openFrameworks/video/ofGstVideoGrabber.cpp index ffc73ee3e6f..d7ac8148013 100644 --- a/libs/openFrameworks/video/ofGstVideoGrabber.cpp +++ b/libs/openFrameworks/video/ofGstVideoGrabber.cpp @@ -230,9 +230,13 @@ static void get_supported_framerates (ofGstVideoFormat &video_format, GstStructu ofLogVerbose("ofGstVideoGrabber") << "get_supported_framerates(): from " << numerator_min << "/" << denominator_max << " to " << numerator_max << "/" << denominator_min; - - for (int i = numerator_min; i <= numerator_max; i++){ - for (int j = denominator_min; j <= denominator_max; j++){ + if(denominator_max==1 && numerator_max>1000000){ + // workaround for #4647 where some camera seems to + // return a really high value for num_max crashing the app + numerator_max = 1000; + } + for (int i = numerator_min; i <= numerator_max; i++){ + for (int j = denominator_min; j <= denominator_max; j++){ framerate.numerator = i; framerate.denominator = j; video_format.framerates.push_back(framerate); @@ -739,7 +743,7 @@ bool ofGstVideoGrabber::setup(int w, int h){ string pipeline_string; string format_str_pipeline; string fix_v4l2_316; -#if defined(TARGET_LINUX) && !defined(OF_USE_GST_GL) && GST_VERSION_MAJOR>0 && GST_VERSION_MINOR>2 +#if defined(TARGET_LINUX) && !defined(OF_USE_GST_GL) && GST_VERSION_MAJOR>0 && GST_VERSION_MINOR>2 && GST_VERSION_MINOR<5 videoUtils.setCopyPixels(true); #endif if(internalPixelFormat!=OF_PIXELS_NATIVE){ diff --git a/libs/openFrameworks/video/ofQTKitGrabber.mm b/libs/openFrameworks/video/ofQTKitGrabber.mm index a29c10d0816..3af6b9f22e6 100644 --- a/libs/openFrameworks/video/ofQTKitGrabber.mm +++ b/libs/openFrameworks/video/ofQTKitGrabber.mm @@ -129,7 +129,6 @@ + (void) enumerateArray:(NSArray*)someArray + (NSInteger) getIndexofStringInArray:(NSArray*)someArray stringToFind:(NSString*)someStringDescription { - NSInteger count = 0; NSInteger index = -1; for (id object in someArray) { @@ -431,8 +430,6 @@ - (void) startRecording:(NSString*)filePath { if (isRecordReady) { - BOOL success = YES; - // make sure last movie has stopped if (isRecording){ [self stopRecording]; diff --git a/libs/openFrameworks/video/ofQuickTimePlayer.cpp b/libs/openFrameworks/video/ofQuickTimePlayer.cpp index c4299546d53..ed5648fce94 100644 --- a/libs/openFrameworks/video/ofQuickTimePlayer.cpp +++ b/libs/openFrameworks/video/ofQuickTimePlayer.cpp @@ -49,7 +49,7 @@ bool createMovieFromPath(char * path, Movie &movie){ return false; } } else { - ofLogError("ofQuickTimePlayer") << "createMovoeFromPath(): couldn't load movie, OpenMovieFile failed: OSErr " << result; + ofLogError("ofQuickTimePlayer") << "createMovieFromPath(): couldn't load movie, OpenMovieFile failed: OSErr " << result; return false; } diff --git a/libs/openFrameworks/video/ofVideoGrabber.cpp b/libs/openFrameworks/video/ofVideoGrabber.cpp index 8909a35c5fd..22e18bfab8f 100644 --- a/libs/openFrameworks/video/ofVideoGrabber.cpp +++ b/libs/openFrameworks/video/ofVideoGrabber.cpp @@ -65,9 +65,6 @@ bool ofVideoGrabber::setup(int w, int h, bool setUseTexture){ ofPixels plane = grabber->getPixels().getPlane(i); tex.push_back(ofTexture()); tex[i].allocate(plane); - if(ofIsGLProgrammableRenderer() && plane.getPixelFormat() == OF_PIXELS_GRAY){ - tex[i].setRGToRGBASwizzles(true); - } } } } @@ -231,9 +228,6 @@ void ofVideoGrabber::update(){ bool bDiffPixFormat = ( tex[i].isAllocated() && tex[i].texData.glInternalFormat != ofGetGLInternalFormatFromPixelFormat(plane.getPixelFormat()) ); if(bDiffPixFormat || !tex[i].isAllocated() ){ tex[i].allocate(plane); - if(ofIsGLProgrammableRenderer() && plane.getPixelFormat() == OF_PIXELS_GRAY){ - tex[i].setRGToRGBASwizzles(true); - } }else{ tex[i].loadData(plane); } @@ -247,7 +241,7 @@ void ofVideoGrabber::close(){ if(grabber){ grabber->close(); } - if(!grabber->getTexturePtr()) tex.clear(); + tex.clear(); } //-------------------------------------------------------------------- diff --git a/libs/openFrameworks/video/ofVideoPlayer.cpp b/libs/openFrameworks/video/ofVideoPlayer.cpp index df81113c8d5..70ddf8f7115 100644 --- a/libs/openFrameworks/video/ofVideoPlayer.cpp +++ b/libs/openFrameworks/video/ofVideoPlayer.cpp @@ -90,6 +90,7 @@ bool ofVideoPlayer::load(string name){ playerTex = player->getTexturePtr(); } } + setLoopState(OF_LOOP_NORMAL); } return bOk; @@ -211,9 +212,6 @@ void ofVideoPlayer::update(){ bool bDiffPixFormat = ( tex[i].isAllocated() && tex[i].texData.glInternalFormat != ofGetGLInternalFormatFromPixelFormat(plane.getPixelFormat()) ); if(bDiffPixFormat || !tex[i].isAllocated() || tex[i].getWidth() != plane.getWidth() || tex[i].getHeight() != plane.getHeight()){ tex[i].allocate(plane); - if(ofIsGLProgrammableRenderer() && plane.getPixelFormat() == OF_PIXELS_GRAY){ - tex[i].setRGToRGBASwizzles(true); - } } tex[i].loadData(plane); } @@ -379,9 +377,6 @@ void ofVideoPlayer::setUseTexture(bool bUse){ if(!tex[i].isAllocated() || bDiffPixFormat){ tex[i].allocate(plane); } - if(ofIsGLProgrammableRenderer() && plane.getPixelFormat() == OF_PIXELS_GRAY){ - tex[i].setRGToRGBASwizzles(true); - } } } } @@ -486,7 +481,7 @@ bool ofVideoPlayer::isPlaying() const{ //---------------------------------------------------------- bool ofVideoPlayer::isInitialized() const{ if( player ){ - return player->isInitialized() && (!bUseTexture || tex[0].isAllocated() || player->getTexturePtr()); + return player->isInitialized() && (!bUseTexture || tex[0].isAllocated() || (player->getTexturePtr() && player->getTexturePtr()->isAllocated()) ); } return false; } diff --git a/libs/openFrameworksCompiled/project/android/build.gradle b/libs/openFrameworksCompiled/project/android/build.gradle index 75f898dc1ce..772ea8aef08 100644 --- a/libs/openFrameworksCompiled/project/android/build.gradle +++ b/libs/openFrameworksCompiled/project/android/build.gradle @@ -29,19 +29,30 @@ task ofNdkSetup { logger.lifecycle name /* Find NDK directory */ - def localProperties = new File(rootDir, "local.properties") + def pathsmake = new File(project.projectDir, "paths.make") + if (!pathsmake.exists()) { + throw new GradleException("pathsmake is missing!") + } + + + def localProperties = new File(rootProject.projectDir, "local.properties") if (!localProperties.exists()) { throw new GradleException("local.properties is missing!") } + Properties ndkProperties = new Properties() + pathsmake.withInputStream { instr -> + ndkProperties.load(instr) + } + Properties properties = new Properties() localProperties.withInputStream { instr -> properties.load(instr) } String sdkDirectory = properties.get("sdk.dir") - String ndkDirectory = properties.get("ndk.dir") + String ndkDirectory = ndkProperties.get("NDK_ROOT") if (ndkDirectory == null) { - throw new GradleException("NDK not configured. Add ndk.dir=/path/to/ndk to local.properties.") + throw new GradleException("NDK not configured. Add NDK_ROOT=/path/to/ndk to paths.make.") } if (ndkDirectory.contains(' ')) { // Make really hates spaces in filenames, so we have to avoid them. @@ -49,7 +60,7 @@ task ofNdkSetup { } def ndkDir = new File(ndkDirectory) if (!ndkDir.directory) { - throw new GradleException("NDK directory is invalid. Check ndk.dir path in local.properties.") + throw new GradleException("NDK directory is invalid. Check NDK_ROOT path in paths.make.") } /* Find suitable make executable */ @@ -122,11 +133,11 @@ task ofNdkSetup { * Helper function to run make with a given set of options */ def ofRunMake(List opts) { - def num_parallel = rootProject.ofNdkSetup.ext.num_parallel + def num_parallel = ofNdkSetup.ext.num_parallel if (num_parallel > 1) { opts.add(0, "-j$num_parallel") } - List cmd = [rootProject.ofNdkSetup.ext.make] + opts + List cmd = [ofNdkSetup.ext.make] + opts logger.info("Executing make command " + cmd) def proc = cmd.execute() proc.in.eachLine {line -> @@ -146,3 +157,15 @@ def ofRunMake(List opts) { throw new GradleException("make failed with exit status " + proc.exitValue()) } } + +task compileDebugOF { + ofRunMake(["-C", rootProject.projectDir.absolutePath, "PLATFORM_OS=Android", "Debug"]) +} + +task compileReleaseOF { + ofRunMake(["-C", rootProject.projectDir.absolutePath, "PLATFORM_OS=Android", "Release"]) +} + +task clean(dependsOn: ofNdkSetup) << { + ofRunMake(["-C", rootProject.projectDir.absolutePath, "PLATFORM_OS=Android", "clean"]) +} diff --git a/libs/openFrameworksCompiled/project/android/config.android.default.mk b/libs/openFrameworksCompiled/project/android/config.android.default.mk index 365c24913c7..db71428bc78 100644 --- a/libs/openFrameworksCompiled/project/android/config.android.default.mk +++ b/libs/openFrameworksCompiled/project/android/config.android.default.mk @@ -60,7 +60,7 @@ PLATFORM_DEFINES = PLATFORM_DEFINES = ANDROID ifndef $(NDK_PLATFORM) - NDK_PLATFORM = android-21 + NDK_PLATFORM = android-19 endif ifndef $(SDK_TARGET) @@ -108,7 +108,7 @@ endif TOOLCHAIN_PATH=$(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(HOST_PLATFORM)/bin/ DATA_FILES = $(shell find bin/data -type f 2>/dev/null) -RESNAME=$(shell echo $(APPNAME)Resources | tr '[A-Z]' '[a-z]') +RESNAME=ofdataresources RESFILE=$(RESNAME).zip ifeq ($(ABI),armv7) @@ -131,8 +131,8 @@ endif ifeq ($(ABI),x86) ABI_PATH = x86 - PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so - PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so + PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_x86.so + PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_x86.so endif PLATFORM_CORELIB_RELEASE_TARGET = $(OF_CORE_LIB_PATH)/$(ABI)/libopenFrameworks.a @@ -158,7 +158,7 @@ PLATFORM_CORELIB_DEBUG_TARGET = $(OF_CORE_LIB_PATH)/$(ABI)/libopenFrameworksDebu # Note: Leave a leading space when adding list items with the += operator ################################################################################ -PLATFORM_REQUIRED_ADDONS = ofxAndroid +PLATFORM_REQUIRED_ADDONS = ofxAndroid ofxAccelerometer ################################################################################ # PLATFORM CFLAGS @@ -224,13 +224,13 @@ PLATFORM_LDFLAGS += -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--gc-sections ################################################################################ # RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os +PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os -DNDEBUG # RELEASE options PLATFORM_OPTIMIZATION_LDFLAGS_RELEASE = -s # DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -O0 -g -D_DEBUG +PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -O0 -g3 -DANDROID_NDK -D_DEBUG -DDEBUG #-D_GLIBCXX_DEBUG ################################################################################ # PLATFORM CORE EXCLUSIONS @@ -267,6 +267,7 @@ PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppGLFWWindow.c PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/graphics/ofCairoRenderer.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofFmodSoundPlayer.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofOpenALSoundPlayer.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofRtAudioSoundStream.cpp # third party PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glew/% @@ -505,12 +506,14 @@ afterplatform:$(RESFILE) else \ rm -r libs/armeabi 2> /dev/null; \ fi; \ - if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ] || [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ + if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ] && [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ ABIS="$$ABIS armeabi-v7a"; \ elif [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ]; then \ + ABIS="$$ABIS armeabi-v7a"; \ rm libs/armeabi-v7a/libOFAndroidApp_neon.so 2> /dev/null; \ rm libs/armeabi-v7a/libneondetection.so 2> /dev/null; \ elif [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ + ABIS="$$ABIS armeabi-v7a"; \ rm libs/armeabi-v7a/libOFAndroidApp.so 2> /dev/null; \ else \ rm -r libs/armeabi-v7a 2> /dev/null; \ diff --git a/libs/openFrameworksCompiled/project/android/settings.gradle b/libs/openFrameworksCompiled/project/android/settings.gradle deleted file mode 100644 index 1ec3b6dee58..00000000000 --- a/libs/openFrameworksCompiled/project/android/settings.gradle +++ /dev/null @@ -1,18 +0,0 @@ -// settings.gradle project file for Android Studio support - -// openFrameworks-relative root directories (don't touch) -def ofxRoot = '../../../../' - -include ':examples' -project(':examples').projectDir = new File(ofxRoot + 'examples') - -include ':apps' -project(':apps').projectDir = new File(ofxRoot + 'apps') - -include ':ofAndroidLib' -project(':ofAndroidLib').projectDir = new File(ofxRoot + 'addons/ofxAndroid/ofAndroidLib') - -// your projects go here -include 'examples:android:androidEmptyExample' -// Add your own projects like this: -// includeFlat 'apps:myApps:myAwesomeApp' diff --git a/libs/openFrameworksCompiled/project/emscripten/config.emscripten.default.mk b/libs/openFrameworksCompiled/project/emscripten/config.emscripten.default.mk index be5601aecb7..ce5fabda421 100644 --- a/libs/openFrameworksCompiled/project/emscripten/config.emscripten.default.mk +++ b/libs/openFrameworksCompiled/project/emscripten/config.emscripten.default.mk @@ -64,7 +64,7 @@ PLATFORM_REQUIRED_ADDONS = ofxEmscripten ################################################################################ # Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) -PLATFORM_CFLAGS = -Wall -std=c++11 +PLATFORM_CFLAGS = -Wall -std=c++14 -Wno-warn-absolute-paths ################################################################################ @@ -81,13 +81,19 @@ else PLATFORM_EMSCRIPTEN_TOTAL_MEMORY=134217728 endif -PLATFORM_LDFLAGS = -Wl,--as-needed -Wl,--gc-sections --preload-file bin/data@data +PLATFORM_LDFLAGS = -Wl,--as-needed -Wl,--gc-sections --preload-file bin/data@data --emrun PLATFORM_LDFLAGS += --js-library $(OF_ADDONS_PATH)/ofxEmscripten/libs/html5video/lib/emscripten/library_html5video.js PLATFORM_LDFLAGS += --js-library $(OF_ADDONS_PATH)/ofxEmscripten/libs/html5audio/lib/emscripten/library_html5audio.js -PLATFORM_OPTIMIZATION_LDFLAGS_RELEASE = -O3 -s OUTLINING_LIMIT=100000 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 -s TOTAL_MEMORY=$(PLATFORM_EMSCRIPTEN_TOTAL_MEMORY) --memory-init-file 1 +ifdef PROJECT_EMSCRIPTEN_TEMPLATE + PLATFORM_LDFLAGS += --shell-file $(PROJECT_EMSCRIPTEN_TEMPLATE) +else + PLATFORM_LDFLAGS += --shell-file $(OF_LIBS_PATH)/openFrameworksCompiled/project/emscripten/template.html +endif + +PLATFORM_OPTIMIZATION_LDFLAGS_RELEASE = -O3 -s OUTLINING_LIMIT=100000 -s TOTAL_MEMORY=$(PLATFORM_EMSCRIPTEN_TOTAL_MEMORY) --memory-init-file 1 -PLATFORM_OPTIMIZATION_LDFLAGS_DEBUG = -g3 -s TOTAL_MEMORY=134217728 --memory-init-file 1 +PLATFORM_OPTIMIZATION_LDFLAGS_DEBUG = -g3 -s TOTAL_MEMORY=134217728 --memory-init-file 1 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2 ################################################################################ # PLATFORM OPTIMIZATION CFLAGS @@ -105,10 +111,10 @@ PLATFORM_OPTIMIZATION_LDFLAGS_DEBUG = -g3 -s TOTAL_MEMORY=134217728 --memory-ini ################################################################################ # RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -O2 -s OUTLINING_LIMIT=100000 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 +PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -O3 -s OUTLINING_LIMIT=100000 -DNDEBUG # DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 +PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2 ################################################################################ # PLATFORM CORE EXCLUSIONS diff --git a/libs/openFrameworksCompiled/project/emscripten/template.html b/libs/openFrameworksCompiled/project/emscripten/template.html new file mode 100644 index 00000000000..7b09ee508ef --- /dev/null +++ b/libs/openFrameworksCompiled/project/emscripten/template.html @@ -0,0 +1,218 @@ + + + + + + openFrameworks + + + + + +
    +
    Downloading...
    + + + Resize canvas + Lock/hide mouse pointer     + + + + +
    + +
    + + +
    + +
    + + + + {{{ SCRIPT }}} + + + diff --git a/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig b/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig index c2b768bb1b4..3fa1dc1eba1 100644 --- a/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig +++ b/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig @@ -1,6 +1,5 @@ HEADER_OF = "$(OF_PATH)/libs/openFrameworks/**" HEADER_OFXIOS = "$(OF_PATH)/addons/ofxiOS/**" -HEADER_OFXMULTITOUCH = "$(OF_PATH)/addons/ofxMultiTouch/**" HEADER_OFXACCELEROMETER = "$(OF_PATH)/addons/ofxAccelerometer/**" HEADER_FREETYPE = "$(OF_PATH)/libs/freetype/include" HEADER_FREETYPE2 = "$(OF_PATH)/libs/freetype/include/freetype2" @@ -13,6 +12,7 @@ HEADER_RTAUDIO = "$(OF_PATH)/libs/rtaudio/include" HEADER_SSL = "$(OF_PATH)/libs/openssl/include" HEADER_BOOST = "$(OF_PATH)/libs/boost/include" HEADER_UTF8 = "$(OF_PATH)/libs/utf8cpp/include" +HEADER_JSON = "$(OF_PATH)/libs/json/include" //------- Libraries LIB_FREEIMAGE = "$(OF_PATH)/libs/FreeImage/lib/ios/freeimage.a" @@ -40,7 +40,7 @@ LIB_BOOST = $(LIB_BOOST_SYSTEM) $(LIB_BOOST_FS) MISC_FLAGS = "-ObjC" OF_CORE_LIBS = $(MISC_FLAGS) $(LIB_POCO) $(LIB_BOOST) $(LIB_FREEIMAGE) $(LIB_FREETYPE) $(LIB_OPENSSL) $(LIB_TESS) -OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_OFXIOS) $(HEADER_OFXMULTITOUCH) $(HEADER_OFXACCELEROMETER) $(HEADER_POCO) $(HEADER_BOOST) $(HEADER_UTF8) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_FMODEX) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_RTAUDIO) $(HEADER_SSL) +OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_OFXIOS) $(HEADER_OFXACCELEROMETER) $(HEADER_POCO) $(HEADER_BOOST) $(HEADER_UTF8) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_FMODEX) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_RTAUDIO) $(HEADER_SSL) $(HEADER_JSON) // once all libraries are compiled for libc++ / all architectures CLANG_CXX_LIBRARY = libc++ diff --git a/libs/openFrameworksCompiled/project/ios/Release.xcconfig b/libs/openFrameworksCompiled/project/ios/Release.xcconfig index a908b85b950..c68d2eee299 100644 --- a/libs/openFrameworksCompiled/project/ios/Release.xcconfig +++ b/libs/openFrameworksCompiled/project/ios/Release.xcconfig @@ -8,7 +8,7 @@ GCC_MODEL_TUNING = G5 GCC_OPTIMIZATION_LEVEL = s GCC_SYMBOLS_PRIVATE_EXTERN = NO GCC_UNROLL_LOOPS = YES -OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ +OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ -DNDEBUG GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO GCC_WARN_UNINITIALIZED_AUTOS = YES GCC_WARN_UNUSED_VALUE = NO diff --git a/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj index 11ebf5639fa..5b07c6d3896 100644 --- a/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj +++ b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj @@ -100,9 +100,6 @@ BB24DED110DA7A3F00E9C588 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB16EBD80F2B2AB500518274 /* QuartzCore.framework */; }; BB24E0CD10DA9F4800E9C588 /* ofxAccelerometer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BB24E02110DA7C6100E9C588 /* ofxAccelerometer.cpp */; }; BB24E0DC10DA9F5700E9C588 /* ofxAccelerometer.h in Headers */ = {isa = PBXBuildFile; fileRef = BB24E02210DA7C6100E9C588 /* ofxAccelerometer.h */; }; - E485F8191363242200E939D3 /* ofxMultiTouch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E485F8161363242100E939D3 /* ofxMultiTouch.cpp */; }; - E485F81A1363242200E939D3 /* ofxMultiTouch.h in Headers */ = {isa = PBXBuildFile; fileRef = E485F8171363242100E939D3 /* ofxMultiTouch.h */; }; - E485F81B1363242200E939D3 /* ofxMultiTouchListener.h in Headers */ = {isa = PBXBuildFile; fileRef = E485F8181363242100E939D3 /* ofxMultiTouchListener.h */; }; E4F76E19176CB27200798745 /* of3dPrimitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F76D6F176CB27200798745 /* of3dPrimitives.cpp */; }; E4F76E1A176CB27200798745 /* of3dPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F76D70176CB27200798745 /* of3dPrimitives.h */; }; E4F76E1B176CB27200798745 /* of3dUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F76D71176CB27200798745 /* of3dUtils.cpp */; }; @@ -320,9 +317,6 @@ E41D3E9113B38BE900A75A5D /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = SOURCE_ROOT; }; E41D3E9213B38BE900A75A5D /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = SOURCE_ROOT; }; E41D3E9313B38BE900A75A5D /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = SOURCE_ROOT; }; - E485F8161363242100E939D3 /* ofxMultiTouch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ofxMultiTouch.cpp; path = ../../../../addons/ofxMultiTouch/src/ofxMultiTouch.cpp; sourceTree = SOURCE_ROOT; }; - E485F8171363242100E939D3 /* ofxMultiTouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxMultiTouch.h; path = ../../../../addons/ofxMultiTouch/src/ofxMultiTouch.h; sourceTree = SOURCE_ROOT; }; - E485F8181363242100E939D3 /* ofxMultiTouchListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofxMultiTouchListener.h; path = ../../../../addons/ofxMultiTouch/src/ofxMultiTouchListener.h; sourceTree = SOURCE_ROOT; }; E4F76D6F176CB27200798745 /* of3dPrimitives.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp.preprocessed; fileEncoding = 4; path = of3dPrimitives.cpp; sourceTree = ""; }; E4F76D70176CB27200798745 /* of3dPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = of3dPrimitives.h; sourceTree = ""; }; E4F76D71176CB27200798745 /* of3dUtils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp.preprocessed; fileEncoding = 4; path = of3dUtils.cpp; sourceTree = ""; }; @@ -628,7 +622,6 @@ BB16F26B0F2B646B00518274 /* addons */ = { isa = PBXGroup; children = ( - E485F8111363242100E939D3 /* ofxMultiTouch */, BB24E01C10DA7C6100E9C588 /* ofxAccelerometer */, BB24E02310DA7C6100E9C588 /* ofxiOS */, ); @@ -689,26 +682,6 @@ name = core; sourceTree = ""; }; - E485F8111363242100E939D3 /* ofxMultiTouch */ = { - isa = PBXGroup; - children = ( - E485F8151363242100E939D3 /* src */, - ); - name = ofxMultiTouch; - path = ../../../../addons/ofxMultiTouch; - sourceTree = SOURCE_ROOT; - }; - E485F8151363242100E939D3 /* src */ = { - isa = PBXGroup; - children = ( - E485F8161363242100E939D3 /* ofxMultiTouch.cpp */, - E485F8171363242100E939D3 /* ofxMultiTouch.h */, - E485F8181363242100E939D3 /* ofxMultiTouchListener.h */, - ); - name = src; - path = ../../../../addons/ofxMultiTouch/src; - sourceTree = SOURCE_ROOT; - }; E4F76D69176CB27200798745 /* openFrameworks */ = { isa = PBXGroup; children = ( @@ -1009,8 +982,6 @@ 67833F8B19F8996300DBE7AA /* ofBufferObject.h in Headers */, E4F76EB8176CB27200798745 /* ofVideoPlayer.h in Headers */, BB24E0DC10DA9F5700E9C588 /* ofxAccelerometer.h in Headers */, - E485F81A1363242200E939D3 /* ofxMultiTouch.h in Headers */, - E485F81B1363242200E939D3 /* ofxMultiTouchListener.h in Headers */, 15594F0F15C55AC900727FF2 /* EAGLView.h in Headers */, 15594F1015C55AC900727FF2 /* ES1Renderer.h in Headers */, 15594F1115C55AC900727FF2 /* ES2Renderer.h in Headers */, @@ -1157,7 +1128,6 @@ E4F76EB5176CB27200798745 /* ofVideoGrabber.cpp in Sources */, E4F76EB7176CB27200798745 /* ofVideoPlayer.cpp in Sources */, BB24E0CD10DA9F4800E9C588 /* ofxAccelerometer.cpp in Sources */, - E485F8191363242200E939D3 /* ofxMultiTouch.cpp in Sources */, 15594F0C15C55AC900727FF2 /* EAGLView.m in Sources */, 9979E8281A1CDBD4007E55D1 /* ofMainLoop.cpp in Sources */, 15594F0D15C55AC900727FF2 /* ES1Renderer.m in Sources */, @@ -1206,6 +1176,7 @@ EXECUTABLE_PREFIX = lib; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; @@ -1231,6 +1202,7 @@ DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; EXECUTABLE_PREFIX = lib; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; diff --git a/libs/openFrameworksCompiled/project/linux/config.linux.default.mk b/libs/openFrameworksCompiled/project/linux/config.linux.default.mk index 5c48c2060da..d7e5cfbed89 100644 --- a/libs/openFrameworksCompiled/project/linux/config.linux.default.mk +++ b/libs/openFrameworksCompiled/project/linux/config.linux.default.mk @@ -26,17 +26,3 @@ ################################################################################ include $(OF_SHARED_MAKEFILES_PATH)/config.linux.common.mk - - -################################################################################ -# PLATFORM CFLAGS -# This is a list of fully qualified CFLAGS required when compiling for this -# platform. These flags will always be added when compiling a project or the -# core library. These flags are presented to the compiler AFTER the -# PLATFORM_OPTIMIZATION_CFLAGS below. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_CFLAGS += -march=native -PLATFORM_CFLAGS += -mtune=native diff --git a/libs/openFrameworksCompiled/project/linux64/config.linux64.default.mk b/libs/openFrameworksCompiled/project/linux64/config.linux64.default.mk index c3df0861413..d7e5cfbed89 100644 --- a/libs/openFrameworksCompiled/project/linux64/config.linux64.default.mk +++ b/libs/openFrameworksCompiled/project/linux64/config.linux64.default.mk @@ -26,18 +26,3 @@ ################################################################################ include $(OF_SHARED_MAKEFILES_PATH)/config.linux.common.mk - - -################################################################################ -# PLATFORM CFLAGS -# This is a list of fully qualified CFLAGS required when compiling for this -# platform. These flags will always be added when compiling a project or the -# core library. These flags are presented to the compiler AFTER the -# PLATFORM_OPTIMIZATION_CFLAGS below. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_CFLAGS += -march=native -PLATFORM_CFLAGS += -mtune=native -#PLATFORM_CFLAGS += -std=c++11 diff --git a/libs/openFrameworksCompiled/project/linuxarmv6l/config.linuxarmv6l.default.mk b/libs/openFrameworksCompiled/project/linuxarmv6l/config.linuxarmv6l.default.mk index 249878a3c0e..9907f1c0fc4 100644 --- a/libs/openFrameworksCompiled/project/linuxarmv6l/config.linuxarmv6l.default.mk +++ b/libs/openFrameworksCompiled/project/linuxarmv6l/config.linuxarmv6l.default.mk @@ -65,11 +65,6 @@ PLATFORM_DEFINES += HAVE_LIBBCM_HOST PLATFORM_DEFINES += USE_EXTERNAL_LIBBCM_HOST PLATFORM_DEFINES += USE_VCHIQ_ARM -# Fix for firmware update @ -# https://github.com/Hexxeh/rpi-firmware/commit/ca3703d2d282ac96a97650e2e496276727e1b65b -ifeq ($(strip $(shell cat $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/vc_dispmanx.h | grep VC_IMAGE_TRANSFORM_T)),) -PLATFORM_DEFINES += USE_DISPMANX_TRANSFORM_T -endif ################################################################################ # PLATFORM REQUIRED ADDONS @@ -154,11 +149,10 @@ PLATFORM_LDFLAGS += -pthread ################################################################################ # Broadcom hardware interface library -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/IL -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vcos/pthreads -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vmcs_host/linux - +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/IL +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vcos/pthreads +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/linux ########################################################################################## # PLATFORM LIBRARY SEARCH PATH @@ -169,7 +163,7 @@ PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vmcs_host/linux # Note: Leave a leading space when adding list items with the += operator ########################################################################################## -PLATFORM_LIBRARY_SEARCH_PATHS += /opt/vc/lib +PLATFORM_LIBRARY_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/lib ################################################################################ @@ -188,51 +182,39 @@ PLATFORM_LIBRARY_SEARCH_PATHS += /opt/vc/lib # Note: Leave a leading space when adding list items with the += operator ################################################################################ -#PLATFORM_PKG_CONFIG_LIBRARIES += gstreamer-egl-$(GST_VERSION) PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppGLFWWindow.cpp -$(info $(PLATFORM_ARCH)) + ifeq ($(CROSS_COMPILING),1) - ifneq ($(wildcard $(RPI_ROOT)/etc/debian_version),) - #RASPBIAN - ifeq ($(HOST_ARCH),x86_64) - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin - else - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin - endif - GCC_PREFIX=arm-linux-gnueabihf + + ifdef TOOLCHAIN_ROOT + #You have specified TOOLCHAIN_ROOT with an environment variable else - #ARCH LINUX - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-unknown-linux-gnueabihf/bin - GCC_PREFIX=arm-unknown-linux-gnueabihf + TOOLCHAIN_ROOT = /opt/cross/bin endif - + + ifdef GCC_PREFIX + #You have specified GCC_PREFIX with an environment variable + else + GCC_PREFIX = arm-linux-gnueabihf + endif + PLATFORM_CXX = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-g++ PLATFORM_CC = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-gcc PLATFORM_AR = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ar PLATFORM_LD = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ld SYSROOT=$(RPI_ROOT) - #$(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/ - # Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) PLATFORM_CFLAGS += --sysroot=$(SYSROOT) - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vcos/pthreads - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/linux - ifneq ($(wildcard $(RPI_ROOT)/etc/debian_version),) - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.6/ - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.6/arm-linux-gnueabihf - else - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.8.2/ - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.8.2/armv6l-unknown-linux-gnueabihf/ - endif - - - PLATFORM_LIBRARY_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/lib - - PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) - + PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.9 + + PLATFORM_LIBRARY_SEARCH_PATHS += $(SYSROOT)/usr/lib/$(GCC_PREFIX) + + PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/usr/lib/$(GCC_PREFIX) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/lib/$(GCC_PREFIX) + PKG_CONFIG_LIBDIR=$(SYSROOT)/usr/lib/pkgconfig:$(SYSROOT)/usr/lib/arm-linux-gnueabihf/pkgconfig:$(SYSROOT)/usr/share/pkgconfig endif diff --git a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.default.mk b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.default.mk index 2719123509e..5540567c4e9 100644 --- a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.default.mk +++ b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.default.mk @@ -70,27 +70,38 @@ PLATFORM_PKG_CONFIG_LIBRARIES += glesv1_cm PLATFORM_PKG_CONFIG_LIBRARIES += glesv2 PLATFORM_PKG_CONFIG_LIBRARIES += egl -ifeq ($(CROSS_COMPILING),1) - GCC_PREFIX=arm-linux-gnueabihf - PLATFORM_CXX = $(GCC_PREFIX)-g++ - PLATFORM_CC = $(GCC_PREFIX)-gcc - PLATFORM_AR = $(GCC_PREFIX)-ar - PLATFORM_LD = $(GCC_PREFIX)-ld +ifeq ($(CROSS_COMPILING),1) - # Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) - PLATFORM_CFLAGS += --sysroot=$(SYSROOT) + ifdef TOOLCHAIN_ROOT + #You have specified TOOLCHAIN_ROOT with an environment variable + else + TOOLCHAIN_ROOT = /opt/cross/bin + endif + + ifdef GCC_PREFIX + #You have specified GCC_PREFIX with an environment variable + else + GCC_PREFIX = arm-linux-gnueabihf + endif - PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.6/ - PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.6/arm-linux-gnueabihf + PLATFORM_CXX = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-g++ + PLATFORM_CC = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-gcc + PLATFORM_AR = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ar + PLATFORM_LD = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ld + SYSROOT=$(RPI_ROOT) - PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/usr/lib - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/usr/lib/arm-linux-gnueabihf - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/lib - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/lib/arm-linux-gnueabihf + PLATFORM_CFLAGS += --sysroot=$(SYSROOT) + PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.9 + + PLATFORM_LIBRARY_SEARCH_PATHS += $(SYSROOT)/usr/lib/$(GCC_PREFIX) + + PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/usr/lib/$(GCC_PREFIX) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/lib/$(GCC_PREFIX) + PKG_CONFIG_LIBDIR=$(SYSROOT)/usr/lib/pkgconfig:$(SYSROOT)/usr/lib/arm-linux-gnueabihf/pkgconfig:$(SYSROOT)/usr/share/pkgconfig - PLATFORM_LIBRARIES += dl endif + diff --git a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.rpi2.mk b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.raspberry2.mk similarity index 80% rename from libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.rpi2.mk rename to libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.raspberry2.mk index abdef169e03..48151aa7afd 100644 --- a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.rpi2.mk +++ b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.raspberry2.mk @@ -65,11 +65,6 @@ PLATFORM_DEFINES += HAVE_LIBBCM_HOST PLATFORM_DEFINES += USE_EXTERNAL_LIBBCM_HOST PLATFORM_DEFINES += USE_VCHIQ_ARM -# Fix for firmware update @ -# https://github.com/Hexxeh/rpi-firmware/commit/ca3703d2d282ac96a97650e2e496276727e1b65b -ifeq ($(strip $(shell cat $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/vc_dispmanx.h | grep VC_IMAGE_TRANSFORM_T)),) -PLATFORM_DEFINES += USE_DISPMANX_TRANSFORM_T -endif ################################################################################ # PLATFORM REQUIRED ADDONS @@ -154,10 +149,10 @@ PLATFORM_LDFLAGS += -pthread ################################################################################ # Broadcom hardware interface library -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/IL -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vcos/pthreads -PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vmcs_host/linux +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/IL +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vcos/pthreads +PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/linux ########################################################################################## @@ -169,7 +164,7 @@ PLATFORM_HEADER_SEARCH_PATHS += /opt/vc/include/interface/vmcs_host/linux # Note: Leave a leading space when adding list items with the += operator ########################################################################################## -PLATFORM_LIBRARY_SEARCH_PATHS += /opt/vc/lib +PLATFORM_LIBRARY_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/lib ################################################################################ @@ -190,49 +185,38 @@ PLATFORM_LIBRARY_SEARCH_PATHS += /opt/vc/lib #PLATFORM_PKG_CONFIG_LIBRARIES += gstreamer-egl-$(GST_VERSION) PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppGLFWWindow.cpp -$(info $(PLATFORM_ARCH)) + ifeq ($(CROSS_COMPILING),1) - ifneq ($(wildcard $(RPI_ROOT)/etc/debian_version),) - #RASPBIAN - ifeq ($(HOST_ARCH),x86_64) - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin - else - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin - endif - GCC_PREFIX=arm-linux-gnueabihf + + ifdef TOOLCHAIN_ROOT + #You have specified TOOLCHAIN_ROOT with an environment variable else - #ARCH LINUX - TOOLCHAIN_ROOT = $(RPI_TOOLS)/arm-unknown-linux-gnueabihf/bin - GCC_PREFIX=arm-unknown-linux-gnueabihf + TOOLCHAIN_ROOT = /opt/cross/bin endif - + + ifdef GCC_PREFIX + #You have specified GCC_PREFIX with an environment variable + else + GCC_PREFIX = arm-linux-gnueabihf + endif + PLATFORM_CXX = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-g++ PLATFORM_CC = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-gcc PLATFORM_AR = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ar PLATFORM_LD = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ld SYSROOT=$(RPI_ROOT) - #$(RPI_TOOLS)/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/ - # Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) PLATFORM_CFLAGS += --sysroot=$(SYSROOT) - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vcos/pthreads - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/include/interface/vmcs_host/linux - ifneq ($(wildcard $(RPI_ROOT)/etc/debian_version),) - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.6/ - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.6/arm-linux-gnueabihf - else - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.8.2/ - PLATFORM_HEADER_SEARCH_PATHS += $(RPI_ROOT)/usr/include/c++/4.8.2/armv6l-unknown-linux-gnueabihf/ - endif - - - PLATFORM_LIBRARY_SEARCH_PATHS += $(RPI_ROOT)/opt/vc/lib - - PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) - + PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.9 + + PLATFORM_LIBRARY_SEARCH_PATHS += $(SYSROOT)/usr/lib/$(GCC_PREFIX) + + PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/usr/lib/$(GCC_PREFIX) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/lib/$(GCC_PREFIX) + PKG_CONFIG_LIBDIR=$(SYSROOT)/usr/lib/pkgconfig:$(SYSROOT)/usr/lib/arm-linux-gnueabihf/pkgconfig:$(SYSROOT)/usr/share/pkgconfig endif diff --git a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.udoo.mk b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.udoo.mk index 0b62046bcc9..bb3d3dc9eef 100644 --- a/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.udoo.mk +++ b/libs/openFrameworksCompiled/project/linuxarmv7l/config.linuxarmv7l.udoo.mk @@ -72,27 +72,38 @@ PLATFORM_LIBRARIES += GLESv1_CM PLATFORM_LIBRARIES += GLESv2 PLATFORM_LIBRARIES += EGL -ifeq ($(CROSS_COMPILING),1) - GCC_PREFIX=arm-linux-gnueabihf - PLATFORM_CXX = $(GCC_PREFIX)-g++ - PLATFORM_CC = $(GCC_PREFIX)-gcc - PLATFORM_AR = $(GCC_PREFIX)-ar - PLATFORM_LD = $(GCC_PREFIX)-ld +ifeq ($(CROSS_COMPILING),1) - # Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) - PLATFORM_CFLAGS += --sysroot=$(SYSROOT) + ifdef TOOLCHAIN_ROOT + #You have specified TOOLCHAIN_ROOT with an environment variable + else + TOOLCHAIN_ROOT = /opt/cross/bin + endif + + ifdef GCC_PREFIX + #You have specified GCC_PREFIX with an environment variable + else + GCC_PREFIX = arm-linux-gnueabihf + endif - PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.6/ - PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.6/arm-linux-gnueabihf + PLATFORM_CXX = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-g++ + PLATFORM_CC = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-gcc + PLATFORM_AR = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ar + PLATFORM_LD = $(TOOLCHAIN_ROOT)/$(GCC_PREFIX)-ld + SYSROOT=$(RPI_ROOT) - PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/usr/lib - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/usr/lib/arm-linux-gnueabihf - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/lib - PLATFORM_LDFLAGS += -Wl,-rpath-link $(SYSROOT)/lib/arm-linux-gnueabihf + PLATFORM_CFLAGS += --sysroot=$(SYSROOT) + PLATFORM_HEADER_SEARCH_PATHS += $(SYSROOT)/usr/include/c++/4.9 + + PLATFORM_LIBRARY_SEARCH_PATHS += $(SYSROOT)/usr/lib/$(GCC_PREFIX) + + PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/usr/lib/$(GCC_PREFIX) + PLATFORM_LDFLAGS += -Wl,-rpath=$(SYSROOT)/lib/$(GCC_PREFIX) + PKG_CONFIG_LIBDIR=$(SYSROOT)/usr/lib/pkgconfig:$(SYSROOT)/usr/lib/arm-linux-gnueabihf/pkgconfig:$(SYSROOT)/usr/share/pkgconfig - PLATFORM_LIBRARIES += dl endif + diff --git a/libs/openFrameworksCompiled/project/makefileCommon/compile.core.mk b/libs/openFrameworksCompiled/project/makefileCommon/compile.core.mk index 14611275571..af4f3858c40 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/compile.core.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/compile.core.mk @@ -198,7 +198,7 @@ endif # targets that are "recipe" only -- that is recipes that respond to specific # requests, not filenames or lists of filenames. .PNONY targets are used to # avoid conflict with files of the same name and to improve performance. -.PHONY: all Debug Release after clean CleanDebug CleanRelease help +.PHONY: all Debug Release after clean CleanDebug CleanRelease help force Release: ifndef ABIS_TO_COMPILE_RELEASE @@ -228,19 +228,24 @@ DebugABI: $(TARGET) all: @$(MAKE) --no-print-directory Debug @$(MAKE) --no-print-directory Release + +$(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags: force + @mkdir -p $(OF_CORE_OBJ_OUTPUT_PATH) + @if [ "$(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS))" != "$(strip $$(cat $@))" ]; then echo $(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS))> $@; fi + #This rule does the compilation -$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.cpp +$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.cpp $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) $(CXX) $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_CORE_OBJ_OUTPUT_PATH)$*.d -MT$(OF_CORE_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.mm +$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.mm $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) $(CXX) $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_CORE_OBJ_OUTPUT_PATH)$*.d -MT$(OF_CORE_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.m +$(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.m $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) $(CC) $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_CORE_OBJ_OUTPUT_PATH)$*.d -MT$(OF_CORE_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< @@ -249,17 +254,17 @@ $(OF_CORE_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/%.m # $(TARGET) : $(OF_CORE_OBJ_FILES) means that each of the items in the # $(OF_CORE_OBJ_FILES) must be processed first ifeq ($(SHAREDCORE),1) -$(TARGET) : $(OF_CORE_OBJ_FILES) +$(TARGET) : $(OF_CORE_OBJ_FILES) $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Creating library " $(TARGET) @mkdir -p $(@D) $(CC) -shared $(OF_CORE_OBJ_FILES) -o $@ else ifeq ($(BYTECODECORE),1) -$(TARGET) : $(OF_CORE_OBJ_FILES) +$(TARGET) : $(OF_CORE_OBJ_FILES) $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Creating library " $(TARGET) @mkdir -p $(@D) $(CC) $(OF_CORE_OBJ_FILES) -o $@ else -$(TARGET) : $(OF_CORE_OBJ_FILES) +$(TARGET) : $(OF_CORE_OBJ_FILES) $(OF_CORE_OBJ_OUTPUT_PATH).compiler_flags @echo "Creating library " $(TARGET) @mkdir -p $(@D) $(AR) ${ARFLAGS} "$@" $(OF_CORE_OBJ_FILES) diff --git a/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk b/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk index fa195b28125..cb554d78f10 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk @@ -119,7 +119,7 @@ ifeq ($(findstring ABI,$(MAKECMDGOALS)),ABI) endif -.PHONY: all Debug Release after clean CleanDebug CleanRelease help +.PHONY: all Debug Release after clean CleanDebug CleanRelease help force Release: @@ -184,119 +184,200 @@ else @$(PLATFORM_RUN_COMMAND) endif -#This rule does the compilation +$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags: force + @mkdir -p $(OF_PROJECT_OBJ_OUTPUT_PATH) + @if [ "$(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) $(OPTIMIZATION_LDFLAGS) $(LDFLAGS))" != "$(strip $$(cat $@))" ]; then echo $(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) $(OPTIMIZATION_LDFLAGS) $(LDFLAGS)) > $@; fi + +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags: force + @mkdir -p $(OF_PROJECT_OBJ_OUTPUT_PATH) + @mkdir -p $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH) + @if [ "$(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS))" != "$(strip $$(cat $@))" ]; then echo $(strip $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS)) > $@; fi + +# Rules to compile the project sources #$(OBJS): $(SOURCES) -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cpp +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cpp $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cxx $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cc $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.m $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.mm $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.c $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags + @echo "Compiling" $< + @mkdir -p $(@D) + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.S $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + + + + + + -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cxx +# Rules to compile the project external sources +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cpp $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.cc +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cxx $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + @$(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.m +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cc $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.mm +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.m $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.c +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.mm $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_ROOT)/%.S +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.c $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cpp +$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.S $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(PROJECT_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + + -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cxx + +# Rules to compile the addons sources when the addon path is specified explicitly +PROJECT_ADDONS_CPPS=$(addsuffix %.cpp,$(PROJECT_ADDON_PATHS)) +PROJECT_ADDONS_OBJ_PATH=$(realpath .)/$(OF_PROJECT_OBJ_OUTPUT_PATH)addons/ +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_CPPS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - @$(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.cc +PROJECT_ADDONS_CXXS=$(addsuffix %.cxx,$(PROJECT_ADDON_PATHS)) +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_CXXS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + @$(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.m +PROJECT_ADDONS_MS=$(addsuffix %.m,$(PROJECT_ADDON_PATHS)) +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_MS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.mm +PROJECT_ADDONS_MMS=$(addsuffix %.mm,$(PROJECT_ADDON_PATHS)) +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_MMS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.c +PROJECT_ADDONS_CCS=$(addsuffix %.cc,$(PROJECT_ADDON_PATHS)) +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_CCS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif -$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(PROJECT_EXTERNAL_SOURCE_PATHS)/%.S +PROJECT_ADDONS_SS=$(addsuffix %.S,$(PROJECT_ADDON_PATHS)) +$(PROJECT_ADDONS_OBJ_PATH)%.o: $(PROJECT_ADDONS_SS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags +ifdef PROJECT_ADDON_PATHS @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(PROJECT_ADDONS_OBJ_PATH)$*.d -MT $(PROJECT_ADDONS_OBJ_PATH)$*.o -o $@ -c $< +endif + + + + + -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.cpp +# Rules to compile the standard addons sources +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.cpp $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.cxx +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.cxx $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.cc +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.cc $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.m +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.m $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.mm +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.mm $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.c +$(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.c $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ROOT)/addons/%.S +$(OF_ADDONS_PATH)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)%.o: $(OF_ADDONS_PATH)/%.S $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) -MMD -MP -MF $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ROOT)/addons/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< + $(CC) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(ADDON_INCLUDE_CFLAGS) -MMD -MP -MF $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.d -MT $(OF_ADDONS_PATH)/$(OF_PROJECT_OBJ_OUTPUT_PATH)$*.o -o $@ -c $< -$(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/%.o: $(OF_ROOT)/libs/openFrameworks/%.cpp + + +# Rules to compile the addons sources from the core +$(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/%.o: $(OF_ROOT)/libs/openFrameworks/%.cpp $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo "Compiling" $< @mkdir -p $(@D) - $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/$*.o -o $@ -c $< + $(CXX) -c $(OPTIMIZATION_CFLAGS) $(CFLAGS) $(CXXFLAGS) $(OF_CORE_INCLUDES_CFLAGS) -MMD -MP -MF $(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/$*.d -MT $(OF_PROJECT_OBJ_OUTPUT_PATH)libs/openFrameworks/$*.o -o $@ -c $< + + -$(TARGET): $(OF_PROJECT_OBJS) $(OF_PROJECT_ADDONS_OBJS) $(OF_PROJECT_LIBS) $(TARGET_LIBS) +# Rules to link the project +$(TARGET): $(OF_PROJECT_OBJS) $(OF_PROJECT_ADDONS_OBJS) $(OF_PROJECT_LIBS) $(TARGET_LIBS) $(OF_PROJECT_OBJ_OUTPUT_PATH).compiler_flags @echo 'Linking $(TARGET) for $(ABI_LIB_SUBPATH)' @mkdir -p $(@D) $(CXX) -o $@ $(OPTIMIZATION_LDFLAGS) $(OF_PROJECT_OBJS) $(OF_PROJECT_ADDONS_OBJS) $(TARGET_LIBS) $(OF_PROJECT_LIBS) $(LDFLAGS) $(OF_CORE_LIBS) diff --git a/libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk b/libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk index 83e20ff9b32..3a66b5ceaed 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk @@ -7,13 +7,13 @@ define parse_addons_includes $(eval ADDONS_INCLUDES_FILTER = $(addprefix $1/, $(ADDON_INCLUDES_EXCLUDE))) \ $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ - $(eval PARSED_ADDONS_SOURCE_INCLUDES = $(shell find $(PARSED_ADDONS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_FILTERED_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_SOURCE_INCLUDES))) \ $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ - $(eval PARSED_ADDONS_LIBS_SOURCE_INCLUDES = $(shell find $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_SOURCE_INCLUDES))) \ $(eval PARSED_ADDONS_LIBS_INCLUDES_PATHS = $(addsuffix /libs/*/include, $1)) \ - $(eval PARSED_ADDONS_LIBS_INCLUDES = $(shell find $(PARSED_ADDONS_LIBS_INCLUDES_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_INCLUDES_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_FILTERED_LIBS_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_INCLUDES))) \ $(eval PARSED_ADDONS_INCLUDES = $(PARSED_ADDONS_FILTERED_INCLUDE_PATHS)) \ $(eval PARSED_ADDONS_INCLUDES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS)) \ @@ -24,10 +24,10 @@ endef define parse_addons_sources $(eval ADDONS_SOURCES_FILTER = $(addprefix $1/, $(ADDON_SOURCES_EXCLUDE))) \ $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ - $(eval PARSED_ADDONS_OFX_SOURCES = $(shell find $(PARSED_ADDONS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_OFX_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_FILTERED_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_OFX_SOURCES))) \ $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ - $(eval PARSED_ADDONS_LIBS_SOURCES = $(shell find $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_LIBS_SOURCES))) \ $(eval PARSED_ADDONS_SOURCE_FILES = $(PARSED_ADDONS_FILTERED_SOURCE_PATHS)) \ $(eval PARSED_ADDONS_SOURCE_FILES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS)) @@ -36,12 +36,12 @@ endef # parses addons libraries, in PARSED_ADDON_LIBS receives full PATHS to addons and libs_exclude define parse_addons_libraries $(eval PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS = $(filter-out $(ADDON_LIBS_EXCLUDE),$(addsuffix /libs/*/lib/$(ABI_LIB_SUBPATH), $1))) \ - $(eval PARSED_ALL_PLATFORM_LIBS = $(shell find $(PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ALL_PLATFORM_LIBS = $(shell $(FIND) $(PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ $(if $(PARSED_ALL_PLATFORM_LIBS), \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS = $(shell find $(PARSED_ALL_PLATFORM_LIBS) -name *.a 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED = $(shell find $(PARSED_ALL_PLATFORM_LIBS) -name *.so 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell find $(PARSED_ALL_PLATFORM_LIBS) -name *.dylib 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell find $(PARSED_ALL_PLATFORM_LIBS) -name *.dll 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.a 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.so 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dylib 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dll 2> /dev/null | grep -v "/\.[^\.]" )) \ $(eval PARSED_ADDONS_LIBS = $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS)) \ $(eval PARSED_ADDONS_LIBS += $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED)) \ ) @@ -52,7 +52,7 @@ space := space += define src_to_obj - $(addsuffix .o,$(basename $(filter %.c %.cpp %.cc %.cxx %.cc %.s %.S, $(addprefix $(OF_PROJECT_OBJ_OUTPUT_PATH),$(addprefix $2,$1))))) + $(addsuffix .o,$(basename $(filter %.c %.cpp %.cc %.cxx %.cc %.s %.S, $(addprefix $3,$(addprefix $2,$1))))) endef # PARSE addon_config.mk FILES @@ -65,7 +65,16 @@ endef # 5. if the line matches %: but it's not common or platform: set PROCESS_NEXT to false # 6: if PROCESS_NEXT eval the line to put the variable in the makefile space define parse_addon - $(eval addon=$(addprefix $(OF_ADDONS_PATH)/, $1)) \ + $(if $(wildcard $(PROJECT_ROOT)/$1), \ + $(eval addon=$(realpath $(addprefix $(PROJECT_ROOT)/, $1))) \ + $(eval addon_obj_path=$(PROJECT_ROOT)) \ + $(eval ADDON_PATHS+= $(dir $(addon))) \ + $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)addons/) \ + , \ + $(eval addon=$(realpath $(addprefix $(OF_ADDONS_PATH)/, $1))) \ + $(eval addon_obj_path=$(OF_ADDONS_PATH)) \ + $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)) \ + ) \ $(eval ADDON_DEPENDENCIES= ) \ $(eval ADDON_DATA= ) \ $(eval ADDON_CFLAGS= ) \ @@ -128,12 +137,12 @@ define parse_addon $(foreach addon_src, $(strip $(ADDON_SOURCES_FILTERED)), \ $(if $(filter $(addon)%, $(addon_src)), \ $(eval PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ - $(eval SRC_OBJ_FILE=$(addprefix $(OF_ADDONS_PATH)/,$(strip $(call src_to_obj, $(addon_src:$(addon)/%=%), $1/)))) \ + $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ $(eval PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ , \ $(if $(filter $(OF_ROOT)%, $(addon_src)), \ $(eval PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ - $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(addon_src:$(OF_ROOT)/%=%),))) \ + $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(addon_src:$(OF_ROOT)/%=%),,$(obj_prefix)))) \ $(eval PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ ,$(error cannot find addon source file $(addon_src)) \ ) \ @@ -146,14 +155,14 @@ define parse_addon $(foreach addon_dep, $(strip $(ADDON_DEPENDENCIES)), \ $(if $(filter-out $(PROJECT_ADDONS),$(addon_dep)), \ $(eval PROJECT_ADDONS += $(addon_dep)) \ - $(call parse_addon, $(addon_dep)) \ + $(call parse_addon,$(addon_dep)) \ ) \ ) endef $(foreach addon_to_parse, $(PROJECT_ADDONS), \ - $(call parse_addon, $(addon_to_parse)) \ + $(call parse_addon,$(addon_to_parse)) \ ) diff --git a/libs/openFrameworksCompiled/project/makefileCommon/config.linux.common.mk b/libs/openFrameworksCompiled/project/makefileCommon/config.linux.common.mk index c1737539683..28cd3f171b7 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/config.linux.common.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/config.linux.common.mk @@ -124,28 +124,28 @@ PLATFORM_REQUIRED_ADDONS = ifeq ($(CXX),g++) GCC_MAJOR_EQ_4 := $(shell expr `gcc -dumpversion | cut -f1 -d.` \= 4) GCC_MAJOR_GT_4 := $(shell expr `gcc -dumpversion | cut -f1 -d.` \> 4) - GCC_MINOR_GTEQ_7 := $(shell expr `gcc -dumpversion | cut -f2 -d.` \>= 7) + GCC_MINOR_GTEQ_7 := $(shell expr `gcc -dumpversion | cut -f2 -d.` \<= 7) GCC_MINOR_GTEQ_9 := $(shell expr `gcc -dumpversion | cut -f2 -d.` \>= 9) ifeq ("$(GCC_MAJOR_EQ_4)","1") - ifeq ("$(GCC_MINOR_GTEQ_7)","0") - PLATFORM_CFLAGS = -Wall -std=c++0x + ifeq ("$(GCC_MINOR_GTEQ_7)","1") + PLATFORM_CFLAGS = -Wall -std=c++0x -DHAS_TLS=0 else ifeq ("$(GCC_MINOR_GTEQ_9)","1") - PLATFORM_CFLAGS = -Wall -std=c++14 + PLATFORM_CFLAGS = -Wall -std=c++14 -DGCC_HAS_REGEX else PLATFORM_CFLAGS = -Wall -std=c++11 endif endif endif ifeq ("$(GCC_MAJOR_GT_4)","1") - PLATFORM_CFLAGS = -Wall -std=c++14 + PLATFORM_CFLAGS = -Wall -std=c++14 -DGCC_HAS_REGEX endif else ifeq ($(CXX),g++-5) - PLATFORM_CFLAGS = -Wall -std=c++14 + PLATFORM_CFLAGS = -Wall -std=c++14 -DGCC_HAS_REGEX else ifeq ($(CXX),g++-4.9) - PLATFORM_CFLAGS = -Wall -std=c++14 + PLATFORM_CFLAGS = -Wall -std=c++14 -DGCC_HAS_REGEX else ifeq ($(CXX),g++-4.8) PLATFORM_CFLAGS = -Wall -std=c++11 @@ -185,11 +185,23 @@ PLATFORM_LDFLAGS = -Wl,-rpath=./libs:./bin/libs -Wl,--as-needed -Wl,--gc-section # Note: Leave a leading space when adding list items with the += operator ################################################################################ -# RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -O3 +ifndef PROJECT_OPTIMIZATION_CFLAGS_RELEASE + # RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) + PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -O3 -DNDEBUG + + ifneq ($(LINUX_ARM),1) + PLATFORM_OPTIMIZATION_CFLAGS_RELEASE += -march=native -mtune=native + endif +else + PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = $(PROJECT_OPTIMIZATION_CFLAGS_RELEASE) +endif -# DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 +ifndef PROJECT_OPTIMIZATION_CFLAGS_DEBUG + # DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) + PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 #-D_GLIBCXX_DEBUG +else + PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = $(PROJECT_OPTIMIZATION_CFLAGS_DEBUG) +endif ################################################################################ # PLATFORM CORE EXCLUSIONS @@ -228,6 +240,7 @@ endif PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glew/% PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/cairo/% PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glu/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/lib/% PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/Poco PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/CppUnit PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/Poco/% @@ -308,11 +321,11 @@ PLATFORM_STATIC_LIBRARIES = PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoNetSSL.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoNet.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoCrypto.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoJSON.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoMongoDB.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoDataSQLite.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoData.a +#PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoMongoDB.a +#PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoDataSQLite.a +#PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoData.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoUtil.a +PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoJSON.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoXML.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoFoundation.a diff --git a/libs/openFrameworksCompiled/project/makefileCommon/config.project.mk b/libs/openFrameworksCompiled/project/makefileCommon/config.project.mk index 5c87f366220..6d9a2683342 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/config.project.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/config.project.mk @@ -25,11 +25,11 @@ ALL_OF_CORE_LIBS_PLATFORM_LIB_PATHS = $(OF_LIBS_PATH)/*/lib/$(ABI_LIB_SUBPATH) # create a list of all core platform libraries # grep -v "/\.[^\.]" will exclude all .hidden folders and files -ALL_OF_CORE_LIBS_PATHS = $(shell find $(ALL_OF_CORE_LIBS_PLATFORM_LIB_PATHS) -type d -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]" ) +ALL_OF_CORE_LIBS_PATHS = $(shell $(FIND) $(ALL_OF_CORE_LIBS_PLATFORM_LIB_PATHS) -type d -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]" ) # create a list of all core lib directories that have libsorder.make # grep -v "/\.[^\.]" will exclude all .hidden folders and files -ALL_OF_CORE_LIBSORDER_MAKE_FILES = $(shell find $(ALL_OF_CORE_LIBS_PLATFORM_LIB_PATHS) -name libsorder.make -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]" ) +ALL_OF_CORE_LIBSORDER_MAKE_FILES = $(shell $(FIND) $(ALL_OF_CORE_LIBS_PLATFORM_LIB_PATHS) -name libsorder.make -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]" ) # create a list of all of the core libs that require ordering OF_CORE_LIBS_THAT_NEED_ORDER = $(subst /lib/$(ABI_LIB_SUBPATH)/libsorder.make,,$(ALL_OF_CORE_LIBSORDER_MAKE_FILES)) @@ -43,7 +43,7 @@ OF_CORE_LIBS_THAT_DONT_NEED_ORDER = $(filter-out $(OF_CORE_LIBS_THAT_NEED_ORDER) # 2> /dev/null consumes file not found errors from find searches # grep -v "/\.[^\.]" will exclude all .hidden folders and files # TODO: create a varaible for core specific static lib suffix -OF_CORE_LIBS_PLATFORM_LIBS_STATICS = $(shell find $(addsuffix /lib/$(ABI_LIB_SUBPATH),$(OF_CORE_LIBS_THAT_DONT_NEED_ORDER)) -name *.a 2> /dev/null | grep -v "/\.[^\.]" ) +OF_CORE_LIBS_PLATFORM_LIBS_STATICS = $(shell $(FIND) $(addsuffix /lib/$(ABI_LIB_SUBPATH),$(OF_CORE_LIBS_THAT_DONT_NEED_ORDER)) -name *.a 2> /dev/null | grep -v "/\.[^\.]" ) # create a list of all static lib files for the libs that need order # NOTE. this is the most unintuitive line of make script magic in here # How does it work? @@ -62,10 +62,10 @@ OF_CORE_LIBS_PLATFORM_LIBS_STATICS += $(foreach v,$(ALL_OF_CORE_LIBSORDER_MAKE_F # grep -v "/\.[^\.]" will exclude all .hidden folders and files ifeq ($(PLATFORM_OS),Linux) - ALL_OF_CORE_THIRDPARTY_SHARED_LIBS := $(shell find $(OF_LIBS_PATH)/*/lib/$(ABI_LIB_SUBPATH)/*.so -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]") + ALL_OF_CORE_THIRDPARTY_SHARED_LIBS := $(shell $(FIND) $(OF_LIBS_PATH)/*/lib/$(ABI_LIB_SUBPATH)/*.so -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]") else ifeq ($(PLATFORM_OS),Darwin) - ALL_OF_CORE_THIRDPARTY_SHARED_LIBS := $(shell find $(OF_LIBS_PATH)/*/lib/$(ABI_LIB_SUBPATH)/*.dylib -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]") + ALL_OF_CORE_THIRDPARTY_SHARED_LIBS := $(shell $(FIND) $(OF_LIBS_PATH)/*/lib/$(ABI_LIB_SUBPATH)/*.dylib -not -path "*/openFrameworksCompiled/*" 2> /dev/null | grep -v "/\.[^\.]") endif endif @@ -156,7 +156,7 @@ ifdef B_PROCESS_ADDONS # (to escape # in make, you must use \#) # sed '/^$/d' removes all empty lines # (to escape $ in make, you must use $$) - REQUESTED_PROJECT_ADDONS := $(shell cat $(PROJECT_ROOT)/addons.make 2> /dev/null | sed 's/[ ]*\#.*//g' | sed '/^$$/d' ) + REQUESTED_PROJECT_ADDONS := $(shell cat $(PROJECT_ROOT)/addons.make 2> /dev/null | sed 's/[ ]*\#.*//g' | sed '/^$$/d') # deal with platform specfic addons # remove any platform specific addons that were already added to the addons.make file @@ -179,8 +179,10 @@ ifdef B_PROCESS_ADDONS VALID_PROJECT_ADDONS = $(filter $(REQUESTED_PROJECT_ADDONS),$(ALL_INSTALLED_ADDONS)) # create a list of the invalid addons - INVALID_PROJECT_ADDONS = $(filter-out $(VALID_PROJECT_ADDONS),$(REQUESTED_PROJECT_ADDONS)) + INVALID_GLOBAL_ADDONS = $(filter-out $(VALID_PROJECT_ADDONS),$(REQUESTED_PROJECT_ADDONS)) + INVALID_PROJECT_ADDONS = $(filter-out $(INVALID_GLOBAL_ADDONS), $(wildcard $(INVALID_GLOBAL_ADDONS))) + # if any invalid addons are found, throw a warning, but don't cause an error ifneq ($(INVALID_PROJECT_ADDONS),) $(warning The following unknown addons will be ignored:) @@ -205,6 +207,10 @@ ifdef B_PROCESS_ADDONS ifneq ($(PROJECT_ADDONS),) include $(OF_SHARED_MAKEFILES_PATH)/config.addons.mk endif + + ifdef ADDON_PATHS + PROJECT_ADDON_PATHS = $(addsuffix /,$(call remove-dupes-func,$(ADDON_PATHS:%/=%))) + endif endif # generate the list of core libraries @@ -221,9 +227,9 @@ OF_CORE_LIBS += $(PLATFORM_SHARED_LIBRARIES) CORE_PKG_CONFIG_LIBRARIES += $(PROJECT_ADDONS_PKG_CONFIG_LIBRARIES) ifneq ($(strip $(CORE_PKG_CONFIG_LIBRARIES)),) ifeq ($(CROSS_COMPILING),1) - OF_CORE_LIBS += $(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --libs) + OF_CORE_LIBS += $(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);$(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --libs) else - OF_CORE_LIBS += $(shell pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --libs) + OF_CORE_LIBS += $(shell $(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --libs) endif endif @@ -233,9 +239,9 @@ OF_CORE_LIBS += $(addprefix -l,$(PLATFORM_LIBRARIES)) # add the list of addon includes ifneq ($(strip $(PROJECT_ADDONS_PKG_CONFIG_LIBRARIES)),) ifeq ($(CROSS_COMPILING),1) - OF_CORE_INCLUDES_CFLAGS += $(patsubst -I%,-I$(SYSROOT)% ,$(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags)) + OF_CORE_INCLUDES_CFLAGS += $(patsubst -I%,-I$(SYSROOT)% ,$(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);$(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags)) else - OF_CORE_INCLUDES_CFLAGS += $(shell pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags) + OF_CORE_INCLUDES_CFLAGS += $(shell $(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags) endif endif @@ -249,10 +255,13 @@ OF_PROJECT_EXCLUSIONS := $(strip $(PROJECT_EXCLUSIONS)) OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/bin OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/obj OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/.git -OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/bin% -OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/obj% +OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/bin/% +OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/obj/% OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/.git/% OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/%.xcodeproj +OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/%.xcodeproj/% +OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/build +OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/build/% ################################################################################ @@ -263,7 +272,7 @@ OF_PROJECT_EXCLUSIONS += $(PROJECT_ROOT)/%.xcodeproj # create a list of all dirs in the project root that might be valid project # source directories -ALL_OF_PROJECT_SOURCE_PATHS = $(shell find $(PROJECT_ROOT) -mindepth 1 \ +ALL_OF_PROJECT_SOURCE_PATHS = $(shell $(FIND) $(PROJECT_ROOT) -mindepth 1 \ -type d \ -not -path "./bin/*" \ -not -path "./obj/*" \ @@ -271,7 +280,7 @@ ALL_OF_PROJECT_SOURCE_PATHS = $(shell find $(PROJECT_ROOT) -mindepth 1 \ -not -path "*/\.*") ifneq ($(PROJECT_EXTERNAL_SOURCE_PATHS),) ALL_OF_PROJECT_SOURCE_PATHS += $(PROJECT_EXTERNAL_SOURCE_PATHS) - ALL_OF_PROJECT_SOURCE_PATHS += $(shell find $(PROJECT_EXTERNAL_SOURCE_PATHS) -mindepth 1 -type d | grep -v "/\.[^\.]") + ALL_OF_PROJECT_SOURCE_PATHS += $(shell $(FIND) $(PROJECT_EXTERNAL_SOURCE_PATHS) -mindepth 1 -type d | grep -v "/\.[^\.]") endif # be included as locations for header searches via @@ -287,16 +296,14 @@ endif # find all sources inside the project's source directory (recursively) # grep -v "/\.[^\.]" will exclude all .hidden folders and files -OF_PROJECT_SOURCE_FILES = $(shell find $(OF_PROJECT_SOURCE_PATHS) -maxdepth 1 -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" -or -name "*.S" | grep -v "/\.[^\.]") +OF_PROJECT_SOURCE_FILES = $(shell $(FIND) $(OF_PROJECT_SOURCE_PATHS) -maxdepth 1 -name "*.mm" -or -name "*.m" -or -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" -or -name "*.S" | grep -v "/\.[^\.]") ################################################################################ # PROJECT HEADER INCLUDES (-I ...) ################################################################################ -OF_PROJECT_INCLUDES := $(filter-out $(PROJECT_INCLUDE_EXCLUSIONS),$(OF_PROJECT_SOURCE_PATHS)) -OF_PROJECT_INCLUDES += $(filter-out $(PROJECT_INCLUDE_EXCLUSIONS),$(PROJECT_ADDONS_INCLUDES)) - -OF_PROJECT_INCLUDES_CFLAGS = $(addprefix -I,$(OF_PROJECT_INCLUDES)) +OF_PROJECT_INCLUDES_CFLAGS := $(addprefix -I,$(filter-out $(PROJECT_INCLUDE_EXCLUSIONS),$(OF_PROJECT_SOURCE_PATHS))) +OF_ADDON_INCLUDES_CFLAGS += $(addprefix -I,$(filter-out $(PROJECT_INCLUDE_EXCLUSIONS),$(PROJECT_ADDONS_INCLUDES))) ifdef MAKEFILE_DEBUG $(info ---OF_PROJECT_INCLUDES_CFLAGS---) @@ -335,9 +342,6 @@ OF_PROJECT_CFLAGS += $(PROJECT_CFLAGS) OF_PROJECT_CFLAGS += $(PROJECT_ADDONS_CFLAGS) OF_PROJECT_CFLAGS += $(USER_CFLAGS) # legacy OF_PROJECT_CFLAGS += $(OF_PROJECT_DEFINES_CFLAGS) -OF_PROJECT_CFLAGS += $(OF_PROJECT_INCLUDES_CFLAGS) -OF_PROJECT_CFLAGS += $(OF_CORE_INCLUDES_CFLAGS) - OF_PROJECT_CXXFLAGS = $(OF_CORE_BASE_CXXFLAGS) @@ -407,6 +411,9 @@ CFLAGS = $(strip $(ALL_CFLAGS)) # clean up all extra whitespaces in the CFLAGS CXXFLAGS = $(strip $(ALL_CXXFLAGS)) +PROJECT_INCLUDE_CFLAGS = $(strip $(OF_CORE_INCLUDES_CFLAGS) $(OF_PROJECT_INCLUDES_CFLAGS) $(OF_ADDON_INCLUDES_CFLAGS)) +ADDON_INCLUDE_CFLAGS = $(strip $(OF_CORE_INCLUDES_CFLAGS) $(OF_ADDON_INCLUDES_CFLAGS)) + ################################################################################ # LDFLAGS ################################################################################ @@ -488,7 +495,7 @@ ifdef MAKEFILE_DEBUG endif -OF_PROJECT_OBJ_FILES = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cxx,%.o,$(patsubst %.cc,%.o,$(patsubst %.S,%.o,$(OF_PROJECT_SOURCE_FILES)))))) +OF_PROJECT_OBJ_FILES = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cxx,%.o,$(patsubst %.cc,%.o,$(patsubst %.S,%.o,$(patsubst %.mm,%.o,$(patsubst %.m,%.o,$(OF_PROJECT_SOURCE_FILES)))))))) OBJS_WITH_PREFIX = $(addprefix $(OF_PROJECT_OBJ_OUTPUT_PATH),$(OF_PROJECT_OBJ_FILES)) OBJS_WITHOUT_EXTERNAL = $(subst $(strip $(PROJECT_EXTERNAL_SOURCE_PATHS)),,$(OBJS_WITH_PREFIX)) OF_PROJECT_OBJS = $(subst $(PROJECT_ROOT)/,,$(OBJS_WITHOUT_EXTERNAL)) diff --git a/libs/openFrameworksCompiled/project/makefileCommon/config.shared.mk b/libs/openFrameworksCompiled/project/makefileCommon/config.shared.mk index 601c1b101de..067f16046ef 100644 --- a/libs/openFrameworksCompiled/project/makefileCommon/config.shared.mk +++ b/libs/openFrameworksCompiled/project/makefileCommon/config.shared.mk @@ -34,6 +34,8 @@ ifeq ($(CC),$(EMSCRIPTEN)/emcc) PLATFORM_OS=emscripten endif +FIND=find + # if not defined, determine this platform's operating system via uname -s ifndef PLATFORM_OS # determine from the uname if not defined manually @@ -42,18 +44,32 @@ endif HOST_OS=$(shell uname -s) $(info HOST_OS=${HOST_OS}) -# if not defined, determine this platform's architecture via uname -m -ifndef PLATFORM_ARCH - # determine from the uname - PLATFORM_ARCH=$(shell uname -m) +#check for Raspbian as armv7l needs to use armv6l architecture +ifdef RPI_ROOT + ifeq ($(shell grep ID=raspbian $(RPI_ROOT)/etc/*-release),ID=raspbian) + IS_RASPBIAN=1 + endif endif -HOST_ARCH=$(shell uname -m) -$(info HOST_ARCH=${HOST_ARCH}) -ifneq ($(HOST_ARCH),$(PLATFORM_ARCH)) - CROSS_COMPILING=1 +ifdef IS_RASPBIAN + PLATFORM_ARCH=armv6l + HOST_ARCH=armv6l + ifdef RPI_ROOT + CROSS_COMPILING=1 + endif else - CROSS_COMPILING=0 + HOST_ARCH=$(shell uname -m) + ifndef PLATFORM_ARCH + # determine from the uname + PLATFORM_ARCH=$(shell uname -m) + endif + ifndef CROSS_COMPILING + ifneq ($(HOST_ARCH),$(PLATFORM_ARCH)) + CROSS_COMPILING=1 + else + CROSS_COMPILING=0 + endif + endif endif #$(info PLATFORM_ARCH=$(PLATFORM_ARCH)) @@ -61,6 +77,8 @@ endif #$(info HOST_ARCH=$(HOST_ARCH)) #$(info HOST_OS=$(HOST_OS)) #$(info CROSS_COMPILING=$(CROSS_COMPILING)) +#$(info PLATFORM_VARIANT=$(PLATFORM_VARIANT)) +#$(info IS_RASPBIAN=$(IS_RASPBIAN)) # if not defined, construct the default PLATFORM_LIB_SUBPATH ifndef PLATFORM_LIB_SUBPATH @@ -80,7 +98,11 @@ ifndef PLATFORM_LIB_SUBPATH $(error This makefile does not support your architecture $(PLATFORM_ARCH)) endif else ifneq (,$(findstring MINGW32_NT,$(PLATFORM_OS))) - PLATFORM_LIB_SUBPATH=win_cb + PLATFORM_LIB_SUBPATH=msys2 + else ifneq (,$(findstring MSYS_NT,$(PLATFORM_OS))) + PLATFORM_LIB_SUBPATH=msys2 + else ifneq (,$(findstring MINGW64_NT,$(PLATFORM_OS))) + PLATFORM_LIB_SUBPATH=msys2 else ifeq ($(PLATFORM_OS),Android) PLATFORM_LIB_SUBPATH=android else ifeq ($(PLATFORM_OS),Darwin) @@ -196,7 +218,7 @@ $(error This package doesn't support your platform, probably you downloaded the endif # generate a list of valid core platform variants from the files in the platform makefiles directory -AVAILABLE_PLATFORM_VARIANTS=$(shell find $(OF_PLATFORM_MAKEFILES)/config.*.mk -maxdepth 1 -type f | sed -E 's/.*\.([^\.]*)\.mk/\1/' ) +AVAILABLE_PLATFORM_VARIANTS=$(shell $(FIND) $(OF_PLATFORM_MAKEFILES)/config.*.mk -maxdepth 1 -type f | sed -E 's/.*\.([^\.]*)\.mk/\1/' ) AVAILABLE_PLATFORM_VARIANTS+=default # check to see if we have a file for the desired variant. if not, quit and list the variants. @@ -213,6 +235,8 @@ else ABI_LIB_SUBPATH=$(PLATFORM_LIB_SUBPATH) endif +PLATFORM_PKG_CONFIG ?= pkg-config + ################################ FLAGS ######################################### # define the location of the core path @@ -239,7 +263,7 @@ CORE_EXCLUSIONS = $(strip $(PLATFORM_CORE_EXCLUSIONS)) # find all of the source directories # grep -v "/\.[^\.]" will exclude all .hidden folders and files -ALL_OF_CORE_SOURCE_PATHS=$(shell find $(OF_LIBS_OPENFRAMEWORKS_PATH) -maxdepth 1 -mindepth 1 -type d | grep -v "/\.[^\.]" ) +ALL_OF_CORE_SOURCE_PATHS=$(shell $(FIND) $(OF_LIBS_OPENFRAMEWORKS_PATH) -maxdepth 1 -mindepth 1 -type d | grep -v "/\.[^\.]" ) # create a list of core source PATHS, filtering out any items that have a match in the CORE_EXCLUSIONS list OF_CORE_SOURCE_PATHS=$(filter-out $(CORE_EXCLUSIONS),$(ALL_OF_CORE_SOURCE_PATHS)) @@ -251,7 +275,7 @@ OF_CORE_HEADER_PATHS = $(OF_LIBS_OPENFRAMEWORKS_PATH) $(OF_CORE_SOURCE_PATHS) # add folders or single files to exclude fromt he compiled lib # grep -v "/\.[^\.]" will exclude all .hidden folders and files -ALL_OF_CORE_THIRDPARTY_HEADER_PATHS = $(shell find $(OF_LIBS_PATH)/*/include -type d | grep -v "/\.[^\.]") +ALL_OF_CORE_THIRDPARTY_HEADER_PATHS = $(shell $(FIND) $(OF_LIBS_PATH)/*/include -type d | grep -v "/\.[^\.]") # filter out all excluded files / folders that were defined above OF_CORE_THIRDPARTY_HEADER_PATHS = $(filter-out $(CORE_EXCLUSIONS),$(ALL_OF_CORE_THIRDPARTY_HEADER_PATHS)) @@ -266,13 +290,13 @@ CORE_PKG_CONFIG_LIBRARIES += $(PROJECT_PKG_CONFIG_LIBRARIES) ifneq ($(strip $(CORE_PKG_CONFIG_LIBRARIES)),) $(info checking pkg-config libraries: $(CORE_PKG_CONFIG_LIBRARIES)) - ifneq ($(shell pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --exists; echo $$?),0) + ifneq ($(shell $(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --exists; echo $$?),0) $(error couldn't find some pkg-config packages, did you run the latest install_dependencies.sh?) endif ifeq ($(CROSS_COMPILING),1) - OF_CORE_INCLUDES_CFLAGS += $(patsubst -I%,-I$(SYSROOT)% ,$(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags)) + OF_CORE_INCLUDES_CFLAGS += $(patsubst -I%,-I$(SYSROOT)% ,$(shell export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR);$(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags)) else - OF_CORE_INCLUDES_CFLAGS += $(shell pkg-config "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags) + OF_CORE_INCLUDES_CFLAGS += $(shell $(PLATFORM_PKG_CONFIG) "$(CORE_PKG_CONFIG_LIBRARIES)" --cflags) endif endif @@ -304,8 +328,8 @@ OF_CORE_BASE_CXXFLAGS=$(PLATFORM_CXXFLAGS) # search the directories in the source folders for all .cpp files # filter out all excluded files / folders that were defined above # grep -v "/\.[^\.]" will exclude all .hidden folders and files -OF_CORE_SOURCE_FILES=$(filter-out $(CORE_EXCLUSIONS),$(shell find $(OF_CORE_SOURCE_PATHS) -name "*.cpp" -or -name "*.mm" -or -name "*.m" | grep -v "/\.[^\.]")) -OF_CORE_HEADER_FILES=$(filter-out $(CORE_EXCLUSIONS),$(shell find $(OF_CORE_SOURCE_PATHS) -name "*.h" | grep -v "/\.[^\.]")) +OF_CORE_SOURCE_FILES=$(filter-out $(CORE_EXCLUSIONS),$(shell $(FIND) $(OF_CORE_SOURCE_PATHS) -name "*.cpp" -or -name "*.mm" -or -name "*.m" | grep -v "/\.[^\.]")) +OF_CORE_HEADER_FILES=$(filter-out $(CORE_EXCLUSIONS),$(shell $(FIND) $(OF_CORE_SOURCE_PATHS) -name "*.h" | grep -v "/\.[^\.]")) diff --git a/libs/openFrameworksCompiled/project/win_cb/config.win_cb.default.mk b/libs/openFrameworksCompiled/project/msys2/config.msys2.default.mk similarity index 70% rename from libs/openFrameworksCompiled/project/win_cb/config.win_cb.default.mk rename to libs/openFrameworksCompiled/project/msys2/config.msys2.default.mk index a2b3aa941c0..710f21970ed 100644 --- a/libs/openFrameworksCompiled/project/win_cb/config.win_cb.default.mk +++ b/libs/openFrameworksCompiled/project/msys2/config.msys2.default.mk @@ -28,6 +28,27 @@ PLATFORM_PROJECT_DEBUG_BIN_NAME=$(APPNAME)_debug PLATFORM_PROJECT_RELEASE_BIN_NAME=$(APPNAME) PLATFORM_RUN_COMMAND = +#ifneq (,$(findstring MINMGW64_NT,$(PLATFORM_OS))) +MSYS2_ROOT = /mingw32 +PLATFORM_CFLAGS += -std=gnu++14 -I$(MSYS2_ROOT)/include/cairo -I$(MSYS2_ROOT)/include/glib-2.0 -I$(MSYS2_ROOT)/lib/glib-2.0/include -I$(MSYS2_ROOT)/include/pixman-1 -I$(MSYS2_ROOT)/include -I$(MSYS2_ROOT)/include/freetype2 -I$(MSYS2_ROOT)/include/harfbuzz -I$(MSYS2_ROOT)/include/libpng16 -DUNICODE -D_UNICODE -DPOCO_STATIC +#PLATFORM_CFLAGS += -IC:/msys64/mingw32/include/gstreamer-1.0 -DOF_VIDEO_PLAYER_GSTREAMER +PLATFORM_LDFLAGS += -L$(MSYS_ROOT)/lib -L$(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH) -lpthread +#ifeq ($(PLATFORM_ARCH),x86_64) +CC = $(MSYS2_ROOT)/bin/gcc +CXX = $(MSYS2_ROOT)/bin/g++ +FIND = /usr/bin/find +PLATFORM_AR = $(MSYS2_ROOT)/bin/ar +PLATFORM_LD = $(MSYS2_ROOT)/bin/ld +PLATFORM_PKG_CONFIG = $(MSYS2_ROOT)/bin/pkg-config +#endif +#endif + + +PLATFORM_PROJECT_DEBUG_BIN_NAME=$(APPNAME)_debug.exe +PLATFORM_PROJECT_RELEASE_BIN_NAME=$(APPNAME).exe +PLATFORM_PROJECT_RELEASE_TARGET = bin/$(BIN_NAME) +PLATFORM_PROJECT_DEBUG_TARGET = bin/$(BIN_NAME) +PLATFORM_RUN_COMMAND = cd bin;./$(BIN_NAME) ########################################################################################## # PLATFORM DEFINES @@ -84,17 +105,6 @@ ifeq ($(shell gcc -march=native -S -o /dev/null -xc /dev/null 2> /dev/null; echo PLATFORM_CFLAGS += -mtune=native endif -# Optimization options (http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html) -PLATFORM_CFLAGS += -finline-functions -#PLATFORM_CFLAGS += -funroll-all-loops -#PLATFORM_CFLAGS += -Os - -PLATFORM_CFLAGS += -funroll-loops -PLATFORM_CFLAGS += -mssse3 -PLATFORM_CFLAGS += -fmessage-length=0 - -PLATFORM_CFLAGS += -Wno-multichar -PLATFORM_CFLAGS += -g ################################################################################ # PLATFORM LDFLAGS @@ -121,10 +131,10 @@ PLATFORM_CFLAGS += -g ########################################################################################## # RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os +PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os -DNDEBUG # DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 +PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 #-D_GLIBCXX_DEBUG ########################################################################################## # PLATFORM CORE EXCLUSIONS @@ -143,26 +153,34 @@ PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 PLATFORM_CORE_EXCLUSIONS = # core sources -#PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowGrabber.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowPlayer.cpp +PLATFORM_CORE_EXCLUSIONS += %.mm +PLATFORM_CORE_EXCLUSIONS += %.m +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtUtils.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQuickTimeGrabber.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQuickTimePlayer.cpp +#PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowPlayer.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstUtils.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstVideoGrabber.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstVideoPlayer.cpp - PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppEGLWindow.cpp -PLATFORM_CORE_EXCLUSIONS += %.mm -PLATFORM_CORE_EXCLUSIONS += %.m - # third party PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/Poco PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/CppUnit PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/Poco/% PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/include/CppUnit/% -#PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/videoInput/% -#PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/quicktime/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/quicktime/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glew/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/cairo/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/poco/lib/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/freetype/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/FreeImage/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/assimp/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glut/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openssl/% +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/boost/% ########################################################################################## @@ -195,12 +213,13 @@ PLATFORM_HEADER_SEARCH_PATHS = # Note: Be sure to leave a leading space when using a += operator to add items to the list ########################################################################################## -PLATFORM_LIBRARIES += opengl32 gdi32 msimg32 glu32 dsound winmm dxguid strmiids +PLATFORM_LIBRARIES += ksuser opengl32 gdi32 msimg32 glu32 dsound winmm strmiids #dxguid PLATFORM_LIBRARIES += uuid ole32 oleaut32 setupapi wsock32 ws2_32 Iphlpapi Comdlg32 +PLATFORM_LIBRARIES += freeimage boost_filesystem-mt boost_system-mt freetype cairo +#PLATFORM_LIBRARIES += PocoNetSSL PocoNet PocoCrypto PocoUtil PocoXML PocoFoundation PocoZip PocoJSON PocoData PocoDataSQLite +#PLATFORM_LIBRARIES += gstapp-1.0 gstvideo-1.0 gstbase-1.0 gstreamer-1.0 gobject-2.0 glib-2.0 intl #static libraries (fully qualified paths) -# libssl and libcrypto need to come *after* Poco libs for the linker, and the Poco libs -# need to be linked in the right order. PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoNetSSL.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoNet.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoCrypto.a @@ -212,13 +231,13 @@ PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPoco PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoMongoDB.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoData.a PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/poco/lib/$(ABI_LIB_SUBPATH)/libPocoDataSQLite.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/openssl/lib/$(ABI_LIB_SUBPATH)/libssl.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/openssl/lib/$(ABI_LIB_SUBPATH)/libcrypto.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/videoInput/lib/$(ABI_LIB_SUBPATH)/videoInputLib.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/FreeImage/lib/$(ABI_LIB_SUBPATH)/FreeImage.lib -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/quicktime/lib/$(ABI_LIB_SUBPATH)/qtmlClient.lib -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/glew/lib/$(ABI_LIB_SUBPATH)/libglew32.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/glu/lib/$(ABI_LIB_SUBPATH)/glu32.lib +#PLATFORM_STATIC_LIBRARIES += somestaticlib + +PLATFORM_PKG_CONFIG_LIBRARIES = +PLATFORM_PKG_CONFIG_LIBRARIES += zlib +PLATFORM_PKG_CONFIG_LIBRARIES += openssl +PLATFORM_PKG_CONFIG_LIBRARIES += glew +#PLATFORM_PKG_CONFIG_LIBRARIES += gstreamer-1.0 # shared libraries PLATFORM_SHARED_LIBRARIES = @@ -269,5 +288,68 @@ PLATFORM_LIBRARY_SEARCH_PATHS = ################################################################################ #PLATFORM_CC= -afterplatform: after - @echo \ No newline at end of file +copy_dlls: + @echo " copying dlls to bin" + @cp $(MSYS2_ROOT)/bin/libwinpthread-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libgcc_s_dw2-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libstdc++-6.dll bin/ + @cp $(MSYS2_ROOT)/bin/libboost_filesystem-mt.dll bin/ + @cp $(MSYS2_ROOT)/bin/libboost_system-mt.dll bin/ + @cp $(MSYS2_ROOT)/bin/libbz2-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libcairo-2.dll bin/ + @cp $(MSYS2_ROOT)/bin/LIBEAY32.dll bin/ + @cp $(MSYS2_ROOT)/bin/libfreeimage-3.dll bin/ + @cp $(MSYS2_ROOT)/bin/libfreetype-6.dll bin/ + @cp $(MSYS2_ROOT)/bin/glew32.dll bin/ + @cp $(MSYS2_ROOT)/bin/SSLEAY32.dll bin/ + @cp $(MSYS2_ROOT)/bin/libfontconfig-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libpixman-1-0.dll bin/ + @cp $(MSYS2_ROOT)/bin/libpng16-16.dll bin/ + @cp $(MSYS2_ROOT)/bin/libHalf-2_2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libharfbuzz-0.dll bin/ + @cp $(MSYS2_ROOT)/bin/libexpat-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libiconv-2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libIex-2_2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libIlmImf-2_2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libImath-2_2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libglib-2.0-0.dll bin/ + @cp $(MSYS2_ROOT)/bin/libIlmThread-2_2.dll bin/ + @cp $(MSYS2_ROOT)/bin/liblcms2-2.dll bin/ + @cp $(MSYS2_ROOT)/bin/libintl-8.dll bin/ + @cp $(MSYS2_ROOT)/bin/liblzma-5.dll bin/ + @cp $(MSYS2_ROOT)/bin/libminizip-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libjpeg-8.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopenjp2-7.dll bin/ + @cp $(MSYS2_ROOT)/bin/libraw-10.dll bin/ + @cp $(MSYS2_ROOT)/bin/libtiff-5.dll bin/ + @cp $(MSYS2_ROOT)/bin/libwebp*.dll bin/ + @cp $(MSYS2_ROOT)/bin/zlib1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libjasper-1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_calib3d*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_core*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_features2d*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_flann*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_imgcodecs*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_imgproc*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_ml*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_objdetect*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_photo*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_video*.dll bin/ + @cp $(MSYS2_ROOT)/bin/libopencv_videoio*.dll bin/ + @cp $(MSYS2_ROOT)/bin/tbb.dll bin/ + @cp $(MSYS2_ROOT)/bin/zlib1.dll bin/ + @cp $(MSYS2_ROOT)/bin/libassimp.dll bin/ + +afterplatform: $(TARGET_NAME) + @if [ -d $(OF_EXPORT_PATH)/$(ABI_LIB_SUBPATH) ]; then cp -r $(OF_EXPORT_PATH)/$(ABI_LIB_SUBPATH)/* bin/; fi + @echo + @echo " compiling done" + @echo " to launch the application" + @echo + @echo " cd bin" + @echo " ./$(BIN_NAME)" + @echo "" + @echo " - or -" + @echo "" + @echo " make $(RUN_TARGET)" + @echo \ No newline at end of file diff --git a/libs/openFrameworksCompiled/project/win_cb/icon-debug.ico b/libs/openFrameworksCompiled/project/msys2/icon-debug.ico similarity index 100% rename from libs/openFrameworksCompiled/project/win_cb/icon-debug.ico rename to libs/openFrameworksCompiled/project/msys2/icon-debug.ico diff --git a/libs/openFrameworksCompiled/project/win_cb/icon.ico b/libs/openFrameworksCompiled/project/msys2/icon.ico similarity index 100% rename from libs/openFrameworksCompiled/project/win_cb/icon.ico rename to libs/openFrameworksCompiled/project/msys2/icon.ico diff --git a/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig b/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig index 5a0ed59255e..5bd1663bcc7 100644 --- a/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig +++ b/libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig @@ -28,6 +28,7 @@ HEADER_GLFW = "$(OF_PATH)/libs/glfw/include" HEADER_BOOST = "$(OF_PATH)/libs/boost/include" HEADER_SSL = "$(OF_PATH)/libs/openssl/include" HEADER_UTF8 = "$(OF_PATH)/libs/utf8cpp/include" +HEADER_JSON = "$(OF_PATH)/libs/json/include" LIB_FMODEX = "$(OF_PATH)/libs/fmodex/lib/osx/libfmodex.dylib" LIB_GLUT = "$(OF_PATH)/libs/glut/lib/osx/GLUT.framework/Versions/A/GLUT" @@ -61,7 +62,7 @@ LIB_BOOST_FS = "$(OF_PATH)/libs/boost/lib/osx/boost_filesystem.a" OF_CORE_LIBS = $(LIB_POCO) $(LIB_TESS) $(LIB_GLEW) $(LIB_CAIRO1) $(LIB_CAIRO2) $(LIB_CAIRO3) $(LIB_FMODEX) $(LIB_RTAUDIO) $(LIB_OPENSSL1) $(LIB_OPENSSL2) $(LIB_GLFW) $(LIB_FREEIMAGE) $(LIB_FREETYPE) $(LIB_BOOST_FS) $(LIB_BOOST_SYSTEM) -OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_POCO) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_FMODEX) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_CAIRO) $(HEADER_RTAUDIO) $(HEADER_GLFW) $(HEADER_BOOST) $(HEADER_UTF8) $(HEADER_SSL) +OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_POCO) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_FMODEX) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_CAIRO) $(HEADER_RTAUDIO) $(HEADER_GLFW) $(HEADER_BOOST) $(HEADER_UTF8) $(HEADER_SSL) $(HEADER_JSON) OF_CORE_FRAMEWORKS = -framework Accelerate -framework AGL -framework AppKit -framework ApplicationServices -framework AudioToolbox -framework AVFoundation -framework Cocoa -framework CoreAudio -framework CoreFoundation -framework CoreMedia -framework CoreServices -framework CoreVideo -framework IOKit -framework OpenGL -framework QuartzCore -framework QuickTime -framework QTKit -framework GLUT diff --git a/libs/openFrameworksCompiled/project/osx/Debug.xcconfig b/libs/openFrameworksCompiled/project/osx/Debug.xcconfig index 48c4b47811d..1bcd122e5f0 100644 --- a/libs/openFrameworksCompiled/project/osx/Debug.xcconfig +++ b/libs/openFrameworksCompiled/project/osx/Debug.xcconfig @@ -6,7 +6,7 @@ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES GCC_INLINES_ARE_PRIVATE_EXTERN = NO GCC_MODEL_TUNING = G5 GCC_SYMBOLS_PRIVATE_EXTERN = NO -OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ +OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO GCC_WARN_UNINITIALIZED_AUTOS = YES GCC_WARN_UNUSED_VALUE = NO diff --git a/libs/openFrameworksCompiled/project/osx/Release.xcconfig b/libs/openFrameworksCompiled/project/osx/Release.xcconfig index a2edb5e4ab6..fa424ea28dc 100644 --- a/libs/openFrameworksCompiled/project/osx/Release.xcconfig +++ b/libs/openFrameworksCompiled/project/osx/Release.xcconfig @@ -8,7 +8,7 @@ GCC_MODEL_TUNING = G5 GCC_OPTIMIZATION_LEVEL = 3 GCC_SYMBOLS_PRIVATE_EXTERN = NO GCC_UNROLL_LOOPS = YES -OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ +OTHER_CPLUSPLUSFLAGS = -D__MACOSX_CORE__ -DNDEBUG GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO GCC_WARN_UNINITIALIZED_AUTOS = YES GCC_WARN_UNUSED_VALUE = NO diff --git a/libs/openFrameworksCompiled/project/osx/config.osx.default.mk b/libs/openFrameworksCompiled/project/osx/config.osx.default.mk index 4ddab14da8c..2620bd821b7 100644 --- a/libs/openFrameworksCompiled/project/osx/config.osx.default.mk +++ b/libs/openFrameworksCompiled/project/osx/config.osx.default.mk @@ -176,7 +176,7 @@ PLATFORM_LDFLAGS += -mmacosx-version-min=$(MAC_OS_MIN_VERSION) -v ########################################################################################## # RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os +PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os -DNDEBUG # DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g3 @@ -200,6 +200,14 @@ PLATFORM_CORE_EXCLUSIONS = # core sources PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowGrabber.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowPlayer.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtKitGrabber.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtKitPlayer.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtKitMovieRenderer.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtKitPlayer.mm +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQtUtils.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQuicktimeGrabber.cpp +PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofQuicktimePlayer.cpp + ifneq ($(USE_GST),1) PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstUtils.cpp PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstVideoGrabber.cpp @@ -378,11 +386,14 @@ afterplatform: $(TARGET_NAME) @echo TARGET=$(TARGET) - @install_name_tool -change ./libfmodex.dylib @executable_path/libs/libfmodex.dylib $(TARGET) - @install_name_tool -change @executable_path/../Frameworks/GLUT.framework/Versions/A/GLUT @executable_path/Frameworks/GLUT.framework/Versions/A/GLUT $(TARGET) @mv $(TARGET) bin/$(BIN_NAME).app/Contents/MacOS - @cp -r $(OF_EXPORT_PATH)/$(ABI_LIB_SUBPATH)/* bin/$(BIN_NAME).app/Contents/MacOS + @cp -r $(OF_EXPORT_PATH)/$(ABI_LIB_SUBPATH)/libs/* bin/$(BIN_NAME).app/Contents/MacOS + + +ifdef PROJECT_AFTER_OSX + ${PROJECT_AFTER_OSX} +endif @echo @echo " compiling done" diff --git a/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj/project.pbxproj b/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj/project.pbxproj index 5a0c8b0702a..ff5034ec8cc 100644 --- a/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj/project.pbxproj +++ b/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj/project.pbxproj @@ -867,6 +867,7 @@ OBJROOT = "$(SRCROOT)/../../lib/osx/build/debug/"; PRODUCT_NAME = openFrameworksDebug; SDKROOT = ""; + SKIP_INSTALL = YES; }; name = Debug; }; @@ -895,6 +896,7 @@ OBJROOT = "$(SRCROOT)/../../lib/osx/build/release/"; PRODUCT_NAME = openFrameworks; SDKROOT = ""; + SKIP_INSTALL = YES; }; name = Release; }; @@ -905,7 +907,7 @@ CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../lib/osx/"; CONFIGURATION_TEMP_DIR = "$(SRCROOT)/../../lib/osx/build/debug/"; OBJROOT = "$(SRCROOT)/../../lib/osx/build/debug/"; - ONLY_ACTIVE_ARCH = YES; + ONLY_ACTIVE_ARCH = NO; SDKROOT = ""; }; name = Debug; @@ -917,6 +919,7 @@ CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../lib/osx/"; CONFIGURATION_TEMP_DIR = "$(SRCROOT)/../../lib/osx/build/release/"; OBJROOT = "$(SRCROOT)/../../lib/osx/build/release"; + ONLY_ACTIVE_ARCH = NO; SDKROOT = ""; }; name = Release; diff --git a/libs/openFrameworksCompiled/project/qtcreator/modules/of/helpers.js b/libs/openFrameworksCompiled/project/qtcreator/modules/of/helpers.js new file mode 100644 index 00000000000..f32167c2518 --- /dev/null +++ b/libs/openFrameworksCompiled/project/qtcreator/modules/of/helpers.js @@ -0,0 +1,317 @@ +function listDir(dir){ + var ls = new Process(); + ls.exec("ls", [dir]); + if(ls.exitCode()!==0){ + var error = ls.readStdErr(); + throw("error: " + error) + } + var line = ls.readLine(); + var ret = [] + while(line.trim()!==""){ + ret = ret.concat([line.trim()]); + line = ls.readLine(); + } + ls.close(); + return(ret) +} + +function listDirsRecursive(dir){ + var ret = [] + if(!File.exists(dir)){ + return ret; + } + var find = new Process(); + var params = [dir,'-type','d']; + find.exec("find", params) + if(find.exitCode()!==0){ + find.exec("C:\\msys64\\usr\\bin\\find", params); + if(find.exitCode()!==0){ + find.exec("C:\\msys32\\usr\\bin\\find", params); + if(find.exitCode()!==0){ + var error = find.readStdErr(); + throw("error: " + error) + } + } + } + var line = find.readLine(); + while(line.trim()!==""){ + ret = ret.concat([line.trim()]); + line = find.readLine(); + } + find.close(); + return(ret) +} + +function hasExtension(str, extension){ + var suffix = "." + extension; + return str.indexOf(suffix, str.length - suffix.length) !== -1; +} + +function findLibsRecursive(dir, platform, exclude){ + var ret = [] + if(!File.exists(dir)){ + return ret; + } + var libs = listDir(dir); + for(libdir in libs){ + if(exclude.indexOf(libs[libdir])!==-1){ + continue; + } + + var libpath = dir + '/' + libs[libdir] + '/lib/' + platform + "/" + var find = new Process(); + find.exec('ls', [libpath]) + var line = find.readLine().trim(); + var libFiles = []; + while(line!==""){ + libFiles.push(line); + line = find.readLine().trim(); + } + find.close(); + + var staticLibs = libFiles.filter(function(lib){ + return hasExtension(lib, "a"); + }); + + var sharedLibs = libFiles.filter(function(lib){ + return hasExtension(lib, "so") || hasExtension(lib, "dylib") || hasExtension(lib, "dll"); + }); + + for(var idx in staticLibs){ + ret.push(libpath + staticLibs[idx]) + } + + for(var idx in sharedLibs){ + ret.push(libpath + sharedLibs[idx]) + } + + /*if(sharedLibs.length>0){ + ret.push("-L"+libpath); + } + + for(var idx in sharedLibs){ + var lib = sharedLibs[idx]; + if(lib.indexOf("lib")===0){ + lib = lib.substr(3); + } + lib = lib.split(".")[0]; + ret.push("-l" + lib) + }*/ + } + return(ret) +} + +function findSourceRecursive(dir){ + var ret = [] + if(!File.exists(dir)){ + return ret; + } + var find = new Process(); + var params = [dir ,'-name', '*.cpp' + ,'-or', '-name', '*.h' + ,'-or', '-name', '*.hpp' + ,'-or', '-name', '*.cxx' + ,'-or', '-name', '*.cc' + ,'-or', '-name', '*.c++' + ,'-or', '-name', '*.s' + ,'-or', '-name', '*.S' + ,'-or', '-name', '*.c']; + find.exec("find", params); + if(find.exitCode()!==0){ + find.exec("C:\\msys64\\usr\\bin\\find", params); + if(find.exitCode()!==0){ + find.exec("C:\\msys32\\usr\\bin\\find", params); + if(find.exitCode()!==0){ + var error = find.readStdErr(); + throw("error: " + error) + } + } + } + var line = find.readLine(); + while(line.trim()!==""){ + ret = ret.concat([line.trim()]); + line = find.readLine(); + } + find.close(); + return(ret) +} + +function pkgconfig(pkgs,parameters){ + if(pkgs.length===0){ + return []; + } + var pkgconfig = new Process(); + var arguments = pkgs.concat(parameters); + pkgconfig.exec('pkg-config', arguments); + if(pkgconfig.exitCode()!==0){ + var error = pkgconfig.readStdErr(); + throw("error: " + error) + } + return pkgconfig.readLine().split(" ").filter(function(element){ + return element.trim()!==""; + }); +} + +function addonIncludes(addon){ + var includes = listDirsRecursive(addon + '/src') + try{ + var libs = Helpers.listDir(addon + '/libs'); + var libsIncludes = []; + for(var lib in libs){ + var libpath = addon + '/libs/' + libs[lib]; + var include_path = libpath + "/include" + try{ + var include_paths = listDirsRecursive(libpath); + libsIncludes = libsIncludes.concat(include_paths); + }catch(e){} + } + if(File.exists(addon + '/libs') && libsIncludes.length==0){ + includes = includes.concat(listDirsRecursive(addon + '/libs')); + }else{ + includes = includes.concat(libsIncludes); + } + }catch(e){} + return includes; +} + +function addonSources(addon){ + var sources = findSourceRecursive(addon + '/src') + try{ + sources = sources.concat(Helpers.findSourceRecursive(addon + '/libs')); + }catch(e){} + return sources; +} + +function parseConfig(configPath, variable, currentValue, platform, prefix){ + var values = currentValue.slice(0); + try{ + var section = ""; + var addonconfig = new TextFile(configPath); + while(!addonconfig.atEof()){ + var line = addonconfig.readLine().trim(); + var varValue; + var lineVar; + var valuesList; + if(line==="" || line.startsWith("#")){ + continue; + } + + if(line.indexOf(":") === line.length-1){ + section = line.substr(0,line.length-1); + }else if(section === platform || section === "common" || platform === "all"){ + if(line.indexOf("+=") !== -1){ + varValue = line.split("+="); + lineVar = varValue[0].trim(); + if(lineVar === variable){ + valuesList = varValue[1].split(" ").filter(function(element){ + return element.trim() !== ""; + }); + if(prefix!==undefined){ + valuesList = valuesList.map(function(element){ + if(!FileInfo.isAbsolutePath(element)){ + return prefix + element; + }else{ + return element; + } + }); + } + values = values.concat(valuesList) + } + }else if(line.indexOf("=") !== -1){ + varValue = line.split("="); + lineVar = varValue[0].trim(); + if(lineVar === variable){ + values = varValue[1].split(" ").filter(function(element){ + return element.trim() !== ""; + }); + if(prefix!==undefined){ + values = values.map(function(element){ + if(!FileInfo.isAbsolutePath(element)){ + return prefix + element; + }else{ + return element; + } + }); + } + } + } + } + } + }catch(e){ + //throw(e) + } + + return values; +} + +function parseAddonConfig(addonPath, variable, currentValue, platform, prefix){ + var configPath = addonPath + "/addon_config.mk"; + return parseConfig(configPath, variable, currentValue, platform, prefix); +} + +function removeDuplicates(arrayName){ + var newArray=[]; + label:for(var i=0; i 0) { + + parts = path.split(SCHEME); + scheme = parts[0]; + src = parts[1].split(SLASH); + } else { + + src = path.split(SLASH); + } + + for (var i = 0; i < src.length; ++i) { + + token = src[i]; + + if (token === DOTS) { + target.pop(); + } else if (token !== BLANK && token !== DOT) { + target.push(token); + } + } + + var result = target.join(SLASH).replace(/[\/]{2,}/g, SLASH); + + return (scheme ? scheme + SCHEME : '') + (prependSlash ? SLASH : BLANK) + result; +} + +function absOFRoot(){ + if(FileInfo.isAbsolutePath(project.of_root)){ + return project.of_root; + }else{ + return FileInfo.joinPaths(path, project.of_root); + } +} diff --git a/libs/openFrameworksCompiled/project/qtcreator/modules/of/of.qbs b/libs/openFrameworksCompiled/project/qtcreator/modules/of/of.qbs new file mode 100644 index 00000000000..d8a38d4638c --- /dev/null +++ b/libs/openFrameworksCompiled/project/qtcreator/modules/of/of.qbs @@ -0,0 +1,512 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "helpers.js" as Helpers + +Module{ + name: "ofCore" + property string msys2root: "c:/msys64" + + property string ofRoot: { + if(FileInfo.isAbsolutePath(project.of_root)){ + return project.of_root; + }else{ + return FileInfo.joinPaths(project.sourceDirectory, project.of_root); + } + } + + property string platform: { + if(qbs.targetOS.contains("linux")){ + if(qbs.architecture==="x86_64"){ + return "linux64"; + }else if(qbs.architecture==="x86"){ + return "linux"; + }else{ + throw(qbs.architecture + " not supported yet"); + } + }else if(qbs.targetOS.contains("windows")){ + return "msys2"; + }else if(qbs.targetOS.contains("osx")){ + return "osx"; + }else{ + throw(qbs.targetOS + " not supported yet"); + } + } + + property stringList addons + + readonly property stringList LIBS_EXCEPTIONS: { + if(qbs.targetOS.indexOf("linux")!=-1){ + return [ + "glew", + "cairo", + "glu", + "poco", + "quicktime", + "videoInput", + "freetype", + "FreeImage", + "assimp", + "glut", + "rtAudio", + "openssl", + "boost", + "openFrameworksCompiled" + ]; + }else if(platform==="msys2"){ + return [ + "glew", + "cairo", + "poco", + "freetype", + "FreeImage", + "assimp", + "glut", + "rtAudio", + "openssl", + "boost", + "openFrameworksCompiled" + ]; + }else if(platform==="osx"){ + return [ + "poco", + "quicktime", + "glut", + "openFrameworksCompiled", + ]; + + } + } + + readonly property stringList PKG_CONFIGS: { + if(qbs.targetOS.indexOf("linux")!=-1){ + return [ + "cairo", + "gstreamer-1.0", + "zlib", + "gstreamer-app-1.0", + "gstreamer-video-1.0", + "gstreamer-base-1.0", + "libudev", + "freetype2", + "fontconfig", + "sndfile", + "openal", + "openssl", + "libpulse-simple", + "alsa", + "gl", + "glu", + "glew", + "gtk+-3.0", + "libmpg123", + ].concat(pkgConfigs) + }else if(qbs.targetOS.indexOf("windows")!=-1){ + return [ + "zlib", + "openssl", + "glew", + ].concat(pkgConfigs) + }else{ + return []; + } + } + + readonly property stringList ADDITIONAL_LIBS: { + if(qbs.targetOS.contains("linux")){ + return [ + "glut", + "X11", + "Xrandr", + "Xxf86vm", + "Xi", + "Xcursor", + "dl", + "pthread", + "freeimage", + "rtaudio", + "boost_filesystem", + "boost_system", + ]; + }else if(platform === "msys2"){ + return [ + 'opengl32', 'gdi32', 'msimg32', 'glu32', 'dsound', 'winmm', 'strmiids', + 'uuid', 'ole32', 'oleaut32', 'setupapi', 'wsock32', 'ws2_32', 'Iphlpapi', 'Comdlg32', + 'freeimage', 'boost_filesystem-mt', 'boost_system-mt', 'freetype', 'cairo','pthread' + ]; + } + } + + readonly property stringList PKG_CONFIG_INCLUDES: { + if(platform.contains("linux") || platform === "msys2"){ + return Helpers.pkgconfig(PKG_CONFIGS,["--cflags-only-I"]).map(function(element){ + return element.substr(2).trim() + }); + }else{ + return []; + } + } + + readonly property stringList PKG_CONFIG_CFLAGS: { + if(platform.contains("linux") || platform === "msys2"){ + return (Helpers.pkgconfig(PKG_CONFIGS,["--cflags-only-other"])); + }else{ + return []; + } + } + + readonly property stringList PKG_CONFIG_LDFLAGS: { + if(platform.contains("linux") || platform === "msys2"){ + return (Helpers.pkgconfig(PKG_CONFIGS,["--libs"])); + }else{ + return []; + } + } + + readonly property pathList INCLUDE_PATHS: { + var includes = Helpers.listDirsRecursive(ofRoot + "/libs/openFrameworks"); + var libs = Helpers.listDir(ofRoot + '/libs/'); + for(var lib in libs){ + if(LIBS_EXCEPTIONS.indexOf(libs[lib])==-1){ + var libpath = ofRoot + '/libs/' + libs[lib]; + var include_path = libpath + "/include" + var include_paths = Helpers.listDirsRecursive(include_path); + includes = includes.concat(include_paths); + } + } + includes.push(ofRoot+'/libs/poco/include'); + includes = includes.concat(PKG_CONFIG_INCLUDES); + if(platform === "msys2"){ + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/cairo')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/glib-2.0')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/lib/glib-2.0/include')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/pixman-1')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/freetype2')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/harfbuzz')); + includes.push(FileInfo.joinPaths(msys2root,'mingw32/include/libpng16')); + } + + return includes; + } + + readonly property pathList STATIC_LIBS: { + var staticLibraries = Helpers.findLibsRecursive(ofRoot + "/libs",platform,LIBS_EXCEPTIONS); + if(platform === "osx"){ + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoNetSSL.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoNet.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoCrypto.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoUtil.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoJSON.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoXML.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/PocoFoundation.a'); + }else{ + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoNetSSL.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoNet.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoCrypto.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoUtil.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoJSON.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoXML.a'); + staticLibraries.push(ofRoot + '/libs/poco/lib/' + platform + '/libPocoFoundation.a'); + } + return(staticLibraries) + } + + readonly property stringList LDFLAGS: { + var ret = PKG_CONFIG_LDFLAGS; + for(lib in ADDITIONAL_LIBS){ + var libname = ADDITIONAL_LIBS[lib].trim(); + if(libname!=""){ + ret.push("-l" + libname); + } + } + if(qbs.targetOS.contains("windows")){ + ret.push("-L"+FileInfo.joinPaths(msys2root,"mingw32/lib")); + //ret.push("-fuse-ld=gold"); + } + + return STATIC_LIBS.concat(ret); + } + + readonly property stringList addonsMake: { + var allAddons = []; + try{ + var addonsmake = new TextFile(project.sourceDirectory + "/addons.make"); + while(!addonsmake.atEof()){ + var line = addonsmake.readLine().trim(); + allAddons.push(line); + var addonPath = ofRoot + '/addons/' + line; + var dependencies = Helpers.parseAddonConfig(addonPath, "ADDON_DEPENDENCIES", [], platform); + allAddons = allAddons.concat(dependencies); + } + }catch(e){} + return allAddons; + } + + readonly property stringList ADDONS: { + var allAddons = []; + if(addons===undefined){ + allAddons = addonsMake; + }else{ + allAddons = addons; + } + + return Helpers.removeDuplicates(allAddons.map(function(addon){ + var addonPath = Helpers.normalize(FileInfo.joinPaths(project.sourceDirectory, addon)) + if(File.exists(addonPath)){ + return addonPath; + }else{ + return Helpers.normalize(FileInfo.joinPaths(ofRoot, '/addons/', addon)); + } + })); + } + + readonly property stringList ADDON_INCLUDES: { + var includes = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + var addonIncludes = Helpers.addonIncludes(addonPath); + addonIncludes = Helpers.parseAddonConfig(addonPath, "ADDON_INCLUDES", addonIncludes, platform, addonPath+"/"); + var addonIncludesExcludes = Helpers.parseAddonConfig(addonPath, "ADDON_INCLUDES_EXCLUDE", [], platform, addonPath+"/"); + if(addonIncludesExcludes.length>0){ + addonIncludes = addonIncludes.filter(function(element){ + for(var exclude in addonIncludesExcludes){ + var exclude = addonIncludesExcludes[exclude].replace("%",".*"); + var patt = new RegExp(exclude); + var match = patt.exec(element); + if(match!=null){ + return false; + } + } + return true; + }); + } + includes = includes.concat(addonIncludes); + } + return includes; + } + + readonly property pathList ADDONS_SOURCES: { + var sources = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + var addonSources = Helpers.addonSources(addonPath); + addonSources = Helpers.parseAddonConfig(addonPath, "ADDON_SOURCES", addonSources, platform, addonPath+"/"); + var addonSourcesExcludes = Helpers.parseAddonConfig(addonPath, "ADDON_SOURCES_EXCLUDE", [], platform, addonPath+"/"); + if(addonSourcesExcludes.length>0){ + addonSources = addonSources.filter(function(element){ + for(var exclude in addonSourcesExcludes){ + var exclude = addonSourcesExcludes[exclude].replace("%",".*"); + var patt = new RegExp(exclude); + var match = patt.exec(element); + if(match!=null){ + return false; + } + } + return true; + }); + } + sources = sources.concat(addonSources); + var addon_config = FileInfo.joinPaths(addonPath,"addon_config.mk"); + if(File.exists(addon_config)){ + sources.push(addon_config); + } + } + return sources; + } + + readonly property stringList ADDON_LIBS: { + var libs = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + var addonLibs = Helpers.findLibsRecursive(addonPath + "/libs", platform, []); + addonLibs = Helpers.parseAddonConfig(addonPath, "ADDON_LIBS", addonLibs, platform, addonPath+"/"); + var addonLibsExcludes = Helpers.parseAddonConfig(addonPath, "ADDON_LIBS_EXCLUDE", [], platform, addonPath+"/"); + if(addonLibsExcludes.length>0){ + addonLibs = addonLibs.filter(function(element){ + for(var exclude in addonLibsExcludes){ + var exclude = addonLibsExcludes[exclude].replace("%",".*"); + var patt = new RegExp(exclude); + var match = patt.exec(element); + if(match!=null){ + return false; + } + } + return true; + }); + } + libs = libs.concat(addonLibs); + } + return libs; + } + + readonly property stringList ADDON_FRAMEWORKS: { + var frameworks = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + var addonFrameworks = []; + addonFrameworks = Helpers.parseAddonConfig(addonPath, "ADDON_FRAMEWORKS", addonFrameworks, platform, addonPath+"/"); + frameworks = frameworks.concat(addonFrameworks); + } + return frameworks; + } + + readonly property stringList ADDON_PKG_CONFIGS: { + var pkgconfigs = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + pkgconfigs = pkgconfigs.concat(Helpers.parseAddonConfig(addonPath, "ADDON_PKG_CONFIG_LIBRARIES", [], platform)) + } + return pkgconfigs; + } + + readonly property stringList ADDON_PKG_CONFIG_INCLUDES: { + return Helpers.pkgconfig(ADDON_PKG_CONFIGS,["--cflags-only-I"]).map(function(element){ + return element.substr(2).trim() + }) + } + + readonly property stringList ADDON_PKG_CONFIG_CFLAGS: { + return Helpers.pkgconfig(ADDON_PKG_CONFIGS,["--cflags-only-other"]) + } + + readonly property stringList ADDON_PKG_CONFIG_LDFLAGS: { + return Helpers.pkgconfig(ADDON_PKG_CONFIGS,["--libs"]) + } + + readonly property stringList ADDON_CFLAGS: { + var cflags = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + cflags = cflags.concat(Helpers.parseAddonConfig(addonPath, "ADDON_CFLAGS", [], platform)) + } + return cflags; + } + + readonly property stringList ADDON_LDFLAGS: { + var ldflags = []; + for(var addon in ADDONS){ + var addonPath = ADDONS[addon]; + ldflags = ldflags.concat(Helpers.parseAddonConfig(addonPath, "ADDON_LDFLAGS", [], platform)) + } + return ldflags; + } + + readonly property stringList DEFINES: { + var defines = ['GCC_HAS_REGEX', 'OF_USING_GTK', 'OF_USING_MPG123']; + + if(qbs.targetOS.indexOf("windows")>-1){ + defines.concat(['UNICODE','_UNICODE','POCO_STATIC']); + } + return defines; + } + + property stringList pkgConfigs: [] + property pathList includePaths: [] + property stringList cFlags: [] + property stringList cxxFlags: [] + property stringList linkerFlags: [] + property stringList defines: [] + property stringList frameworks: [] + + Depends{ + name: "cpp" + } + + Depends{ + condition: platform==="osx" + name: "bundle" + } + + //cpp.cxxLanguageVersion: "c++14" + cpp.warningLevel: 'default' + cpp.cFlags: PKG_CONFIG_CFLAGS + .concat(['-Wno-unused-parameter']) + .concat(ADDON_PKG_CONFIG_CFLAGS) + .concat(ADDON_CFLAGS) + .concat(cFlags) + + Properties{ + condition: qbs.targetOS.contains("linux") || platform === "msys2" + cpp.cxxFlags: PKG_CONFIG_CFLAGS + .concat(['-Wno-unused-parameter','-std=gnu++14']) + .concat(ADDON_PKG_CONFIG_CFLAGS) + .concat(ADDON_CFLAGS) + .concat(cxxFlags) + } + + Properties{ + condition: platform === "osx" + cpp.cxxLanguageVersion: "c++11" + cpp.cxxStandardLibrary: "libc++" + + cpp.cxxFlags: PKG_CONFIG_CFLAGS + .concat(['-Wno-unused-parameter']) + .concat(ADDON_PKG_CONFIG_CFLAGS) + .concat(ADDON_CFLAGS) + .concat(cxxFlags) + + cpp.frameworks: [ + 'Accelerate', + 'AGL', + 'AppKit', + 'ApplicationServices', + 'AudioToolbox', + 'AVFoundation', + 'Cocoa', + 'CoreAudio', + 'CoreFoundation', + 'CoreMedia', + 'CoreServices', + 'CoreVideo', + 'IOKit', + 'OpenGL', + 'QuartzCore', + ].concat(frameworks) + .concat(ADDON_FRAMEWORKS) + } + + Properties{ + condition: platform === "msys2" + cpp.cxxStandardLibrary: "" + } + + Properties{ + condition: qbs.buildVariant.contains("debug") && platform === "osx" + bundle.infoPlist: ({"CFBundleIconFile":"icon-debug.icns"}) + } + + Properties{ + condition: qbs.buildVariant.contains("release") && platform === "osx" + bundle.infoPlist: ({"CFBundleIconFile":"icon.icns"}) + } + + cpp.includePaths: INCLUDE_PATHS + .concat(ADDON_INCLUDES) + .concat(ADDON_PKG_CONFIG_INCLUDES) + .concat(includePaths) + + cpp.linkerFlags: + LDFLAGS + .concat(ADDON_LIBS) + .concat(ADDON_PKG_CONFIG_LDFLAGS) + .concat(ADDON_LDFLAGS) + .concat(linkerFlags) + + Properties{ + condition: qbs.buildVariant.contains("debug") + cpp.defines: ['DEBUG'].concat(DEFINES).concat(defines) + } + + Properties{ + condition: qbs.buildVariant.contains("release") + cpp.defines: ['NDEBUG'].concat(DEFINES).concat(defines) + } + + Group{ + name: "addons" + files: of.ADDONS_SOURCES + } +} diff --git a/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs b/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs new file mode 100644 index 00000000000..70fad015d64 --- /dev/null +++ b/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs @@ -0,0 +1,136 @@ +import qbs +import qbs.FileInfo; +import qbs.Process +import qbs.File +import qbs.TextFile +import "modules/of/helpers.js" as Helpers + +CppApplication{ + name: "ofApp" + consoleApplication: false + destinationDirectory: Helpers.normalize(FileInfo.joinPaths(project.sourceDirectory,"bin")) + qbsSearchPaths: "." + readonly property string platform: of.platform + + Depends{ + name: "of" + } + + cpp.includePaths: of.cpp.includePaths.concat(Helpers.listDirsRecursive(project.sourceDirectory + '/src')) + + Properties{ + condition: qbs.buildVariant.contains("debug") + targetName: Helpers.parseConfig(project.sourceDirectory + "/config.make","APPNAME",name,"all") + "_debug" + } + + Properties{ + condition: qbs.buildVariant.contains("release") + targetName: Helpers.parseConfig(project.sourceDirectory + "/config.make","APPNAME",name,"all") + } + + // Copy windows dlls from export to bin folder + Transformer { + condition: qbs.targetOS.contains("windows") + inputs: [] + Artifact { + filePath: "bin/fmodex.dll" + fileTags: "processed_file" + } + Artifact { + filePath: "bin/qtmlClient.dll" + fileTags: "processed_file" + } + prepare: { + var cpLibsCmd = new JavaScriptCommand(); + cpLibsCmd.description = "copying dynamic libraries"; + cpLibsCmd.silent = false; + cpLibsCmd.highlight = 'filegen'; + cpLibsCmd.sourceCode = function(){ + var exportDir = FileInfo.joinPaths(project.path, project.of_root, "export", product.platform); + File.copy(FileInfo.joinPaths(exportDir,"fmodex.dll"), project.path+"/bin/fmodex.dll"); + } + + return [cpLibsCmd]; + } + } + + // Copy osx dylibs into bundle and run install_name_tool on the binary + Transformer { + condition: qbs.targetOS.contains("osx") + Artifact { + filePath: FileInfo.joinPaths(parent.destinationDirectory, parent.targetName + ".app", "Contents/MacOS/libfmodex.dylib") + fileTags: "preprocessed_file" + } + prepare: { + var cpLibsCmd = new JavaScriptCommand(); + cpLibsCmd.description = "copying dynamic libraries"; + cpLibsCmd.silent = false; + cpLibsCmd.highlight = 'filegen'; + cpLibsCmd.sourceCode = function(){ + var exportDir; + if(FileInfo.isAbsolutePath(project.of_root)){ + exportDir = Helpers.normalize(FileInfo.joinPaths(project.of_root, "libs/fmodex/lib", product.platform)); + }else{ + exportDir = Helpers.normalize(FileInfo.joinPaths(project.path, project.of_root, "libs/fmodex/lib", product.platform)); + } + + File.copy(FileInfo.joinPaths(exportDir,"libfmodex.dylib"), FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".app", "Contents/MacOS/libfmodex.dylib")); + } + return [cpLibsCmd]; + + } + } + + // Copy osx icon release + Transformer { + condition: qbs.targetOS.contains("osx") && qbs.buildVariant.contains("release") + Artifact { + filePath: FileInfo.joinPaths(parent.destinationDirectory, parent.targetName + ".app", "Contents/Resources/icon.icns") + fileTags: "preprocessed_file" + } + prepare: { + var cpCmd = new JavaScriptCommand(); + cpCmd.description = "copying icon"; + cpCmd.silent = false; + cpCmd.highlight = 'filegen'; + cpCmd.sourceCode = function(){ + var src; + if(FileInfo.isAbsolutePath(project.of_root)){ + src = FileInfo.joinPaths(project.of_root,'libs/openFrameworksCompiled/project/osx/icon.icns'); + }else{ + src = FileInfo.joinPaths(project.path, project.of_root,'libs/openFrameworksCompiled/project/osx/icon.icns'); + } + + var dst = FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".app", "Contents/Resources/icon.icns"); + File.copy(src, dst); + } + return [cpCmd]; + } + } + + // Copy osx icon debug + Transformer { + condition: qbs.targetOS.contains("osx") && qbs.buildVariant.contains("debug") + Artifact { + filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".app", "Contents/Resources/icon-debug.icns") + fileTags: "preprocessed_file" + } + prepare: { + var cpCmd = new JavaScriptCommand(); + cpCmd.description = "copying icon"; + cpCmd.silent = false; + cpCmd.highlight = 'filegen'; + cpCmd.sourceCode = function(){ + var src; + if(FileInfo.isAbsolutePath(project.of_root)){ + src = FileInfo.joinPaths(project.of_root,'libs/openFrameworksCompiled/project/osx/icon-debug.icns'); + }else{ + src = FileInfo.joinPaths(project.path, project.of_root,'libs/openFrameworksCompiled/project/osx/icon-debug.icns'); + } + var dst = FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".app", "Contents/Resources/icon-debug.icns"); + File.copy(src, dst); + } + return [cpCmd]; + } + } +} diff --git a/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs b/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs new file mode 100644 index 00000000000..336bf6082be --- /dev/null +++ b/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs @@ -0,0 +1,118 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "modules/of/helpers.js" as Helpers + +Product{ + of.ofRoot: Helpers.normalize(FileInfo.joinPaths(path, "../../../..")) + name: "openFrameworks" + qbsSearchPaths: "." + + readonly property string projectDir: of.ofRoot + "/libs/openFrameworksCompiled/project" + readonly property string libDir: of.ofRoot + "/libs/openFrameworksCompiled/lib/" + of.platform + + // setting this variable to true will build OF using + // qbs instead of makefiles which helps catching errors... + // but will build on each application rebuild instead of in + // a common directory + readonly property bool qbsBuild: false + + Properties{ + condition: qbsBuild + type: "staticlibrary" + destinationDirectory: Helpers.normalize(FileInfo.joinPaths(path, "../../lib", project.platform)) + } + + Depends { + name: "of" + } + + property stringList FILES_EXCLUDE: { + + if(qbs.targetOS.indexOf("linux")>-1){ + return [ + "video/ofDirectShowPlayer.*", + "video/ofDirectShowGrabber.*", + "video/ofAVFoundationVideoPlayer.*", + "video/ofAVFoundationVideoGrabber.*", + "video/ofQuickTimePlayer.*", + "video/ofQuickTimeGrabber.*", + "video/ofQtUtils.*", + "video/ofQTKit.*", + "app/ofAppEGLWindow.*", + ]; + }else if(qbs.targetOS.indexOf("windows")>-1){ + return [ + "video/ofGstVideoPlayer.*", + "video/ofGstVideoGrabber.*", + "video/ofGstUtils.*", + "video/ofAVFoundationVideoPlayer.*", + "video/ofAVFoundationVideoGrabber.*", + "video/ofQuickTimePlayer.*", + "video/ofQuickTimeGrabber.*", + "video/ofQtUtils.*", + "video/ofQTKit.*", + "app/ofAppEGLWindow.*", + ]; + } + } + + files: { + var source = Helpers.findSourceRecursive(FileInfo.joinPaths(of.ofRoot, '/libs/openFrameworks')); + var filteredSource = source.filter(function filterExcludes(path){ + for(exclude in FILES_EXCLUDE){ + var patt = new RegExp(FILES_EXCLUDE[exclude]); + var match = patt.exec(path); + if(match!=null){ + return false; + } + } + return true; + }); + return filteredSource; + } + + readonly property string make: { + if(qbs.targetOS.contains("windows")){ + return FileInfo.joinPaths(of.msys2root,"usr/bin/make"); + }else{ + return "make"; + } + } + + Transformer { + condition: qbs.buildVariant.contains('debug') && !product.qbsBuild + inputs: files + Artifact { + filePath: Helpers.normalize(product.libDir + "/libopenFrameworksDebug.a") + fileTags: "staticlibrary" + } + prepare: { + var qbsCmd = new Command(product.make, ['Debug']); + qbsCmd.description = "building openFrameworks library"; + qbsCmd.workingDirectory = product.projectDir; + qbsCmd.silent = false; + qbsCmd.highlight = 'compiler'; + return [qbsCmd]; + } + } + + Transformer { + condition: qbs.buildVariant.contains('release') && !product.qbsBuild + inputs: files + Artifact { + filePath: Helpers.normalize(product.libDir + "/libopenFrameworks.a") + fileTags: "staticlibrary" + } + prepare: { + var qbsCmd = new Command(product.make, ['Release']); + qbsCmd.description = "building openFrameworks library"; + qbsCmd.workingDirectory = product.projectDir; + qbsCmd.silent = false; + qbsCmd.highlight = 'compiler'; + return [qbsCmd]; + } + } +} diff --git a/libs/openFrameworksCompiled/project/qtcreator/paths.config b/libs/openFrameworksCompiled/project/qtcreator/paths.config new file mode 100644 index 00000000000..e17cb0c2a8c --- /dev/null +++ b/libs/openFrameworksCompiled/project/qtcreator/paths.config @@ -0,0 +1 @@ +c:\msys64\ diff --git a/libs/openFrameworksCompiled/project/vs/openFrameworksRelease.props b/libs/openFrameworksCompiled/project/vs/openFrameworksRelease.props index fa7ea02ae1e..b5386a9a863 100644 --- a/libs/openFrameworksCompiled/project/vs/openFrameworksRelease.props +++ b/libs/openFrameworksCompiled/project/vs/openFrameworksRelease.props @@ -20,7 +20,7 @@ PocoFoundationd.lib;atlthunk.lib;LIBC.lib;LIBCMT - robocopy "$(OF_ROOT)/export/vs/$(Platform_Actual)/" "$(ProjectDir)bin/" "*.dll" /njs /njh /np /fp /bytes + robocopy "$(OF_ROOT)/export/vs/Win32/" "$(ProjectDir)bin/" "*.dll" /njs /njh /np /fp /bytes if errorlevel 1 exit 0 else exit %errorlevel% diff --git a/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj b/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj index 63aa61d849b..e3d0ea331d5 100644 --- a/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj +++ b/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj @@ -66,27 +66,27 @@ - ..\..\lib\vs\$(Platform) + ..\..\lib\vs\$(Platform)\ obj\$(Platform)\$(Configuration)\ $(ProjectName)_debug - ..\..\lib\vs\$(Platform) + ..\..\lib\vs\$(Platform)\ obj\$(Platform)\$(Configuration)\ $(ProjectName)_debug - ..\..\lib\vs\$(Platform) + ..\..\lib\vs\$(Platform)\ obj\$(Platform)\$(Configuration)\ - ..\..\lib\vs\$(Platform) + ..\..\lib\vs\$(Platform)\ obj\$(Platform)\$(Configuration)\ Disabled - ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\gl\include;..\..\..\openssl\include;..\..\..\addons;%(AdditionalIncludeDirectories) + ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\gl\include;..\..\..\openssl\include;..\..\..\json\include;..\..\..\addons;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;POCO_STATIC;CAIRO_WIN32_STATIC_BUILD;DISABLE_SOME_FLOATING_POINT;%(PreprocessorDefinitions) true EnableFastChecks @@ -98,7 +98,7 @@ Disabled - ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\gl\include;..\..\..\openssl\include;..\..\..\addons;%(AdditionalIncludeDirectories) + ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\gl\include;..\..\..\openssl\include;..\..\..\json\include;..\..\..\addons;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;POCO_STATIC;CAIRO_WIN32_STATIC_BUILD;DISABLE_SOME_FLOATING_POINT;%(PreprocessorDefinitions) true EnableFastChecks @@ -111,7 +111,7 @@ false - ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\openssl\include;..\..\..\addons;%(AdditionalIncludeDirectories) + ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\openssl\include;..\..\..\json\include;..\..\..\addons;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;POCO_STATIC;CAIRO_WIN32_STATIC_BUILD;DISABLE_SOME_FLOATING_POINT;%(PreprocessorDefinitions) MultiThreadedDLL Level3 @@ -121,7 +121,7 @@ false - ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\openssl\include;..\..\..\addons;%(AdditionalIncludeDirectories) + ..\..\..\openFrameworks;..\..\..\openFrameworks\graphics;..\..\..\openFrameworks\app;..\..\..\openFrameworks\sound;..\..\..\openFrameworks\utils;..\..\..\openFrameworks\communication;..\..\..\openFrameworks\video;..\..\..\openFrameworks\types;..\..\..\openFrameworks\math;..\..\..\openFrameworks\3d;..\..\..\openFrameworks\gl;..\..\..\openFrameworks\events;..\..\..\glut\include;..\..\..\rtAudio\include;..\..\..\quicktime\include;..\..\..\freetype\include;..\..\..\freetype\include\freetype2;..\..\..\freeImage\include;..\..\..\fmodex\include;..\..\..\videoInput\include;..\..\..\glew\include\;..\..\..\glu\include;..\..\..\tess2\include;..\..\..\cairo\include\cairo;..\..\..\poco\include;..\..\..\glfw\include;..\..\..\boost\include;..\..\..\utf8cpp\include;..\..\..\openssl\include;..\..\..\json\include;..\..\..\addons;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;POCO_STATIC;CAIRO_WIN32_STATIC_BUILD;DISABLE_SOME_FLOATING_POINT;%(PreprocessorDefinitions) MultiThreadedDLL Level1 @@ -280,4 +280,4 @@ - \ No newline at end of file + diff --git a/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj.filters b/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj.filters index 8ed9fc8f97c..575c9cfb948 100644 --- a/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj.filters +++ b/libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj.filters @@ -486,4 +486,4 @@ libs\openFrameworks\app - \ No newline at end of file + diff --git a/libs/openFrameworksCompiled/project/win_cb/openFrameworksLib.cbp b/libs/openFrameworksCompiled/project/win_cb/openFrameworksLib.cbp deleted file mode 100644 index 7e1385b8a80..00000000000 --- a/libs/openFrameworksCompiled/project/win_cb/openFrameworksLib.cbp +++ /dev/null @@ -1,514 +0,0 @@ - - - - - - diff --git a/libs/openssl/lib/android/armeabi-v7a/libcrypto.a b/libs/openssl/lib/android/armeabi-v7a/libcrypto.a index b2ef720e5e7..e120525b783 100644 Binary files a/libs/openssl/lib/android/armeabi-v7a/libcrypto.a and b/libs/openssl/lib/android/armeabi-v7a/libcrypto.a differ diff --git a/libs/openssl/lib/android/armeabi-v7a/libssl.a b/libs/openssl/lib/android/armeabi-v7a/libssl.a index 843537b4aca..9af7cf04239 100644 Binary files a/libs/openssl/lib/android/armeabi-v7a/libssl.a and b/libs/openssl/lib/android/armeabi-v7a/libssl.a differ diff --git a/libs/openssl/lib/android/x86/libcrypto.a b/libs/openssl/lib/android/x86/libcrypto.a index 420d02c178a..535629e7a0f 100644 Binary files a/libs/openssl/lib/android/x86/libcrypto.a and b/libs/openssl/lib/android/x86/libcrypto.a differ diff --git a/libs/openssl/lib/android/x86/libssl.a b/libs/openssl/lib/android/x86/libssl.a index 0e9e89c8633..dc090d2dee4 100644 Binary files a/libs/openssl/lib/android/x86/libssl.a and b/libs/openssl/lib/android/x86/libssl.a differ diff --git a/libs/openssl/lib/win_cb/libcrypto.a b/libs/openssl/lib/win_cb/libcrypto.a deleted file mode 100644 index 33b044ec329..00000000000 Binary files a/libs/openssl/lib/win_cb/libcrypto.a and /dev/null differ diff --git a/libs/openssl/lib/win_cb/libssl.a b/libs/openssl/lib/win_cb/libssl.a deleted file mode 100644 index 5b0b5cc97a0..00000000000 Binary files a/libs/openssl/lib/win_cb/libssl.a and /dev/null differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoCrypto.a b/libs/poco/lib/android/armeabi-v7a/libPocoCrypto.a index 513f0cbd28d..40458ff8b85 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoCrypto.a and b/libs/poco/lib/android/armeabi-v7a/libPocoCrypto.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoData.a b/libs/poco/lib/android/armeabi-v7a/libPocoData.a index 6544c675235..3ca2adc346f 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoData.a and b/libs/poco/lib/android/armeabi-v7a/libPocoData.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoDataSQLite.a b/libs/poco/lib/android/armeabi-v7a/libPocoDataSQLite.a index cc35db91784..a84ecf0727e 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoDataSQLite.a and b/libs/poco/lib/android/armeabi-v7a/libPocoDataSQLite.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoFoundation.a b/libs/poco/lib/android/armeabi-v7a/libPocoFoundation.a index 680eeb4665d..5ca4ffcbe38 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoFoundation.a and b/libs/poco/lib/android/armeabi-v7a/libPocoFoundation.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoJSON.a b/libs/poco/lib/android/armeabi-v7a/libPocoJSON.a index 4431e4ea1db..10c9f99b62e 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoJSON.a and b/libs/poco/lib/android/armeabi-v7a/libPocoJSON.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoMongoDB.a b/libs/poco/lib/android/armeabi-v7a/libPocoMongoDB.a index 7b645986aba..41cfde2523b 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoMongoDB.a and b/libs/poco/lib/android/armeabi-v7a/libPocoMongoDB.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoNet.a b/libs/poco/lib/android/armeabi-v7a/libPocoNet.a index da4dd9131be..f9538dc24ad 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoNet.a and b/libs/poco/lib/android/armeabi-v7a/libPocoNet.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoNetSSL.a b/libs/poco/lib/android/armeabi-v7a/libPocoNetSSL.a index ea67781be14..bc630b37a03 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoNetSSL.a and b/libs/poco/lib/android/armeabi-v7a/libPocoNetSSL.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoUtil.a b/libs/poco/lib/android/armeabi-v7a/libPocoUtil.a index 3049e688425..8f59e32f960 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoUtil.a and b/libs/poco/lib/android/armeabi-v7a/libPocoUtil.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoXML.a b/libs/poco/lib/android/armeabi-v7a/libPocoXML.a index f11250f22f5..0fcfa4b0b74 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoXML.a and b/libs/poco/lib/android/armeabi-v7a/libPocoXML.a differ diff --git a/libs/poco/lib/android/armeabi-v7a/libPocoZip.a b/libs/poco/lib/android/armeabi-v7a/libPocoZip.a index 4d5c8397413..22cf130591c 100644 Binary files a/libs/poco/lib/android/armeabi-v7a/libPocoZip.a and b/libs/poco/lib/android/armeabi-v7a/libPocoZip.a differ diff --git a/libs/poco/lib/android/x86/libPocoCrypto.a b/libs/poco/lib/android/x86/libPocoCrypto.a index 4913eae6249..e630f9a3f9e 100644 Binary files a/libs/poco/lib/android/x86/libPocoCrypto.a and b/libs/poco/lib/android/x86/libPocoCrypto.a differ diff --git a/libs/poco/lib/android/x86/libPocoData.a b/libs/poco/lib/android/x86/libPocoData.a index b54f94c6acb..d7dd68dca01 100644 Binary files a/libs/poco/lib/android/x86/libPocoData.a and b/libs/poco/lib/android/x86/libPocoData.a differ diff --git a/libs/poco/lib/android/x86/libPocoDataSQLite.a b/libs/poco/lib/android/x86/libPocoDataSQLite.a index 545737ee678..5ebdcad5424 100644 Binary files a/libs/poco/lib/android/x86/libPocoDataSQLite.a and b/libs/poco/lib/android/x86/libPocoDataSQLite.a differ diff --git a/libs/poco/lib/android/x86/libPocoFoundation.a b/libs/poco/lib/android/x86/libPocoFoundation.a index 5b1e9011d99..e98f7560af2 100644 Binary files a/libs/poco/lib/android/x86/libPocoFoundation.a and b/libs/poco/lib/android/x86/libPocoFoundation.a differ diff --git a/libs/poco/lib/android/x86/libPocoJSON.a b/libs/poco/lib/android/x86/libPocoJSON.a index 268482c918f..4e12d28747e 100644 Binary files a/libs/poco/lib/android/x86/libPocoJSON.a and b/libs/poco/lib/android/x86/libPocoJSON.a differ diff --git a/libs/poco/lib/android/x86/libPocoMongoDB.a b/libs/poco/lib/android/x86/libPocoMongoDB.a index 803ed3973c4..58789feb3a4 100644 Binary files a/libs/poco/lib/android/x86/libPocoMongoDB.a and b/libs/poco/lib/android/x86/libPocoMongoDB.a differ diff --git a/libs/poco/lib/android/x86/libPocoNet.a b/libs/poco/lib/android/x86/libPocoNet.a index 19554fd973c..71f75ed589c 100644 Binary files a/libs/poco/lib/android/x86/libPocoNet.a and b/libs/poco/lib/android/x86/libPocoNet.a differ diff --git a/libs/poco/lib/android/x86/libPocoNetSSL.a b/libs/poco/lib/android/x86/libPocoNetSSL.a index d3cfa8d7993..119f0c5d96a 100644 Binary files a/libs/poco/lib/android/x86/libPocoNetSSL.a and b/libs/poco/lib/android/x86/libPocoNetSSL.a differ diff --git a/libs/poco/lib/android/x86/libPocoUtil.a b/libs/poco/lib/android/x86/libPocoUtil.a index 307a0e8401e..1fc81547bb4 100644 Binary files a/libs/poco/lib/android/x86/libPocoUtil.a and b/libs/poco/lib/android/x86/libPocoUtil.a differ diff --git a/libs/poco/lib/android/x86/libPocoXML.a b/libs/poco/lib/android/x86/libPocoXML.a index 230dc723971..f7463abe170 100644 Binary files a/libs/poco/lib/android/x86/libPocoXML.a and b/libs/poco/lib/android/x86/libPocoXML.a differ diff --git a/libs/poco/lib/android/x86/libPocoZip.a b/libs/poco/lib/android/x86/libPocoZip.a index ab9ba546bd4..bc1608c8b7d 100644 Binary files a/libs/poco/lib/android/x86/libPocoZip.a and b/libs/poco/lib/android/x86/libPocoZip.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoCrypto.a b/libs/poco/lib/linuxarmv7l/libPocoCrypto.a index 1bd2f8ea945..3b3ffa3fb06 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoCrypto.a and b/libs/poco/lib/linuxarmv7l/libPocoCrypto.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoData.a b/libs/poco/lib/linuxarmv7l/libPocoData.a new file mode 100644 index 00000000000..5ec5fab1da1 Binary files /dev/null and b/libs/poco/lib/linuxarmv7l/libPocoData.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoDataSQLite.a b/libs/poco/lib/linuxarmv7l/libPocoDataSQLite.a new file mode 100644 index 00000000000..2e3c20cc03d Binary files /dev/null and b/libs/poco/lib/linuxarmv7l/libPocoDataSQLite.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoFoundation.a b/libs/poco/lib/linuxarmv7l/libPocoFoundation.a index 54d0472b8d9..245deeb6eea 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoFoundation.a and b/libs/poco/lib/linuxarmv7l/libPocoFoundation.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoJSON.a b/libs/poco/lib/linuxarmv7l/libPocoJSON.a new file mode 100644 index 00000000000..24f18a78595 Binary files /dev/null and b/libs/poco/lib/linuxarmv7l/libPocoJSON.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoMongoDB.a b/libs/poco/lib/linuxarmv7l/libPocoMongoDB.a new file mode 100644 index 00000000000..11b77d7d7f6 Binary files /dev/null and b/libs/poco/lib/linuxarmv7l/libPocoMongoDB.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoNet.a b/libs/poco/lib/linuxarmv7l/libPocoNet.a index db210209d86..0645209b3e3 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoNet.a and b/libs/poco/lib/linuxarmv7l/libPocoNet.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoNetSSL.a b/libs/poco/lib/linuxarmv7l/libPocoNetSSL.a index 5d487ae63d6..939b53b5607 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoNetSSL.a and b/libs/poco/lib/linuxarmv7l/libPocoNetSSL.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoUtil.a b/libs/poco/lib/linuxarmv7l/libPocoUtil.a index ded70418080..1f62ccb1bfb 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoUtil.a and b/libs/poco/lib/linuxarmv7l/libPocoUtil.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoXML.a b/libs/poco/lib/linuxarmv7l/libPocoXML.a index f45a7318ec6..561b1a5c5ae 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoXML.a and b/libs/poco/lib/linuxarmv7l/libPocoXML.a differ diff --git a/libs/poco/lib/linuxarmv7l/libPocoZip.a b/libs/poco/lib/linuxarmv7l/libPocoZip.a index 13a50116ff8..2b3775c572b 100644 Binary files a/libs/poco/lib/linuxarmv7l/libPocoZip.a and b/libs/poco/lib/linuxarmv7l/libPocoZip.a differ diff --git a/libs/poco/lib/msys2/libPocoCrypto.a b/libs/poco/lib/msys2/libPocoCrypto.a new file mode 100644 index 00000000000..2c18edf8a44 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoCrypto.a differ diff --git a/libs/poco/lib/msys2/libPocoData.a b/libs/poco/lib/msys2/libPocoData.a new file mode 100644 index 00000000000..da09e731222 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoData.a differ diff --git a/libs/poco/lib/msys2/libPocoDataSQLite.a b/libs/poco/lib/msys2/libPocoDataSQLite.a new file mode 100644 index 00000000000..3f86b29821f Binary files /dev/null and b/libs/poco/lib/msys2/libPocoDataSQLite.a differ diff --git a/libs/poco/lib/msys2/libPocoFoundation.a b/libs/poco/lib/msys2/libPocoFoundation.a new file mode 100644 index 00000000000..01a6f8161bf Binary files /dev/null and b/libs/poco/lib/msys2/libPocoFoundation.a differ diff --git a/libs/poco/lib/msys2/libPocoJSON.a b/libs/poco/lib/msys2/libPocoJSON.a new file mode 100644 index 00000000000..009a4014aa3 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoJSON.a differ diff --git a/libs/poco/lib/msys2/libPocoMongoDB.a b/libs/poco/lib/msys2/libPocoMongoDB.a new file mode 100644 index 00000000000..b87156223ca Binary files /dev/null and b/libs/poco/lib/msys2/libPocoMongoDB.a differ diff --git a/libs/poco/lib/msys2/libPocoNet.a b/libs/poco/lib/msys2/libPocoNet.a new file mode 100644 index 00000000000..8f51dbb81f9 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoNet.a differ diff --git a/libs/poco/lib/msys2/libPocoNetSSL.a b/libs/poco/lib/msys2/libPocoNetSSL.a new file mode 100644 index 00000000000..2738c99c237 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoNetSSL.a differ diff --git a/libs/poco/lib/msys2/libPocoUtil.a b/libs/poco/lib/msys2/libPocoUtil.a new file mode 100644 index 00000000000..0e07175d639 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoUtil.a differ diff --git a/libs/poco/lib/msys2/libPocoXML.a b/libs/poco/lib/msys2/libPocoXML.a new file mode 100644 index 00000000000..ae1549e9472 Binary files /dev/null and b/libs/poco/lib/msys2/libPocoXML.a differ diff --git a/libs/poco/lib/msys2/libPocoZip.a b/libs/poco/lib/msys2/libPocoZip.a new file mode 100644 index 00000000000..e98dcca371a Binary files /dev/null and b/libs/poco/lib/msys2/libPocoZip.a differ diff --git a/libs/poco/lib/win_cb/libPocoCrypto.a b/libs/poco/lib/win_cb/libPocoCrypto.a deleted file mode 100644 index 2a9571a3f23..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoCrypto.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoFoundation.a b/libs/poco/lib/win_cb/libPocoFoundation.a deleted file mode 100644 index eea722e2dd2..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoFoundation.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoNet.a b/libs/poco/lib/win_cb/libPocoNet.a deleted file mode 100644 index 59c6efae9c5..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoNet.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoNetSSL.a b/libs/poco/lib/win_cb/libPocoNetSSL.a deleted file mode 100644 index 236b9d950ab..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoNetSSL.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoUtil.a b/libs/poco/lib/win_cb/libPocoUtil.a deleted file mode 100644 index fcf47ca7493..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoUtil.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoXML.a b/libs/poco/lib/win_cb/libPocoXML.a deleted file mode 100644 index ffb02f9c602..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoXML.a and /dev/null differ diff --git a/libs/poco/lib/win_cb/libPocoZip.a b/libs/poco/lib/win_cb/libPocoZip.a deleted file mode 100644 index 93d4bf36c16..00000000000 Binary files a/libs/poco/lib/win_cb/libPocoZip.a and /dev/null differ diff --git a/libs/portaudio/include/pa_asio.h b/libs/portaudio/include/pa_asio.h deleted file mode 100644 index 7ed3ead226c..00000000000 --- a/libs/portaudio/include/pa_asio.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef PA_ASIO_H -#define PA_ASIO_H -/* - * $Id: pa_asio.h 1592 2011-02-04 10:41:58Z rossb $ - * PortAudio Portable Real-Time Audio Library - * ASIO specific extensions - * - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - - -/** @file - @ingroup public_header - @brief ASIO-specific PortAudio API extension header file. -*/ - -#include "portaudio.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -/** Retrieve legal latency settings for the specificed device, in samples. - - @param device The global index of the device about which the query is being made. - @param minLatency A pointer to the location which will recieve the minimum latency value. - @param maxLatency A pointer to the location which will recieve the maximum latency value. - @param preferredLatency A pointer to the location which will recieve the preferred latency value. - @param granularity A pointer to the location which will recieve the granularity. This value - determines which values between minLatency and maxLatency are available. ie the step size, - if granularity is -1 then available latency settings are powers of two. - - @see ASIOGetBufferSize in the ASIO SDK. - - @todo This function should be renamed to PaAsio_GetAvailableBufferSizes. - No reason to use a wildly different name from the ASIO version. -*/ -PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, - long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ); - - -/** Display the ASIO control panel for the specified device. - - @param device The global index of the device whose control panel is to be displayed. - @param systemSpecific On Windows, the calling application's main window handle, - on Macintosh this value should be zero. -*/ -PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ); - - - - -/** Retrieve a pointer to a string containing the name of the specified - input channel. The string is valid until Pa_Terminate is called. - - The string will be no longer than 32 characters including the null terminator. -*/ -PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, - const char** channelName ); - - -/** Retrieve a pointer to a string containing the name of the specified - input channel. The string is valid until Pa_Terminate is called. - - The string will be no longer than 32 characters including the null terminator. -*/ -PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, - const char** channelName ); - - -/** Set the sample rate of an open paASIO stream. - - @param stream The stream to operate on. - @param sampleRate The new sample rate. - - Note that this function may fail if the stream is alredy running and the - ASIO driver does not support switching the sample rate of a running stream. - - Returns paIncompatibleStreamHostApi if stream is not a paASIO stream. -*/ -PaError PaAsio_SetStreamSampleRate( PaStream* stream, double sampleRate ); - - -#define paAsioUseChannelSelectors (0x01) - -typedef struct PaAsioStreamInfo{ - unsigned long size; /**< sizeof(PaAsioStreamInfo) */ - PaHostApiTypeId hostApiType; /**< paASIO */ - unsigned long version; /**< 1 */ - - unsigned long flags; - - /* Support for opening only specific channels of an ASIO device. - If the paAsioUseChannelSelectors flag is set, channelSelectors is a - pointer to an array of integers specifying the device channels to use. - When used, the length of the channelSelectors array must match the - corresponding channelCount parameter to Pa_OpenStream() otherwise a - crash may result. - The values in the selectors array must specify channels within the - range of supported channels for the device or paInvalidChannelCount will - result. - */ - int *channelSelectors; -}PaAsioStreamInfo; - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_ASIO_H */ diff --git a/libs/portaudio/include/pa_jack.h b/libs/portaudio/include/pa_jack.h deleted file mode 100644 index 99ef833dd0b..00000000000 --- a/libs/portaudio/include/pa_jack.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef PA_JACK_H -#define PA_JACK_H - -/* - * $Id: - * PortAudio Portable Real-Time Audio Library - * JACK-specific extensions - * - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - * @ingroup public_header - * @brief JACK-specific PortAudio API extension header file. - */ - -#include "portaudio.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Set the JACK client name. - * - * During Pa_Initialize, When PA JACK connects as a client of the JACK server, it requests a certain - * name, which is for instance prepended to port names. By default this name is "PortAudio". The - * JACK server may append a suffix to the client name, in order to avoid clashes among clients that - * try to connect with the same name (e.g., different PA JACK clients). - * - * This function must be called before Pa_Initialize, otherwise it won't have any effect. Note that - * the string is not copied, but instead referenced directly, so it must not be freed for as long as - * PA might need it. - * @sa PaJack_GetClientName - */ -PaError PaJack_SetClientName( const char* name ); - -/** Get the JACK client name used by PA JACK. - * - * The caller is responsible for freeing the returned pointer. - */ -PaError PaJack_GetClientName(const char** clientName); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/portaudio/include/pa_linux_alsa.h b/libs/portaudio/include/pa_linux_alsa.h deleted file mode 100644 index 21627bdf11c..00000000000 --- a/libs/portaudio/include/pa_linux_alsa.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef PA_LINUX_ALSA_H -#define PA_LINUX_ALSA_H - -/* - * $Id: pa_linux_alsa.h 1597 2011-02-11 00:15:51Z dmitrykos $ - * PortAudio Portable Real-Time Audio Library - * ALSA-specific extensions - * - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - * @ingroup public_header - * @brief ALSA-specific PortAudio API extension header file. - */ - -#include "portaudio.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PaAlsaStreamInfo -{ - unsigned long size; - PaHostApiTypeId hostApiType; - unsigned long version; - - const char *deviceString; -} -PaAlsaStreamInfo; - -/** Initialize host API specific structure, call this before setting relevant attributes. */ -void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ); - -/** Instruct whether to enable real-time priority when starting the audio thread. - * - * If this is turned on by the stream is started, the audio callback thread will be created - * with the FIFO scheduling policy, which is suitable for realtime operation. - **/ -void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ); - -#if 0 -void PaAlsa_EnableWatchdog( PaStream *s, int enable ); -#endif - -/** Get the ALSA-lib card index of this stream's input device. */ -PaError PaAlsa_GetStreamInputCard( PaStream *s, int *card ); - -/** Get the ALSA-lib card index of this stream's output device. */ -PaError PaAlsa_GetStreamOutputCard( PaStream *s, int *card ); - -/** Set the number of periods (buffer fragments) to configure devices with. - * - * By default the number of periods is 4, this is the lowest number of periods that works well on - * the author's soundcard. - * @param numPeriods The number of periods. - */ -PaError PaAlsa_SetNumPeriods( int numPeriods ); - -/** Set the maximum number of times to retry opening busy device (sleeping for a - * short interval inbetween). - */ -PaError PaAlsa_SetRetriesBusy( int retries ); - -/** Set the path and name of ALSA library file if PortAudio is configured to load it dynamically (see - * PA_ALSA_DYNAMIC). This setting will overwrite the default name set by PA_ALSA_PATHNAME define. - * @param pathName Full path with filename. Only filename can be used, but dlopen() will lookup default - * searchable directories (/usr/lib;/usr/local/lib) then. - */ -void PaAlsa_SetLibraryPathName( const char *pathName ); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/portaudio/include/pa_mac_core.h b/libs/portaudio/include/pa_mac_core.h deleted file mode 100644 index 43321b601e4..00000000000 --- a/libs/portaudio/include/pa_mac_core.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef PA_MAC_CORE_H -#define PA_MAC_CORE_H -/* - * PortAudio Portable Real-Time Audio Library - * Macintosh Core Audio specific extensions - * portaudio.h should be included before this file. - * - * Copyright (c) 2005-2006 Bjorn Roche - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - * @ingroup public_header - * @brief CoreAudio-specific PortAudio API extension header file. - */ - -#include "portaudio.h" - -#include -//#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * A pointer to a paMacCoreStreamInfo may be passed as - * the hostApiSpecificStreamInfo in the PaStreamParameters struct - * when opening a stream or querying the format. Use NULL, for the - * defaults. Note that for duplex streams, flags for input and output - * should be the same or behaviour is undefined. - */ -typedef struct -{ - unsigned long size; /**size of whole structure including this header */ - PaHostApiTypeId hostApiType; /**host API for which this data is intended */ - unsigned long version; /**structure version */ - unsigned long flags; /* flags to modify behaviour */ - SInt32 const * channelMap; /* Channel map for HAL channel mapping , if not needed, use NULL;*/ - unsigned long channelMapSize; /* Channel map size for HAL channel mapping , if not needed, use 0;*/ -} PaMacCoreStreamInfo; - -/* - * Functions - */ - - -/* Use this function to initialize a paMacCoreStreamInfo struct - * using the requested flags. Note that channel mapping is turned - * off after a call to this function. - * @param data The datastructure to initialize - * @param flags The flags to initialize the datastructure with. -*/ -void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); - -/* call this after pa_SetupMacCoreStreamInfo to use channel mapping as described in notes.txt. - * @param data The stream info structure to assign a channel mapping to - * @param channelMap The channel map array, as described in notes.txt. This array pointer will be used directly (ie the underlying data will not be copied), so the caller should not free the array until after the stream has been opened. - * @param channelMapSize The size of the channel map array. - */ -void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); - -/* - * Retrieve the AudioDeviceID of the input device assigned to an open stream - * - * @param s The stream to query. - * - * @return A valid AudioDeviceID, or NULL if an error occurred. - */ -AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ); - -/* - * Retrieve the AudioDeviceID of the output device assigned to an open stream - * - * @param s The stream to query. - * - * @return A valid AudioDeviceID, or NULL if an error occurred. - */ -AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); - -/* - * Returns a statically allocated string with the device's name - * for the given channel. NULL will be returned on failure. - * - * This function's implemenation is not complete! - * - * @param device The PortAudio device index. - * @param channel The channel number who's name is requested. - * @return a statically allocated string with the name of the device. - * Because this string is statically allocated, it must be - * coppied if it is to be saved and used by the user after - * another call to this function. - * - */ -const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); - -/* - * Flags - */ - -/* - * The following flags alter the behaviour of PA on the mac platform. - * they can be ORed together. These should work both for opening and - * checking a device. - */ - -/* Allows PortAudio to change things like the device's frame size, - * which allows for much lower latency, but might disrupt the device - * if other programs are using it, even when you are just Querying - * the device. */ -#define paMacCoreChangeDeviceParameters (0x01) - -/* In combination with the above flag, - * causes the stream opening to fail, unless the exact sample rates - * are supported by the device. */ -#define paMacCoreFailIfConversionRequired (0x02) - -/* These flags set the SR conversion quality, if required. The wierd ordering - * allows Maximum Quality to be the default.*/ -#define paMacCoreConversionQualityMin (0x0100) -#define paMacCoreConversionQualityMedium (0x0200) -#define paMacCoreConversionQualityLow (0x0300) -#define paMacCoreConversionQualityHigh (0x0400) -#define paMacCoreConversionQualityMax (0x0000) - -/* - * Here are some "preset" combinations of flags (above) to get to some - * common configurations. THIS IS OVERKILL, but if more flags are added - * it won't be. - */ - -/*This is the default setting: do as much sample rate conversion as possible - * and as little mucking with the device as possible. */ -#define paMacCorePlayNice (0x00) -/*This setting is tuned for pro audio apps. It allows SR conversion on input - and output, but it tries to set the appropriate SR on the device.*/ -#define paMacCorePro (0x01) -/*This is a setting to minimize CPU usage and still play nice.*/ -#define paMacCoreMinimizeCPUButPlayNice (0x0100) -/*This is a setting to minimize CPU usage, even if that means interrupting the device. */ -#define paMacCoreMinimizeCPU (0x0101) - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_MAC_CORE_H */ diff --git a/libs/portaudio/include/pa_win_ds.h b/libs/portaudio/include/pa_win_ds.h deleted file mode 100644 index 2e1fd5958f7..00000000000 --- a/libs/portaudio/include/pa_win_ds.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef PA_WIN_DS_H -#define PA_WIN_DS_H -/* - * $Id: $ - * PortAudio Portable Real-Time Audio Library - * DirectSound specific extensions - * - * Copyright (c) 1999-2007 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup public_header - @brief DirectSound-specific PortAudio API extension header file. -*/ - -#include "portaudio.h" -#include "pa_win_waveformat.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -#define paWinDirectSoundUseLowLevelLatencyParameters (0x01) -#define paWinDirectSoundUseChannelMask (0x04) - - -typedef struct PaWinDirectSoundStreamInfo{ - unsigned long size; /**< sizeof(PaWinDirectSoundStreamInfo) */ - PaHostApiTypeId hostApiType; /**< paDirectSound */ - unsigned long version; /**< 1 */ - - unsigned long flags; - - /* low-level latency setting support - TODO ** NOT IMPLEMENTED ** - These settings control the number and size of host buffers in order - to set latency. They will be used instead of the generic parameters - to Pa_OpenStream() if flags contains the paWinDirectSoundUseLowLevelLatencyParameters - flag. - - If PaWinDirectSoundStreamInfo structures with paWinDirectSoundUseLowLevelLatencyParameters - are supplied for both input and output in a full duplex stream, then the - input and output framesPerBuffer must be the same, or the larger of the - two must be a multiple of the smaller, otherwise a - paIncompatibleHostApiSpecificStreamInfo error will be returned from - Pa_OpenStream(). - - unsigned long framesPerBuffer; - */ - - /* - support for WAVEFORMATEXTENSIBLE channel masks. If flags contains - paWinDirectSoundUseChannelMask this allows you to specify which speakers - to address in a multichannel stream. Constants for channelMask - are specified in pa_win_waveformat.h - - */ - PaWinWaveFormatChannelMask channelMask; - -}PaWinDirectSoundStreamInfo; - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_WIN_DS_H */ diff --git a/libs/portaudio/include/pa_win_wasapi.h b/libs/portaudio/include/pa_win_wasapi.h deleted file mode 100644 index a60aa047a63..00000000000 --- a/libs/portaudio/include/pa_win_wasapi.h +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef PA_WIN_WASAPI_H -#define PA_WIN_WASAPI_H -/* - * $Id: $ - * PortAudio Portable Real-Time Audio Library - * DirectSound specific extensions - * - * Copyright (c) 1999-2007 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup public_header - @brief WASAPI-specific PortAudio API extension header file. -*/ - -#include "portaudio.h" -#include "pa_win_waveformat.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -/* Setup flags */ -typedef enum PaWasapiFlags -{ - /* puts WASAPI into exclusive mode */ - paWinWasapiExclusive = (1 << 0), - - /* allows to skip internal PA processing completely */ - paWinWasapiRedirectHostProcessor = (1 << 1), - - /* assigns custom channel mask */ - paWinWasapiUseChannelMask = (1 << 2), - - /* selects non-Event driven method of data read/write - Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling - method can only provide 15-20ms latency. */ - paWinWasapiPolling = (1 << 3), - - /* forces custom thread priority setting. must be used if PaWasapiStreamInfo::threadPriority - is set to custom value. */ - paWinWasapiThreadPriority = (1 << 4) -} -PaWasapiFlags; -#define paWinWasapiExclusive (paWinWasapiExclusive) -#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor) -#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask) -#define paWinWasapiPolling (paWinWasapiPolling) -#define paWinWasapiThreadPriority (paWinWasapiThreadPriority) - - -/* Host processor. Allows to skip internal PA processing completely. - You must set paWinWasapiRedirectHostProcessor flag to PaWasapiStreamInfo::flags member - in order to have host processor redirected to your callback. - Use with caution! inputFrames and outputFrames depend solely on final device setup. - To query maximal values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer. -*/ -typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames, - void *outputBuffer, long outputFrames, - void *userData); - -/* Device role */ -typedef enum PaWasapiDeviceRole -{ - eRoleRemoteNetworkDevice = 0, - eRoleSpeakers, - eRoleLineLevel, - eRoleHeadphones, - eRoleMicrophone, - eRoleHeadset, - eRoleHandset, - eRoleUnknownDigitalPassthrough, - eRoleSPDIF, - eRoleHDMI, - eRoleUnknownFormFactor -} -PaWasapiDeviceRole; - - -/* Jack connection type */ -typedef enum PaWasapiJackConnectionType -{ - eJackConnTypeUnknown, - eJackConnType3Point5mm, - eJackConnTypeQuarter, - eJackConnTypeAtapiInternal, - eJackConnTypeRCA, - eJackConnTypeOptical, - eJackConnTypeOtherDigital, - eJackConnTypeOtherAnalog, - eJackConnTypeMultichannelAnalogDIN, - eJackConnTypeXlrProfessional, - eJackConnTypeRJ11Modem, - eJackConnTypeCombination -} -PaWasapiJackConnectionType; - - -/* Jack geometric location */ -typedef enum PaWasapiJackGeoLocation -{ - eJackGeoLocUnk = 0, - eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */ - eJackGeoLocFront, - eJackGeoLocLeft, - eJackGeoLocRight, - eJackGeoLocTop, - eJackGeoLocBottom, - eJackGeoLocRearPanel, - eJackGeoLocRiser, - eJackGeoLocInsideMobileLid, - eJackGeoLocDrivebay, - eJackGeoLocHDMI, - eJackGeoLocOutsideMobileLid, - eJackGeoLocATAPI, - eJackGeoLocReserved5, - eJackGeoLocReserved6, -} -PaWasapiJackGeoLocation; - - -/* Jack general location */ -typedef enum PaWasapiJackGenLocation -{ - eJackGenLocPrimaryBox = 0, - eJackGenLocInternal, - eJackGenLocSeparate, - eJackGenLocOther -} -PaWasapiJackGenLocation; - - -/* Jack's type of port */ -typedef enum PaWasapiJackPortConnection -{ - eJackPortConnJack = 0, - eJackPortConnIntegratedDevice, - eJackPortConnBothIntegratedAndJack, - eJackPortConnUnknown -} -PaWasapiJackPortConnection; - - -/* Thread priority */ -typedef enum PaWasapiThreadPriority -{ - eThreadPriorityNone = 0, - eThreadPriorityAudio, //!< Default for Shared mode. - eThreadPriorityCapture, - eThreadPriorityDistribution, - eThreadPriorityGames, - eThreadPriorityPlayback, - eThreadPriorityProAudio, //!< Default for Exclusive mode. - eThreadPriorityWindowManager -} -PaWasapiThreadPriority; - - -/* Stream descriptor. */ -typedef struct PaWasapiJackDescription -{ - unsigned long channelMapping; - unsigned long color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */ - PaWasapiJackConnectionType connectionType; - PaWasapiJackGeoLocation geoLocation; - PaWasapiJackGenLocation genLocation; - PaWasapiJackPortConnection portConnection; - unsigned int isConnected; -} -PaWasapiJackDescription; - - -/* Stream descriptor. */ -typedef struct PaWasapiStreamInfo -{ - unsigned long size; /**< sizeof(PaWasapiStreamInfo) */ - PaHostApiTypeId hostApiType; /**< paWASAPI */ - unsigned long version; /**< 1 */ - - unsigned long flags; /**< collection of PaWasapiFlags */ - - /* Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains - paWinWasapiUseChannelMask this allows you to specify which speakers - to address in a multichannel stream. Constants for channelMask - are specified in pa_win_waveformat.h. Will be used only if - paWinWasapiUseChannelMask flag is specified. - */ - PaWinWaveFormatChannelMask channelMask; - - /* Delivers raw data to callback obtained from GetBuffer() methods skipping - internal PortAudio processing inventory completely. userData parameter will - be the same that was passed to Pa_OpenStream method. Will be used only if - paWinWasapiRedirectHostProcessor flag is specified. - */ - PaWasapiHostProcessorCallback hostProcessorOutput; - PaWasapiHostProcessorCallback hostProcessorInput; - - /* Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag - is specified. - - Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode) - you shall specify same value for threadPriority or othervise one of the values will be used - to setup thread priority. - */ - PaWasapiThreadPriority threadPriority; -} -PaWasapiStreamInfo; - - -/** Returns default sound format for device. Format is represented by PaWinWaveFormat or - WAVEFORMATEXTENSIBLE structure. - - @param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. - @param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes. - @param nDevice Device index. - - @return Non-negative value indicating the number of bytes copied into format decriptor - or, a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. -*/ -int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice ); - - -/** Returns device role (PaWasapiDeviceRole enum). - - @param nDevice device index. - - @return Non-negative value indicating device role or, a PaErrorCode (which are always negative) - if PortAudio is not initialized or an error is encountered. -*/ -int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice ); - - -/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread - which makes calls to Pa_WriteStream/Pa_ReadStream. - - @param hTask Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority - method to revert thread priority to initial state. - - @param nPriorityClass Id of thread priority of PaWasapiThreadPriority type. Specifying - eThreadPriorityNone does nothing. - - @return Error code indicating success or failure. - @see PaWasapi_RevertThreadPriority -*/ -PaError PaWasapi_ThreadPriorityBoost( void **hTask, PaWasapiThreadPriority nPriorityClass ); - - -/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread - which makes calls to Pa_WriteStream/Pa_ReadStream. - - @param hTask Task handle obtained by PaWasapi_BoostThreadPriority method. - @return Error code indicating success or failure. - @see PaWasapi_BoostThreadPriority -*/ -PaError PaWasapi_ThreadPriorityRevert( void *hTask ); - - -/** Get number of frames per host buffer. This is maximal value of frames of WASAPI buffer which - can be locked for operations. Use this method as helper to findout maximal values of - inputFrames/outputFrames of PaWasapiHostProcessorCallback. - - @param pStream Pointer to PaStream to query. - @param nInput Pointer to variable to receive number of input frames. Can be NULL. - @param nOutput Pointer to variable to receive number of output frames. Can be NULL. - @return Error code indicating success or failure. - @see PaWasapiHostProcessorCallback -*/ -PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput ); - - -/** Get number of jacks associated with a WASAPI device. Use this method to determine if - there are any jacks associated with the provided WASAPI device. Not all audio devices - will support this capability. This is valid for both input and output devices. - @param nDevice device index. - @param jcount Number of jacks is returned in this variable - @return Error code indicating success or failure - @see PaWasapi_GetJackDescription - */ -PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount); - - -/** Get the jack description associated with a WASAPI device and jack number - Before this function is called, use PaWasapi_GetJackCount to determine the - number of jacks associated with device. If jcount is greater than zero, then - each jack from 0 to jcount can be queried with this function to get the jack - description. - @param nDevice device index. - @param jindex Which jack to return information - @param KSJACK_DESCRIPTION This structure filled in on success. - @return Error code indicating success or failure - @see PaWasapi_GetJackCount - */ -PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription); - - -/* - IMPORTANT: - - WASAPI is implemented for Callback and Blocking interfaces. It supports Shared and Exclusive - share modes. - - Exclusive Mode: - - Exclusive mode allows to deliver audio data directly to hardware bypassing - software mixing. - Exclusive mode is specified by 'paWinWasapiExclusive' flag. - - Callback Interface: - - Provides best audio quality with low latency. Callback interface is implemented in - two versions: - - 1) Event-Driven: - This is the most powerful WASAPI implementation which provides glitch-free - audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is - 3 ms for HD Audio class audio chips. For the Shared mode latency can not be - lower than 20 ms. - - 2) Poll-Driven: - Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven - and provides latency at around 10-13ms. Polling must be used to overcome a system bug - under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply - times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug - does not exist in Vista x86 or Windows 7. - Polling can be setup by speciying 'paWinWasapiPolling' flag. Our WASAPI implementation detects - WOW64 bug and sets 'paWinWasapiPolling' automatically. - - Thread priority: - - Normally thread priority is set automatically and does not require modification. Although - if user wants some tweaking thread priority can be modified by setting 'paWinWasapiThreadPriority' - flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority - enum. - - Blocking Interface: - - Blocking interface is implemented but due to above described Poll-Driven method can not - deliver lowest possible latency. Specifying too low latency in Shared mode will result in - distorted audio although Exclusive mode adds stability. - - Pa_IsFormatSupported: - - To check format with correct Share Mode (Exclusive/Shared) you must supply - PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of - PaStreamParameters::hostApiSpecificStreamInfo structure. - - Pa_OpenStream: - - To set desired Share Mode (Exclusive/Shared) you must supply - PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of - PaStreamParameters::hostApiSpecificStreamInfo structure. -*/ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_WIN_WASAPI_H */ diff --git a/libs/portaudio/include/pa_win_waveformat.h b/libs/portaudio/include/pa_win_waveformat.h deleted file mode 100644 index 2c00267117d..00000000000 --- a/libs/portaudio/include/pa_win_waveformat.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef PA_WIN_WAVEFORMAT_H -#define PA_WIN_WAVEFORMAT_H - -/* - * PortAudio Portable Real-Time Audio Library - * Windows WAVEFORMAT* data structure utilities - * portaudio.h should be included before this file. - * - * Copyright (c) 2007 Ross Bencina - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup public_header - @brief Windows specific PortAudio API extension and utilities header file. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - The following #defines for speaker channel masks are the same - as those in ksmedia.h, except with PAWIN_ prepended, KSAUDIO_ removed - in some cases, and casts to PaWinWaveFormatChannelMask added. -*/ - -typedef unsigned long PaWinWaveFormatChannelMask; - -/* Speaker Positions: */ -#define PAWIN_SPEAKER_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1) -#define PAWIN_SPEAKER_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x2) -#define PAWIN_SPEAKER_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x4) -#define PAWIN_SPEAKER_LOW_FREQUENCY ((PaWinWaveFormatChannelMask)0x8) -#define PAWIN_SPEAKER_BACK_LEFT ((PaWinWaveFormatChannelMask)0x10) -#define PAWIN_SPEAKER_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20) -#define PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER ((PaWinWaveFormatChannelMask)0x40) -#define PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER ((PaWinWaveFormatChannelMask)0x80) -#define PAWIN_SPEAKER_BACK_CENTER ((PaWinWaveFormatChannelMask)0x100) -#define PAWIN_SPEAKER_SIDE_LEFT ((PaWinWaveFormatChannelMask)0x200) -#define PAWIN_SPEAKER_SIDE_RIGHT ((PaWinWaveFormatChannelMask)0x400) -#define PAWIN_SPEAKER_TOP_CENTER ((PaWinWaveFormatChannelMask)0x800) -#define PAWIN_SPEAKER_TOP_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1000) -#define PAWIN_SPEAKER_TOP_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x2000) -#define PAWIN_SPEAKER_TOP_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x4000) -#define PAWIN_SPEAKER_TOP_BACK_LEFT ((PaWinWaveFormatChannelMask)0x8000) -#define PAWIN_SPEAKER_TOP_BACK_CENTER ((PaWinWaveFormatChannelMask)0x10000) -#define PAWIN_SPEAKER_TOP_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20000) - -/* Bit mask locations reserved for future use */ -#define PAWIN_SPEAKER_RESERVED ((PaWinWaveFormatChannelMask)0x7FFC0000) - -/* Used to specify that any possible permutation of speaker configurations */ -#define PAWIN_SPEAKER_ALL ((PaWinWaveFormatChannelMask)0x80000000) - -/* DirectSound Speaker Config */ -#define PAWIN_SPEAKER_DIRECTOUT 0 -#define PAWIN_SPEAKER_MONO (PAWIN_SPEAKER_FRONT_CENTER) -#define PAWIN_SPEAKER_STEREO (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT) -#define PAWIN_SPEAKER_QUAD (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) -#define PAWIN_SPEAKER_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_BACK_CENTER) -#define PAWIN_SPEAKER_5POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ - PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) -#define PAWIN_SPEAKER_7POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ - PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ - PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER | PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER) -#define PAWIN_SPEAKER_5POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ - PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) -#define PAWIN_SPEAKER_7POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ - PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ - PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ - PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) -/* - According to the Microsoft documentation: - The following are obsolete 5.1 and 7.1 settings (they lack side speakers). Note this means - that the default 5.1 and 7.1 settings (KSAUDIO_SPEAKER_5POINT1 and KSAUDIO_SPEAKER_7POINT1 are - similarly obsolete but are unchanged for compatibility reasons). -*/ -#define PAWIN_SPEAKER_5POINT1_BACK PAWIN_SPEAKER_5POINT1 -#define PAWIN_SPEAKER_7POINT1_WIDE PAWIN_SPEAKER_7POINT1 - -/* DVD Speaker Positions */ -#define PAWIN_SPEAKER_GROUND_FRONT_LEFT PAWIN_SPEAKER_FRONT_LEFT -#define PAWIN_SPEAKER_GROUND_FRONT_CENTER PAWIN_SPEAKER_FRONT_CENTER -#define PAWIN_SPEAKER_GROUND_FRONT_RIGHT PAWIN_SPEAKER_FRONT_RIGHT -#define PAWIN_SPEAKER_GROUND_REAR_LEFT PAWIN_SPEAKER_BACK_LEFT -#define PAWIN_SPEAKER_GROUND_REAR_RIGHT PAWIN_SPEAKER_BACK_RIGHT -#define PAWIN_SPEAKER_TOP_MIDDLE PAWIN_SPEAKER_TOP_CENTER -#define PAWIN_SPEAKER_SUPER_WOOFER PAWIN_SPEAKER_LOW_FREQUENCY - - -/* - PaWinWaveFormat is defined here to provide compatibility with - compilation environments which don't have headers defining - WAVEFORMATEXTENSIBLE (e.g. older versions of MSVC, Borland C++ etc. - - The fields for WAVEFORMATEX and WAVEFORMATEXTENSIBLE are declared as an - unsigned char array here to avoid clients who include this file having - a dependency on windows.h and mmsystem.h, and also to to avoid having - to write separate packing pragmas for each compiler. -*/ -#define PAWIN_SIZEOF_WAVEFORMATEX 18 -#define PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE (PAWIN_SIZEOF_WAVEFORMATEX + 22) - -typedef struct{ - unsigned char fields[ PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE ]; - unsigned long extraLongForAlignment; /* ensure that compiler aligns struct to DWORD */ -} PaWinWaveFormat; - -/* - WAVEFORMATEXTENSIBLE fields: - - union { - WORD wValidBitsPerSample; - WORD wSamplesPerBlock; - WORD wReserved; - } Samples; - DWORD dwChannelMask; - GUID SubFormat; -*/ - -#define PAWIN_INDEXOF_WVALIDBITSPERSAMPLE (PAWIN_SIZEOF_WAVEFORMATEX+0) -#define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2) -#define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6) - - -/* - Valid values to pass for the waveFormatTag PaWin_InitializeWaveFormatEx and - PaWin_InitializeWaveFormatExtensible functions below. These must match - the standard Windows WAVE_FORMAT_* values. -*/ -#define PAWIN_WAVE_FORMAT_PCM (1) -#define PAWIN_WAVE_FORMAT_IEEE_FLOAT (3) -#define PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092) -#define PAWIN_WAVE_FORMAT_WMA_SPDIF (0x0164) - - -/* - returns PAWIN_WAVE_FORMAT_PCM or PAWIN_WAVE_FORMAT_IEEE_FLOAT - depending on the sampleFormat parameter. -*/ -int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ); - -/* - Use the following two functions to initialize the waveformat structure. -*/ - -void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ); - - -void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, - PaWinWaveFormatChannelMask channelMask ); - - -/* Map a channel count to a speaker channel mask */ -PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_WIN_WAVEFORMAT_H */ \ No newline at end of file diff --git a/libs/portaudio/include/pa_win_wmme.h b/libs/portaudio/include/pa_win_wmme.h deleted file mode 100644 index ac5efe782f6..00000000000 --- a/libs/portaudio/include/pa_win_wmme.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef PA_WIN_WMME_H -#define PA_WIN_WMME_H -/* - * $Id: pa_win_wmme.h 1592 2011-02-04 10:41:58Z rossb $ - * PortAudio Portable Real-Time Audio Library - * MME specific extensions - * - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup public_header - @brief WMME-specific PortAudio API extension header file. -*/ - -#include "portaudio.h" -#include "pa_win_waveformat.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -/* The following are flags which can be set in - PaWinMmeStreamInfo's flags field. -*/ - -#define paWinMmeUseLowLevelLatencyParameters (0x01) -#define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */ -#define paWinMmeUseChannelMask (0x04) - -/* By default, the mme implementation drops the processing thread's priority - to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% - This flag disables any priority throttling. The processing thread will always - run at THREAD_PRIORITY_TIME_CRITICAL. -*/ -#define paWinMmeDontThrottleOverloadedProcessingThread (0x08) - -/* Flags for non-PCM spdif passthrough. -*/ -#define paWinMmeWaveFormatDolbyAc3Spdif (0x10) -#define paWinMmeWaveFormatWmaSpdif (0x20) - - -typedef struct PaWinMmeDeviceAndChannelCount{ - PaDeviceIndex device; - int channelCount; -}PaWinMmeDeviceAndChannelCount; - - -typedef struct PaWinMmeStreamInfo{ - unsigned long size; /**< sizeof(PaWinMmeStreamInfo) */ - PaHostApiTypeId hostApiType; /**< paMME */ - unsigned long version; /**< 1 */ - - unsigned long flags; - - /* low-level latency setting support - These settings control the number and size of host buffers in order - to set latency. They will be used instead of the generic parameters - to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters - flag. - - If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters - are supplied for both input and output in a full duplex stream, then the - input and output framesPerBuffer must be the same, or the larger of the - two must be a multiple of the smaller, otherwise a - paIncompatibleHostApiSpecificStreamInfo error will be returned from - Pa_OpenStream(). - */ - unsigned long framesPerBuffer; - unsigned long bufferCount; /* formerly numBuffers */ - - /* multiple devices per direction support - If flags contains the PaWinMmeUseMultipleDevices flag, - this functionality will be used, otherwise the device parameter to - Pa_OpenStream() will be used instead. - If devices are specified here, the corresponding device parameter - to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification, - otherwise an paInvalidDevice error will result. - The total number of channels accross all specified devices - must agree with the corresponding channelCount parameter to - Pa_OpenStream() otherwise a paInvalidChannelCount error will result. - */ - PaWinMmeDeviceAndChannelCount *devices; - unsigned long deviceCount; - - /* - support for WAVEFORMATEXTENSIBLE channel masks. If flags contains - paWinMmeUseChannelMask this allows you to specify which speakers - to address in a multichannel stream. Constants for channelMask - are specified in pa_win_waveformat.h - - */ - PaWinWaveFormatChannelMask channelMask; - -}PaWinMmeStreamInfo; - - -/** Retrieve the number of wave in handles used by a PortAudio WinMME stream. - Returns zero if the stream is output only. - - @return A non-negative value indicating the number of wave in handles - or, a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. - - @see PaWinMME_GetStreamInputHandle -*/ -int PaWinMME_GetStreamInputHandleCount( PaStream* stream ); - - -/** Retrieve a wave in handle used by a PortAudio WinMME stream. - - @param stream The stream to query. - @param handleIndex The zero based index of the wave in handle to retrieve. This - should be in the range [0, PaWinMME_GetStreamInputHandleCount(stream)-1]. - - @return A valid wave in handle, or NULL if an error occurred. - - @see PaWinMME_GetStreamInputHandle -*/ -HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex ); - - -/** Retrieve the number of wave out handles used by a PortAudio WinMME stream. - Returns zero if the stream is input only. - - @return A non-negative value indicating the number of wave out handles - or, a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. - - @see PaWinMME_GetStreamOutputHandle -*/ -int PaWinMME_GetStreamOutputHandleCount( PaStream* stream ); - - -/** Retrieve a wave out handle used by a PortAudio WinMME stream. - - @param stream The stream to query. - @param handleIndex The zero based index of the wave out handle to retrieve. - This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1]. - - @return A valid wave out handle, or NULL if an error occurred. - - @see PaWinMME_GetStreamOutputHandleCount -*/ -HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex ); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_WIN_WMME_H */ diff --git a/libs/portaudio/include/portaudio.h b/libs/portaudio/include/portaudio.h deleted file mode 100644 index f26e09d79cd..00000000000 --- a/libs/portaudio/include/portaudio.h +++ /dev/null @@ -1,1149 +0,0 @@ -#ifndef PORTAUDIO_H -#define PORTAUDIO_H -/* - * $Id: portaudio.h 1594 2011-02-05 14:33:29Z rossb $ - * PortAudio Portable Real-Time Audio Library - * PortAudio API Header File - * Latest version available at: http://www.portaudio.com/ - * - * Copyright (c) 1999-2002 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup public_header - @brief The portable PortAudio API. -*/ - - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -/** Retrieve the release number of the currently running PortAudio build, - eg 1900. -*/ -int Pa_GetVersion( void ); - - -/** Retrieve a textual description of the current PortAudio build, - eg "PortAudio V19-devel 13 October 2002". -*/ -const char* Pa_GetVersionText( void ); - - -/** Error codes returned by PortAudio functions. - Note that with the exception of paNoError, all PaErrorCodes are negative. -*/ - -typedef int PaError; -typedef enum PaErrorCode -{ - paNoError = 0, - - paNotInitialized = -10000, - paUnanticipatedHostError, - paInvalidChannelCount, - paInvalidSampleRate, - paInvalidDevice, - paInvalidFlag, - paSampleFormatNotSupported, - paBadIODeviceCombination, - paInsufficientMemory, - paBufferTooBig, - paBufferTooSmall, - paNullCallback, - paBadStreamPtr, - paTimedOut, - paInternalError, - paDeviceUnavailable, - paIncompatibleHostApiSpecificStreamInfo, - paStreamIsStopped, - paStreamIsNotStopped, - paInputOverflowed, - paOutputUnderflowed, - paHostApiNotFound, - paInvalidHostApi, - paCanNotReadFromACallbackStream, - paCanNotWriteToACallbackStream, - paCanNotReadFromAnOutputOnlyStream, - paCanNotWriteToAnInputOnlyStream, - paIncompatibleStreamHostApi, - paBadBufferPtr -} PaErrorCode; - - -/** Translate the supplied PortAudio error code into a human readable - message. -*/ -const char *Pa_GetErrorText( PaError errorCode ); - - -/** Library initialization function - call this before using PortAudio. - This function initializes internal data structures and prepares underlying - host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), - and Pa_GetErrorText(), this function MUST be called before using any other - PortAudio API functions. - - If Pa_Initialize() is called multiple times, each successful - call must be matched with a corresponding call to Pa_Terminate(). - Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not - required to be fully nested. - - Note that if Pa_Initialize() returns an error code, Pa_Terminate() should - NOT be called. - - @return paNoError if successful, otherwise an error code indicating the cause - of failure. - - @see Pa_Terminate -*/ -PaError Pa_Initialize( void ); - - -/** Library termination function - call this when finished using PortAudio. - This function deallocates all resources allocated by PortAudio since it was - initialized by a call to Pa_Initialize(). In cases where Pa_Initialise() has - been called multiple times, each call must be matched with a corresponding call - to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically - close any PortAudio streams that are still open. - - Pa_Terminate() MUST be called before exiting a program which uses PortAudio. - Failure to do so may result in serious resource leaks, such as audio devices - not being available until the next reboot. - - @return paNoError if successful, otherwise an error code indicating the cause - of failure. - - @see Pa_Initialize -*/ -PaError Pa_Terminate( void ); - - - -/** The type used to refer to audio devices. Values of this type usually - range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice - and paUseHostApiSpecificDeviceSpecification values. - - @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification -*/ -typedef int PaDeviceIndex; - - -/** A special PaDeviceIndex value indicating that no device is available, - or should be used. - - @see PaDeviceIndex -*/ -#define paNoDevice ((PaDeviceIndex)-1) - - -/** A special PaDeviceIndex value indicating that the device(s) to be used - are specified in the host api specific stream info structure. - - @see PaDeviceIndex -*/ -#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) - - -/* Host API enumeration mechanism */ - -/** The type used to enumerate to host APIs at runtime. Values of this type - range from 0 to (Pa_GetHostApiCount()-1). - - @see Pa_GetHostApiCount -*/ -typedef int PaHostApiIndex; - - -/** Retrieve the number of available host APIs. Even if a host API is - available it may have no devices available. - - @return A non-negative value indicating the number of available host APIs - or, a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. - - @see PaHostApiIndex -*/ -PaHostApiIndex Pa_GetHostApiCount( void ); - - -/** Retrieve the index of the default host API. The default host API will be - the lowest common denominator host API on the current platform and is - unlikely to provide the best performance. - - @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) - indicating the default host API index or, a PaErrorCode (which are always - negative) if PortAudio is not initialized or an error is encountered. -*/ -PaHostApiIndex Pa_GetDefaultHostApi( void ); - - -/** Unchanging unique identifiers for each supported host API. This type - is used in the PaHostApiInfo structure. The values are guaranteed to be - unique and to never change, thus allowing code to be written that - conditionally uses host API specific extensions. - - New type ids will be allocated when support for a host API reaches - "public alpha" status, prior to that developers should use the - paInDevelopment type id. - - @see PaHostApiInfo -*/ -typedef enum PaHostApiTypeId -{ - paInDevelopment=0, /* use while developing support for a new host API */ - paDirectSound=1, - paMME=2, - paASIO=3, - paSoundManager=4, - paCoreAudio=5, - paOSS=7, - paALSA=8, - paAL=9, - paBeOS=10, - paWDMKS=11, - paJACK=12, - paWASAPI=13, - paAudioScienceHPI=14 -} PaHostApiTypeId; - - -/** A structure containing information about a particular host API. */ - -typedef struct PaHostApiInfo -{ - /** this is struct version 1 */ - int structVersion; - /** The well known unique identifier of this host API @see PaHostApiTypeId */ - PaHostApiTypeId type; - /** A textual description of the host API for display on user interfaces. */ - const char *name; - - /** The number of devices belonging to this host API. This field may be - used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate - all devices for this host API. - @see Pa_HostApiDeviceIndexToDeviceIndex - */ - int deviceCount; - - /** The default input device for this host API. The value will be a - device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice - if no default input device is available. - */ - PaDeviceIndex defaultInputDevice; - - /** The default output device for this host API. The value will be a - device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice - if no default output device is available. - */ - PaDeviceIndex defaultOutputDevice; - -} PaHostApiInfo; - - -/** Retrieve a pointer to a structure containing information about a specific - host Api. - - @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) - - @return A pointer to an immutable PaHostApiInfo structure describing - a specific host API. If the hostApi parameter is out of range or an error - is encountered, the function returns NULL. - - The returned structure is owned by the PortAudio implementation and must not - be manipulated or freed. The pointer is only guaranteed to be valid between - calls to Pa_Initialize() and Pa_Terminate(). -*/ -const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); - - -/** Convert a static host API unique identifier, into a runtime - host API index. - - @param type A unique host API identifier belonging to the PaHostApiTypeId - enumeration. - - @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, - a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. - - The paHostApiNotFound error code indicates that the host API specified by the - type parameter is not available. - - @see PaHostApiTypeId -*/ -PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); - - -/** Convert a host-API-specific device index to standard PortAudio device index. - This function may be used in conjunction with the deviceCount field of - PaHostApiInfo to enumerate all devices for the specified host API. - - @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) - - @param hostApiDeviceIndex A valid per-host device index in the range - 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) - - @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) - or, a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. - - A paInvalidHostApi error code indicates that the host API index specified by - the hostApi parameter is out of range. - - A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter - is out of range. - - @see PaHostApiInfo -*/ -PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, - int hostApiDeviceIndex ); - - - -/** Structure used to return information about a host error condition. -*/ -typedef struct PaHostErrorInfo{ - PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ - long errorCode; /**< the error code returned */ - const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ -}PaHostErrorInfo; - - -/** Return information about the last host error encountered. The error - information returned by Pa_GetLastHostErrorInfo() will never be modified - asynchronously by errors occurring in other PortAudio owned threads - (such as the thread that manages the stream callback.) - - This function is provided as a last resort, primarily to enhance debugging - by providing clients with access to all available error information. - - @return A pointer to an immutable structure constraining information about - the host error. The values in this structure will only be valid if a - PortAudio function has previously returned the paUnanticipatedHostError - error code. -*/ -const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); - - - -/* Device enumeration and capabilities */ - -/** Retrieve the number of available devices. The number of available devices - may be zero. - - @return A non-negative value indicating the number of available devices or, - a PaErrorCode (which are always negative) if PortAudio is not initialized - or an error is encountered. -*/ -PaDeviceIndex Pa_GetDeviceCount( void ); - - -/** Retrieve the index of the default input device. The result can be - used in the inputDevice parameter to Pa_OpenStream(). - - @return The default input device index for the default host API, or paNoDevice - if no default input device is available or an error was encountered. -*/ -PaDeviceIndex Pa_GetDefaultInputDevice( void ); - - -/** Retrieve the index of the default output device. The result can be - used in the outputDevice parameter to Pa_OpenStream(). - - @return The default output device index for the default host API, or paNoDevice - if no default output device is available or an error was encountered. - - @note - On the PC, the user can specify a default device by - setting an environment variable. For example, to use device #1. -
    - set PA_RECOMMENDED_OUTPUT_DEVICE=1
    -
    - The user should first determine the available device ids by using - the supplied application "pa_devs". -*/ -PaDeviceIndex Pa_GetDefaultOutputDevice( void ); - - -/** The type used to represent monotonic time in seconds. PaTime is - used for the fields of the PaStreamCallbackTimeInfo argument to the - PaStreamCallback and as the result of Pa_GetStreamTime(). - - PaTime values have unspecified origin. - - @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime -*/ -typedef double PaTime; - - -/** A type used to specify one or more sample formats. Each value indicates - a possible format for sound data passed to and from the stream callback, - Pa_ReadStream and Pa_WriteStream. - - The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 - and aUInt8 are usually implemented by all implementations. - - The floating point representation (paFloat32) uses +1.0 and -1.0 as the - maximum and minimum respectively. - - paUInt8 is an unsigned 8 bit format where 128 is considered "ground" - - The paNonInterleaved flag indicates that audio data is passed as an array - of pointers to separate buffers, one buffer for each channel. Usually, - when this flag is not used, audio data is passed as a single buffer with - all channels interleaved. - - @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo - @see paFloat32, paInt16, paInt32, paInt24, paInt8 - @see paUInt8, paCustomFormat, paNonInterleaved -*/ -typedef unsigned long PaSampleFormat; - - -#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ -#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ -#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ -#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ -#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ -#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ -#define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ - -#define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ - -/** A structure providing information and capabilities of PortAudio devices. - Devices may support input, output or both input and output. -*/ -typedef struct PaDeviceInfo -{ - int structVersion; /* this is struct version 2 */ - const char *name; - PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ - - int maxInputChannels; - int maxOutputChannels; - - /* Default latency values for interactive performance. */ - PaTime defaultLowInputLatency; - PaTime defaultLowOutputLatency; - /* Default latency values for robust non-interactive applications (eg. playing sound files). */ - PaTime defaultHighInputLatency; - PaTime defaultHighOutputLatency; - - double defaultSampleRate; -} PaDeviceInfo; - - -/** Retrieve a pointer to a PaDeviceInfo structure containing information - about the specified device. - @return A pointer to an immutable PaDeviceInfo structure. If the device - parameter is out of range the function returns NULL. - - @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) - - @note PortAudio manages the memory referenced by the returned pointer, - the client must not manipulate or free the memory. The pointer is only - guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). - - @see PaDeviceInfo, PaDeviceIndex -*/ -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); - - -/** Parameters for one direction (input or output) of a stream. -*/ -typedef struct PaStreamParameters -{ - /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) - specifying the device to be used or the special constant - paUseHostApiSpecificDeviceSpecification which indicates that the actual - device(s) to use are specified in hostApiSpecificStreamInfo. - This field must not be set to paNoDevice. - */ - PaDeviceIndex device; - - /** The number of channels of sound to be delivered to the - stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). - It can range from 1 to the value of maxInputChannels in the - PaDeviceInfo record for the device specified by the device parameter. - */ - int channelCount; - - /** The sample format of the buffer provided to the stream callback, - a_ReadStream() or Pa_WriteStream(). It may be any of the formats described - by the PaSampleFormat enumeration. - */ - PaSampleFormat sampleFormat; - - /** The desired latency in seconds. Where practical, implementations should - configure their latency based on these parameters, otherwise they may - choose the closest viable latency instead. Unless the suggested latency - is greater than the absolute upper limit for the device implementations - should round the suggestedLatency up to the next practical value - ie to - provide an equal or higher latency than suggestedLatency wherever possible. - Actual latency values for an open stream may be retrieved using the - inputLatency and outputLatency fields of the PaStreamInfo structure - returned by Pa_GetStreamInfo(). - @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo - */ - PaTime suggestedLatency; - - /** An optional pointer to a host api specific data structure - containing additional information for device setup and/or stream processing. - hostApiSpecificStreamInfo is never required for correct operation, - if not used it should be set to NULL. - */ - void *hostApiSpecificStreamInfo; - -} PaStreamParameters; - - -/** Return code for Pa_IsFormatSupported indicating success. */ -#define paFormatIsSupported (0) - -/** Determine whether it would be possible to open a stream with the specified - parameters. - - @param inputParameters A structure that describes the input parameters used to - open a stream. The suggestedLatency field is ignored. See PaStreamParameters - for a description of these parameters. inputParameters must be NULL for - output-only streams. - - @param outputParameters A structure that describes the output parameters used - to open a stream. The suggestedLatency field is ignored. See PaStreamParameters - for a description of these parameters. outputParameters must be NULL for - input-only streams. - - @param sampleRate The required sampleRate. For full-duplex streams it is the - sample rate for both input and output - - @return Returns 0 if the format is supported, and an error code indicating why - the format is not supported otherwise. The constant paFormatIsSupported is - provided to compare with the return value for success. - - @see paFormatIsSupported, PaStreamParameters -*/ -PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ); - - - -/* Streaming types and functions */ - - -/** - A single PaStream can provide multiple channels of real-time - streaming audio input and output to a client application. A stream - provides access to audio hardware represented by one or more - PaDevices. Depending on the underlying Host API, it may be possible - to open multiple streams using the same device, however this behavior - is implementation defined. Portable applications should assume that - a PaDevice may be simultaneously used by at most one PaStream. - - Pointers to PaStream objects are passed between PortAudio functions that - operate on streams. - - @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, - Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, - Pa_GetStreamTime, Pa_GetStreamCpuLoad - -*/ -typedef void PaStream; - - -/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() - or Pa_OpenDefaultStream() to indicate that the stream callback will - accept buffers of any size. -*/ -#define paFramesPerBufferUnspecified (0) - - -/** Flags used to control the behavior of a stream. They are passed as - parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be - ORed together. - - @see Pa_OpenStream, Pa_OpenDefaultStream - @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, - paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags -*/ -typedef unsigned long PaStreamFlags; - -/** @see PaStreamFlags */ -#define paNoFlag ((PaStreamFlags) 0) - -/** Disable default clipping of out of range samples. - @see PaStreamFlags -*/ -#define paClipOff ((PaStreamFlags) 0x00000001) - -/** Disable default dithering. - @see PaStreamFlags -*/ -#define paDitherOff ((PaStreamFlags) 0x00000002) - -/** Flag requests that where possible a full duplex stream will not discard - overflowed input samples without calling the stream callback. This flag is - only valid for full duplex callback streams and only when used in combination - with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using - this flag incorrectly results in a paInvalidFlag error being returned from - Pa_OpenStream and Pa_OpenDefaultStream. - - @see PaStreamFlags, paFramesPerBufferUnspecified -*/ -#define paNeverDropInput ((PaStreamFlags) 0x00000004) - -/** Call the stream callback to fill initial output buffers, rather than the - default behavior of priming the buffers with zeros (silence). This flag has - no effect for input-only and blocking read/write streams. - - @see PaStreamFlags -*/ -#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) - -/** A mask specifying the platform specific bits. - @see PaStreamFlags -*/ -#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) - -/** - Timing information for the buffers passed to the stream callback. -*/ -typedef struct PaStreamCallbackTimeInfo{ - PaTime inputBufferAdcTime; - PaTime currentTime; - PaTime outputBufferDacTime; -} PaStreamCallbackTimeInfo; - - -/** - Flag bit constants for the statusFlags to PaStreamCallback. - - @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, - paPrimingOutput -*/ -typedef unsigned long PaStreamCallbackFlags; - -/** In a stream opened with paFramesPerBufferUnspecified, indicates that - input data is all silence (zeros) because no real data is available. In a - stream opened without paFramesPerBufferUnspecified, it indicates that one or - more zero samples have been inserted into the input buffer to compensate - for an input underflow. - @see PaStreamCallbackFlags -*/ -#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) - -/** In a stream opened with paFramesPerBufferUnspecified, indicates that data - prior to the first sample of the input buffer was discarded due to an - overflow, possibly because the stream callback is using too much CPU time. - Otherwise indicates that data prior to one or more samples in the - input buffer was discarded. - @see PaStreamCallbackFlags -*/ -#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) - -/** Indicates that output data (or a gap) was inserted, possibly because the - stream callback is using too much CPU time. - @see PaStreamCallbackFlags -*/ -#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) - -/** Indicates that output data will be discarded because no room is available. - @see PaStreamCallbackFlags -*/ -#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) - -/** Some of all of the output data will be used to prime the stream, input - data may be zero. - @see PaStreamCallbackFlags -*/ -#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) - -/** - Allowable return values for the PaStreamCallback. - @see PaStreamCallback -*/ -typedef enum PaStreamCallbackResult -{ - paContinue=0, - paComplete=1, - paAbort=2 -} PaStreamCallbackResult; - - -/** - Functions of type PaStreamCallback are implemented by PortAudio clients. - They consume, process or generate audio in response to requests from an - active PortAudio stream. - - @param input and @param output are either arrays of interleaved samples or; - if non-interleaved samples were requested using the paNonInterleaved sample - format flag, an array of buffer pointers, one non-interleaved buffer for - each channel. - - The format, packing and number of channels used by the buffers are - determined by parameters to Pa_OpenStream(). - - @param frameCount The number of sample frames to be processed by - the stream callback. - - @param timeInfo The time in seconds when the first sample of the input - buffer was received at the audio input, the time in seconds when the first - sample of the output buffer will begin being played at the audio output, and - the time in seconds when the stream callback was called. - See also Pa_GetStreamTime() - - @param statusFlags Flags indicating whether input and/or output buffers - have been inserted or will be dropped to overcome underflow or overflow - conditions. - - @param userData The value of a user supplied pointer passed to - Pa_OpenStream() intended for storing synthesis data etc. - - @return - The stream callback should return one of the values in the - PaStreamCallbackResult enumeration. To ensure that the callback continues - to be called, it should return paContinue (0). Either paComplete or paAbort - can be returned to finish stream processing, after either of these values is - returned the callback will not be called again. If paAbort is returned the - stream will finish as soon as possible. If paComplete is returned, the stream - will continue until all buffers generated by the callback have been played. - This may be useful in applications such as soundfile players where a specific - duration of output is required. However, it is not necessary to utilize this - mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also - be used to stop the stream. The callback must always fill the entire output - buffer irrespective of its return value. - - @see Pa_OpenStream, Pa_OpenDefaultStream - - @note With the exception of Pa_GetStreamCpuLoad() it is not permissible to call - PortAudio API functions from within the stream callback. -*/ -typedef int PaStreamCallback( - const void *input, void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ); - - -/** Opens a stream for either input, output or both. - - @param stream The address of a PaStream pointer which will receive - a pointer to the newly opened stream. - - @param inputParameters A structure that describes the input parameters used by - the opened stream. See PaStreamParameters for a description of these parameters. - inputParameters must be NULL for output-only streams. - - @param outputParameters A structure that describes the output parameters used by - the opened stream. See PaStreamParameters for a description of these parameters. - outputParameters must be NULL for input-only streams. - - @param sampleRate The desired sampleRate. For full-duplex streams it is the - sample rate for both input and output - - @param framesPerBuffer The number of frames passed to the stream callback - function, or the preferred block granularity for a blocking read/write stream. - The special value paFramesPerBufferUnspecified (0) may be used to request that - the stream callback will receive an optimal (and possibly varying) number of - frames based on host requirements and the requested latency settings. - Note: With some host APIs, the use of non-zero framesPerBuffer for a callback - stream may introduce an additional layer of buffering which could introduce - additional latency. PortAudio guarantees that the additional latency - will be kept to the theoretical minimum however, it is strongly recommended - that a non-zero framesPerBuffer value only be used when your algorithm - requires a fixed number of frames per stream callback. - - @param streamFlags Flags which modify the behavior of the streaming process. - This parameter may contain a combination of flags ORed together. Some flags may - only be relevant to certain buffer formats. - - @param streamCallback A pointer to a client supplied function that is responsible - for processing and filling input and output buffers. If this parameter is NULL - the stream will be opened in 'blocking read/write' mode. In blocking mode, - the client can receive sample data using Pa_ReadStream and write sample data - using Pa_WriteStream, the number of samples that may be read or written - without blocking is returned by Pa_GetStreamReadAvailable and - Pa_GetStreamWriteAvailable respectively. - - @param userData A client supplied pointer which is passed to the stream callback - function. It could for example, contain a pointer to instance data necessary - for processing the audio buffers. This parameter is ignored if streamCallback - is NULL. - - @return - Upon success Pa_OpenStream() returns paNoError and places a pointer to a - valid PaStream in the stream argument. The stream is inactive (stopped). - If a call to Pa_OpenStream() fails, a non-zero error code is returned (see - PaError for possible error codes) and the value of stream is invalid. - - @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, - Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable -*/ -PaError Pa_OpenStream( PaStream** stream, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ); - - -/** A simplified version of Pa_OpenStream() that opens the default input - and/or output devices. - - @param stream The address of a PaStream pointer which will receive - a pointer to the newly opened stream. - - @param numInputChannels The number of channels of sound that will be supplied - to the stream callback or returned by Pa_ReadStream. It can range from 1 to - the value of maxInputChannels in the PaDeviceInfo record for the default input - device. If 0 the stream is opened as an output-only stream. - - @param numOutputChannels The number of channels of sound to be delivered to the - stream callback or passed to Pa_WriteStream. It can range from 1 to the value - of maxOutputChannels in the PaDeviceInfo record for the default output device. - If 0 the stream is opened as an output-only stream. - - @param sampleFormat The sample format of both the input and output buffers - provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. - sampleFormat may be any of the formats described by the PaSampleFormat - enumeration. - - @param sampleRate Same as Pa_OpenStream parameter of the same name. - @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. - @param streamCallback Same as Pa_OpenStream parameter of the same name. - @param userData Same as Pa_OpenStream parameter of the same name. - - @return As for Pa_OpenStream - - @see Pa_OpenStream, PaStreamCallback -*/ -PaError Pa_OpenDefaultStream( PaStream** stream, - int numInputChannels, - int numOutputChannels, - PaSampleFormat sampleFormat, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamCallback *streamCallback, - void *userData ); - - -/** Closes an audio stream. If the audio stream is active it - discards any pending buffers as if Pa_AbortStream() had been called. -*/ -PaError Pa_CloseStream( PaStream *stream ); - - -/** Functions of type PaStreamFinishedCallback are implemented by PortAudio - clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback - function. Once registered they are called when the stream becomes inactive - (ie once a call to Pa_StopStream() will not block). - A stream will become inactive after the stream callback returns non-zero, - or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio - output, if the stream callback returns paComplete, or Pa_StopStream is called, - the stream finished callback will not be called until all generated sample data - has been played. - - @param userData The userData parameter supplied to Pa_OpenStream() - - @see Pa_SetStreamFinishedCallback -*/ -typedef void PaStreamFinishedCallback( void *userData ); - - -/** Register a stream finished callback function which will be called when the - stream becomes inactive. See the description of PaStreamFinishedCallback for - further details about when the callback will be called. - - @param stream a pointer to a PaStream that is in the stopped state - if the - stream is not stopped, the stream's finished callback will remain unchanged - and an error code will be returned. - - @param streamFinishedCallback a pointer to a function with the same signature - as PaStreamFinishedCallback, that will be called when the stream becomes - inactive. Passing NULL for this parameter will un-register a previously - registered stream finished callback function. - - @return on success returns paNoError, otherwise an error code indicating the cause - of the error. - - @see PaStreamFinishedCallback -*/ -PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); - - -/** Commences audio processing. -*/ -PaError Pa_StartStream( PaStream *stream ); - - -/** Terminates audio processing. It waits until all pending - audio buffers have been played before it returns. -*/ -PaError Pa_StopStream( PaStream *stream ); - - -/** Terminates audio processing immediately without waiting for pending - buffers to complete. -*/ -PaError Pa_AbortStream( PaStream *stream ); - - -/** Determine whether the stream is stopped. - A stream is considered to be stopped prior to a successful call to - Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. - If a stream callback returns a value other than paContinue the stream is NOT - considered to be stopped. - - @return Returns one (1) when the stream is stopped, zero (0) when - the stream is running or, a PaErrorCode (which are always negative) if - PortAudio is not initialized or an error is encountered. - - @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive -*/ -PaError Pa_IsStreamStopped( PaStream *stream ); - - -/** Determine whether the stream is active. - A stream is active after a successful call to Pa_StartStream(), until it - becomes inactive either as a result of a call to Pa_StopStream() or - Pa_AbortStream(), or as a result of a return value other than paContinue from - the stream callback. In the latter case, the stream is considered inactive - after the last buffer has finished playing. - - @return Returns one (1) when the stream is active (ie playing or recording - audio), zero (0) when not playing or, a PaErrorCode (which are always negative) - if PortAudio is not initialized or an error is encountered. - - @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped -*/ -PaError Pa_IsStreamActive( PaStream *stream ); - - - -/** A structure containing unchanging information about an open stream. - @see Pa_GetStreamInfo -*/ - -typedef struct PaStreamInfo -{ - /** this is struct version 1 */ - int structVersion; - - /** The input latency of the stream in seconds. This value provides the most - accurate estimate of input latency available to the implementation. It may - differ significantly from the suggestedLatency value passed to Pa_OpenStream(). - The value of this field will be zero (0.) for output-only streams. - @see PaTime - */ - PaTime inputLatency; - - /** The output latency of the stream in seconds. This value provides the most - accurate estimate of output latency available to the implementation. It may - differ significantly from the suggestedLatency value passed to Pa_OpenStream(). - The value of this field will be zero (0.) for input-only streams. - @see PaTime - */ - PaTime outputLatency; - - /** The sample rate of the stream in Hertz (samples per second). In cases - where the hardware sample rate is inaccurate and PortAudio is aware of it, - the value of this field may be different from the sampleRate parameter - passed to Pa_OpenStream(). If information about the actual hardware sample - rate is not available, this field will have the same value as the sampleRate - parameter passed to Pa_OpenStream(). - */ - double sampleRate; - -} PaStreamInfo; - - -/** Retrieve a pointer to a PaStreamInfo structure containing information - about the specified stream. - @return A pointer to an immutable PaStreamInfo structure. If the stream - parameter invalid, or an error is encountered, the function returns NULL. - - @param stream A pointer to an open stream previously created with Pa_OpenStream. - - @note PortAudio manages the memory referenced by the returned pointer, - the client must not manipulate or free the memory. The pointer is only - guaranteed to be valid until the specified stream is closed. - - @see PaStreamInfo -*/ -const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); - - -/** Returns the current time in seconds for a stream according to the same clock used - to generate callback PaStreamCallbackTimeInfo timestamps. The time values are - monotonically increasing and have unspecified origin. - - Pa_GetStreamTime returns valid time values for the entire life of the stream, - from when the stream is opened until it is closed. Starting and stopping the stream - does not affect the passage of time returned by Pa_GetStreamTime. - - This time may be used for synchronizing other events to the audio stream, for - example synchronizing audio to MIDI. - - @return The stream's current time in seconds, or 0 if an error occurred. - - @see PaTime, PaStreamCallback, PaStreamCallbackTimeInfo -*/ -PaTime Pa_GetStreamTime( PaStream *stream ); - - -/** Retrieve CPU usage information for the specified stream. - The "CPU Load" is a fraction of total CPU time consumed by a callback stream's - audio processing routines including, but not limited to the client supplied - stream callback. This function does not work with blocking read/write streams. - - This function may be called from the stream callback function or the - application. - - @return - A floating point value, typically between 0.0 and 1.0, where 1.0 indicates - that the stream callback is consuming the maximum number of CPU cycles possible - to maintain real-time operation. A value of 0.5 would imply that PortAudio and - the stream callback was consuming roughly 50% of the available CPU time. The - return value may exceed 1.0. A value of 0.0 will always be returned for a - blocking read/write stream, or if an error occurs. -*/ -double Pa_GetStreamCpuLoad( PaStream* stream ); - - -/** Read samples from an input stream. The function doesn't return until - the entire buffer has been filled - this may involve waiting for the operating - system to supply the data. - - @param stream A pointer to an open stream previously created with Pa_OpenStream. - - @param buffer A pointer to a buffer of sample frames. The buffer contains - samples in the format specified by the inputParameters->sampleFormat field - used to open the stream, and the number of channels specified by - inputParameters->numChannels. If non-interleaved samples were requested using - the paNonInterleaved sample format flag, buffer is a pointer to the first element - of an array of buffer pointers, one non-interleaved buffer for each channel. - - @param frames The number of frames to be read into buffer. This parameter - is not constrained to a specific range, however high performance applications - will want to match this parameter to the framesPerBuffer parameter used - when opening the stream. - - @return On success PaNoError will be returned, or PaInputOverflowed if input - data was discarded by PortAudio after the previous call and before this call. -*/ -PaError Pa_ReadStream( PaStream* stream, - void *buffer, - unsigned long frames ); - - -/** Write samples to an output stream. This function doesn't return until the - entire buffer has been consumed - this may involve waiting for the operating - system to consume the data. - - @param stream A pointer to an open stream previously created with Pa_OpenStream. - - @param buffer A pointer to a buffer of sample frames. The buffer contains - samples in the format specified by the outputParameters->sampleFormat field - used to open the stream, and the number of channels specified by - outputParameters->numChannels. If non-interleaved samples were requested using - the paNonInterleaved sample format flag, buffer is a pointer to the first element - of an array of buffer pointers, one non-interleaved buffer for each channel. - - @param frames The number of frames to be written from buffer. This parameter - is not constrained to a specific range, however high performance applications - will want to match this parameter to the framesPerBuffer parameter used - when opening the stream. - - @return On success PaNoError will be returned, or paOutputUnderflowed if - additional output data was inserted after the previous call and before this - call. -*/ -PaError Pa_WriteStream( PaStream* stream, - const void *buffer, - unsigned long frames ); - - -/** Retrieve the number of frames that can be read from the stream without - waiting. - - @return Returns a non-negative value representing the maximum number of frames - that can be read from the stream without blocking or busy waiting or, a - PaErrorCode (which are always negative) if PortAudio is not initialized or an - error is encountered. -*/ -signed long Pa_GetStreamReadAvailable( PaStream* stream ); - - -/** Retrieve the number of frames that can be written to the stream without - waiting. - - @return Returns a non-negative value representing the maximum number of frames - that can be written to the stream without blocking or busy waiting or, a - PaErrorCode (which are always negative) if PortAudio is not initialized or an - error is encountered. -*/ -signed long Pa_GetStreamWriteAvailable( PaStream* stream ); - - -/* Miscellaneous utilities */ - - -/** Retrieve the size of a given sample format in bytes. - - @return The size in bytes of a single sample in the specified format, - or paSampleFormatNotSupported if the format is not supported. -*/ -PaError Pa_GetSampleSize( PaSampleFormat format ); - - -/** Put the caller to sleep for at least 'msec' milliseconds. This function is - provided only as a convenience for authors of portable code (such as the tests - and examples in the PortAudio distribution.) - - The function may sleep longer than requested so don't rely on this for accurate - musical timing. -*/ -void Pa_Sleep( long msec ); - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* PORTAUDIO_H */ diff --git a/libs/portaudio/license/LICENSE.txt b/libs/portaudio/license/LICENSE.txt deleted file mode 100644 index e0ac4e8a0c0..00000000000 --- a/libs/portaudio/license/LICENSE.txt +++ /dev/null @@ -1,81 +0,0 @@ -Portable header file to contain: ->>>>> -/* - * PortAudio Portable Real-Time Audio Library - * PortAudio API Header File - * Latest version available at: http://www.portaudio.com - * - * Copyright (c) 1999-2006 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ -<<<<< - - -Implementation files to contain: ->>>>> -/* - * PortAudio Portable Real-Time Audio Library - * Latest version at: http://www.portaudio.com - * Implementation - * Copyright (c) 1999-2000 - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ -<<<<< \ No newline at end of file diff --git a/libs/quicktime/lib/win_cb/QTSClient.lib b/libs/quicktime/lib/msys2/QTSClient.lib similarity index 100% rename from libs/quicktime/lib/win_cb/QTSClient.lib rename to libs/quicktime/lib/msys2/QTSClient.lib diff --git a/libs/quicktime/lib/win_cb/Rave.lib b/libs/quicktime/lib/msys2/Rave.lib similarity index 100% rename from libs/quicktime/lib/win_cb/Rave.lib rename to libs/quicktime/lib/msys2/Rave.lib diff --git a/export/win_cb/qtmlClient.dll b/libs/quicktime/lib/msys2/qtmlClient.dll similarity index 100% rename from export/win_cb/qtmlClient.dll rename to libs/quicktime/lib/msys2/qtmlClient.dll diff --git a/libs/quicktime/lib/win_cb/qtmlClient.lib b/libs/quicktime/lib/msys2/qtmlClient.lib similarity index 100% rename from libs/quicktime/lib/win_cb/qtmlClient.lib rename to libs/quicktime/lib/msys2/qtmlClient.lib diff --git a/libs/quicktime/lib/win_cb/qtmlClient.dll b/libs/quicktime/lib/win_cb/qtmlClient.dll deleted file mode 100644 index d776a1ea7c4..00000000000 Binary files a/libs/quicktime/lib/win_cb/qtmlClient.dll and /dev/null differ diff --git a/libs/rtAudio/lib/msys2/librtaudio.a b/libs/rtAudio/lib/msys2/librtaudio.a new file mode 100644 index 00000000000..4ebdf182341 Binary files /dev/null and b/libs/rtAudio/lib/msys2/librtaudio.a differ diff --git a/libs/rtAudio/lib/win_cb/librtaudio.a b/libs/rtAudio/lib/win_cb/librtaudio.a deleted file mode 100644 index c3db03c737f..00000000000 Binary files a/libs/rtAudio/lib/win_cb/librtaudio.a and /dev/null differ diff --git a/libs/tess2/include/tesselator.h b/libs/tess2/include/tesselator.h index eafb0aa3579..ee75ee42c42 100644 --- a/libs/tess2/include/tesselator.h +++ b/libs/tess2/include/tesselator.h @@ -37,7 +37,7 @@ extern "C" { #endif #if defined( __APPLE_CC__) - #include + #include #endif // See OpenGL Red Book for description of the winding rules @@ -120,9 +120,9 @@ enum TessElementType typedef float TESSreal; #if TARGET_OS_IPHONE || ANDROID || __ARMEL__ || EMSCRIPTEN - typedef unsigned short TESSindex; + typedef unsigned short TESSindex; #else - typedef unsigned int TESSindex; + typedef unsigned int TESSindex; #endif typedef struct TESStesselator TESStesselator; typedef struct TESSalloc TESSalloc; diff --git a/libs/tess2/lib/emscripten/libtess2.a b/libs/tess2/lib/emscripten/libtess2.a index bf38a01d6aa..09f8e442f29 100644 Binary files a/libs/tess2/lib/emscripten/libtess2.a and b/libs/tess2/lib/emscripten/libtess2.a differ diff --git a/libs/tess2/lib/msys2/libtess2.a b/libs/tess2/lib/msys2/libtess2.a new file mode 100644 index 00000000000..f64670b9641 Binary files /dev/null and b/libs/tess2/lib/msys2/libtess2.a differ diff --git a/libs/tess2/lib/vs/Win32/tess2.lib b/libs/tess2/lib/vs/Win32/tess2.lib index d1caf835006..0d75d82ca40 100644 Binary files a/libs/tess2/lib/vs/Win32/tess2.lib and b/libs/tess2/lib/vs/Win32/tess2.lib differ diff --git a/libs/tess2/lib/vs/x64/tess2.lib b/libs/tess2/lib/vs/x64/tess2.lib index ce3bcce7df9..8efece60c88 100644 Binary files a/libs/tess2/lib/vs/x64/tess2.lib and b/libs/tess2/lib/vs/x64/tess2.lib differ diff --git a/libs/tess2/lib/win_cb/libtess2.a b/libs/tess2/lib/win_cb/libtess2.a deleted file mode 100644 index 7a02350dd5f..00000000000 Binary files a/libs/tess2/lib/win_cb/libtess2.a and /dev/null differ diff --git a/libs/videoInput/lib/msys2/libvideoinput.a b/libs/videoInput/lib/msys2/libvideoinput.a new file mode 100644 index 00000000000..0055e9b42a9 Binary files /dev/null and b/libs/videoInput/lib/msys2/libvideoinput.a differ diff --git a/libs/videoInput/lib/win_cb/videoInputLib.a b/libs/videoInput/lib/win_cb/videoInputLib.a deleted file mode 100644 index c127fbf5985..00000000000 Binary files a/libs/videoInput/lib/win_cb/videoInputLib.a and /dev/null differ diff --git a/scripts/android/buildAllExamples.sh b/scripts/android/buildAllExamples.sh new file mode 100755 index 00000000000..8a7f056e62b --- /dev/null +++ b/scripts/android/buildAllExamples.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# +# This script requires following: +# - ANDROID_HOME should be set +# export ANDROID_HOME=~/Library/Android/sdk/platforms/ +# - tools and platform-tools should be added to PATH +# export PATH=$PATH:~/Library/Android/sdk/platform-tools/ +# export PATH=$PATH:~/Library/Android/sdk/tools/ + +for category in $( find ../../examples -maxdepth 1 -type d ) +do + if [ "$category" = "../../examples/android" ]; then + echo "-----------------------------------------------------------------" + echo building ALL android examples in $category + + for example in $( find $category -maxdepth 1 -type d ) + do + if [ "$example" = "$category" ]; then + continue + fi + + + if [ ! -e "$example"/build.gradle ]; then + echo "-----------------------------------------------------------------" + echo no gradle project for $example + continue + fi + + echo "-----------------------------------------------------------------" + echo Updating android project + android update project -p $example + if [ $? -ne 0 ]; then + echo failed updating android project $example + exit + fi + + echo building $example + (cd $example; gradle assembleDebug ) + if [ $? -ne 0 ]; then + echo failed building $example Debug + exit + fi + done + fi + +done diff --git a/scripts/android/install_tests_env.sh b/scripts/android/install_tests_env.sh deleted file mode 100755 index 52f57c11cb8..00000000000 --- a/scripts/android/install_tests_env.sh +++ /dev/null @@ -1,5 +0,0 @@ -curl -Lk http://dl.google.com/android/ndk/android-ndk-r10e-darwin-x86_64.bin -o ndk.bin -chmod a+x ndk.bin -./ndk.bin -y | grep -v Extracting -NDK_ROOT=$(echo ${PWD} | sed "s/\//\\\\\//g") -cat libs/openFrameworksCompiled/project/android/paths.default.make | sed s/path_to/${NDK_ROOT}/ > libs/openFrameworksCompiled/project/android/paths.make diff --git a/scripts/android/runAllExamples.sh b/scripts/android/runAllExamples.sh new file mode 100755 index 00000000000..04f6e9adfb6 --- /dev/null +++ b/scripts/android/runAllExamples.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# This script requires following: +# - ANDROID_HOME should be set +# export ANDROID_HOME=~/Library/Android/sdk/platforms/ +# - tools and platform-tools should be added to PATH +# export PATH=$PATH:~/Library/Android/sdk/platform-tools/ +# export PATH=$PATH:~/Library/Android/sdk/tools/ + +for category in $( find ../../examples -maxdepth 1 -type d ) +do + if [ "$category" = "../../examples/android" ]; then + echo "-----------------------------------------------------------------" + echo running ALL android examples in $category + + for example in $( find $category -maxdepth 1 -type d ) + do + if [ "$example" = "$category" ]; then + continue + fi + + exampleName=$(basename "$example") + + if [ ! -e "$example"/build/outputs/apk ]; then + echo "-----------------------------------------------------------------" + echo no apk output folder for $example + continue + fi + + echo Installing $exampleName + adb install "$example"/build/outputs/apk/"$exampleName"-debug.apk + echo Starting $exampleName + adb shell am start -a android.intent.action.MAIN -n cc.openframeworks."$exampleName"/.OFActivity + + echo + echo + read -p "$exampleName started! Press [Enter] key to start next example..." + + adb shell am force-stop cc.openframeworks."$exampleName" + + done + fi + +done diff --git a/scripts/android/testTemplate.sh b/scripts/android/testTemplate.sh deleted file mode 100755 index a681bcc6cad..00000000000 --- a/scripts/android/testTemplate.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -e -cd $OF_ROOT -cd examples/android/androidEmptyExample -echo "ABIS_TO_COMPILE_DEBUG = $1" >> config.make -make Debug PLATFORM_OS=Android diff --git a/scripts/apothecary/PROGRESS.md b/scripts/apothecary/PROGRESS.md index eb010dae6f3..3ec6a12d953 100644 --- a/scripts/apothecary/PROGRESS.md +++ b/scripts/apothecary/PROGRESS.md @@ -8,7 +8,7 @@ | ✓C | copy only, written & tested | N/A | not applicable -| Lib | osx | linux | linux64 | linuxarmv6l | linuxarmv7l | vs | win_cb | ios | android | +| Lib | osx | linux | linux64 | linuxarmv6l | linuxarmv7l | vs | msys2 | ios | android | |---------------------------------|-----|-------|---------|-------------|-------------|----|--------|-----|---------| | FreeImage | ✓ | N/A | N/A | N/A | N/A | ✗ | ✗ | ✓ | ✗ | | FreeType | ✓ | N/A | N/A | N/A | N/A | ? | ? | ✓ | ? | diff --git a/scripts/apothecary/README.md b/scripts/apothecary/README.md index 262ca99238e..9d6f9bb3b0f 100644 --- a/scripts/apothecary/README.md +++ b/scripts/apothecary/README.md @@ -78,7 +78,7 @@ See the built in help for more info: ### Options * **-t**: specify libary type when building, detects type from OS by default - * valid types: osx, osx-clang-libc++, linux, linux64, vs, win_cb, ios, android + * valid types: osx, osx-clang-libc++, linux, linux64, vs, msys2, ios, android * **-a**: specify architecture, either 32 or 64 (default is 32 bit) * note: not currently needed, reserved for future use @@ -198,7 +198,7 @@ OpenFrameworks is cross platform and currently supports the following build type * linux: 32 bit linux * linux64: 64 bit linux * vs: Windows, Visual Studio -* win_cb: Windows, CodeBlocks+MinGW +* msys2: Windows, Msys2 (Mingw32 only) * ios: iOS (can only build on OSX), arm7, arm7s, & 32 bit simulator fat libs * android: (requires android sdk) @@ -471,8 +471,8 @@ Bash provides an easy way to debug scripts by `set -x`. Put this command in your If you write a formula but can't finish/test it on all platforms, etc make a note of this using the `echoWarning` print command. This is a function provided by apothecary that prints text in yellow (caution, right?). Start your info string with with "TODO: ": - if [ "$TYPE" == "win_cb" ] then ; - echoWarning "TODO: build win_cb" + if [ "$TYPE" == "msys2" ] then ; + echoWarning "TODO: build msys2" else ... diff --git a/scripts/apothecary/android_configure.sh b/scripts/apothecary/android_configure.sh index d955c4fb94c..7ed977c7366 100755 --- a/scripts/apothecary/android_configure.sh +++ b/scripts/apothecary/android_configure.sh @@ -1,7 +1,11 @@ export ABI=$1 +if [ "$(uname)" == "Darwin" ]; then + export HOST_PLATFORM=darwin-x86_64 +else + export HOST_PLATFORM=linux-x86_64 +fi export LIBSPATH=android/$ABI -export NDK_PLATFORM=android-21 -export HOST_PLATFORM=linux-x86_64 +export NDK_PLATFORM=$ANDROID_PLATFORM export TOOLCHAIN_VERSION=4.9 if [ $ABI = armeabi-v7a ] || [ $ABI = armeabi ]; then export SYSROOT=${NDK_ROOT}/platforms/${NDK_PLATFORM}/arch-arm diff --git a/scripts/apothecary/apothecary b/scripts/apothecary/apothecary index 05c1311616d..c91d228a67c 100755 --- a/scripts/apothecary/apothecary +++ b/scripts/apothecary/apothecary @@ -47,7 +47,7 @@ TYPE= # library build type ("osx", "ios", "vs", etc) ARCH=32 # library build arch, 32 or 64 bit (not used for some build types) # full path to this script's dir -APOTHECARY_DIR=. +APOTHECARY_DIR=$(pwd) # full path to the dir of the current formula FORMULA_DIR= @@ -65,19 +65,19 @@ PARALLEL_MAKE=1 ### Xcode/ios specific settings # xcode Developer root -if [ "$(./ostype.sh)" == "osx" ]; then +if [ "$(${APOTHECARY_DIR}/ostype.sh)" == "osx" ]; then XS="xcode-select -print-path" # stupid hack to keep my syntax highlighting from breaking :P XCODE_DEV_ROOT= # used when building some libs for osx OSX_LATEST_SDK="xcrun -sdk macosx --show-sdk-version" - OSX_SDK_VER=10.10 + OSX_SDK_VER=10.11 OSX_MIN_SDK_VER=10.7 # used when building for ios, the sdks you have installed are found in: # $XCODE_DEV_ROOT/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator#.#.sdk IOS_LATEST_SDK="xcrun -sdk iphoneos --show-sdk-version" # stupid hack to keep my syntax highlighting from breaking :P - IOS_SDK_VER=8.1 + IOS_SDK_VER=9.1 IOS_MIN_SDK_VER=5.1 fi @@ -88,7 +88,7 @@ VS_64_BIT_ENV='VC\bin\x86_amd64\vcvarsx86_amd64.bat' # paths to android SDK, etc ANDROID_NDK_ROOT= ANDROID_SDK_ROOT= -ANDROID_PLATFORM=android-21 +ANDROID_PLATFORM=android-19 ################################################################################ ### PRIVATE VARS, for internal use @@ -108,6 +108,7 @@ REL_FORMULAS_DIR=formulas REL_BUILD_DIR=build REL_LIBS_DIR=../../libs REL_ADDONS_DIR=../../addons +CHECKOUT=YES # ansi console escape codes CON_DEFAULT="\033[0m" @@ -117,7 +118,7 @@ CON_YELLOW="\033[33m" CON_GREEN="\033[32m" # used to filter out bad build types -VALID_TYPES=( "osx" "linux" "linux64" "linuxarmv6l" "linuxarmv7l" "vs" "win_cb" "ios" "android" "emscripten" ) +VALID_TYPES=( "osx" "linux" "linux64" "linuxarmv6l" "linuxarmv7l" "vs" "msys2" "ios" "tvos" "android" "emscripten" ) # verbose mode bool A_VERBOSE=0 @@ -152,7 +153,7 @@ commands: options: -t specify libary type when building, detects type from OS by default - valid types: osx, linux, linux64, linuxarmv6l, linuxarmv7l, vs, win_cb, ios, android + valid types: osx, linux, linux64, linuxarmv6l, linuxarmv7l, vs, msys2, ios, tvos, android -a specify architecture, either 32 or 64 (default is 32 bit) note: not currently needed, reserved for future use @@ -898,10 +899,50 @@ function apothecaryDepend() { function apothecaryDependencies() { if [ ${#FORMULA_DEPENDS[@]} -gt 0 ] ; then for depend in "${FORMULA_DEPENDS[@]}" ; do - apothecaryDepend $1 $depend + + #store where we are + CUR_DIR=$(pwd) + + #change back to APOTHECARY_DIR to run new script + cd $APOTHECARY_DIR + apothecaryDepend $1 $depend + + #restore dir to where we are + cd $CUR_DIR done + + #also have to cd back to the APOTHECARY_DIR for the next commands to work + cd $APOTHECARY_DIR + fi +} + +function dump_output() { + if [ -z "$BUILD_OUTPUT" ]; then + echo "BUILD_OUTPUT not set." + else + echo Tailing the last 500 lines of output: + tail -500 "$BUILD_OUTPUT" fi } +function error_handler() { + + + echo ERROR: An error was encountered with the build. + dump_output + # nicely terminate the ping output loop + if [ -z "$PING_LOOP_PID" ]; then + echo "Loop PID not set." + else + kill $PING_LOOP_PID || true + fi + + JOB="$0" # job name + LASTLINE="$1" # line of error occurrence + LASTERR="$2" # error code + echo "ERROR in ${JOB} : line ${LASTLINE} with exit code ${LASTERR}" + + exit "${LASTERR}" +} ################################################################################ ### GO diff --git a/scripts/apothecary/doc/formula_template.sh b/scripts/apothecary/doc/formula_template.sh index e2122e32e3d..e7e569b5203 100644 --- a/scripts/apothecary/doc/formula_template.sh +++ b/scripts/apothecary/doc/formula_template.sh @@ -8,7 +8,7 @@ # array of build types supported by this formula # you can delete this to implicitly support *all* types -FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "win_cb" "ios" "android" ) +FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "msys2" "ios" "android" ) # define the version VER=#.#.# diff --git a/scripts/apothecary/formulas/FreeImage/FreeImage.sh b/scripts/apothecary/formulas/FreeImage/FreeImage.sh index 3345aa6d723..3055ffac7c5 100644 --- a/scripts/apothecary/formulas/FreeImage/FreeImage.sh +++ b/scripts/apothecary/formulas/FreeImage/FreeImage.sh @@ -7,7 +7,7 @@ # Makefile build system, # some Makefiles are out of date so patching/modification may be required -FORMULA_TYPES=( "osx" "vs" "win_cb" "ios" "android" "emscripten") +FORMULA_TYPES=( "osx" "vs" "msys2" "ios" "tvos" "android" "emscripten") # define the version VER=3170 # 3.16.0 @@ -19,12 +19,12 @@ GIT_TAG=3.17.0 # download the source code and unpack it into LIB_NAME function download() { - if [ "$TYPE" == "vs" -o "$TYPE" == "win_cb" ] ; then + if [ "$TYPE" == "vs" -o "$TYPE" == "msys2" ] ; then # For win32, we simply download the pre-compiled binaries. curl -LO http://downloads.sourceforge.net/freeimage/FreeImage"$VER"Win32Win64.zip unzip -qo FreeImage"$VER"Win32Win64.zip rm FreeImage"$VER"Win32Win64.zip - elif [[ "${TYPE}" == "osx" || "${TYPE}" == "ios" ]]; then + elif [[ "${TYPE}" == "osx" || "${TYPE}" == "ios" || "${TYPE}" == "tvos" ]]; then # Fixed issues for OSX / iOS for FreeImage compiling in git repo. echo "Downloading from $GIT_URL for OSX/iOS" echo $GIT_URL @@ -50,7 +50,7 @@ function prepare() { sed -i tmp "s|MACOSX_SDK =.*|MACOSX_SDK = $OSX_SDK_VER|" Makefile.osx sed -i tmp "s|MACOSX_MIN_SDK =.*|MACOSX_MIN_SDK = $OSX_MIN_SDK_VER|" Makefile.osx - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then mkdir -p Dist/$TYPE mkdir -p builddir/$TYPE @@ -101,18 +101,31 @@ function build() { strip -x Dist/libfreeimage.a - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then # Notes: # --- for 3.1+ Must use "-DNO_LCMS -D__ANSI__ -DDISABLE_PERF_MEASUREMENT" to compile LibJXR export TOOLCHAIN=$XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain export TARGET_IOS - local IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="x86_64 arm64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi + local STDLIB="libc++" local CURRENTPATH=`pwd` - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi + + DEVELOPER=$XCODE_DEV_ROOT TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER @@ -147,10 +160,17 @@ function build() { export EXTRA_PLATFORM_LDFLAGS="" if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" - + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + fi else - PLATFORM="iPhoneOS" + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + fi fi export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" @@ -163,14 +183,27 @@ function build() { if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors - fi - - MIN_TYPE=-miphoneos-version-min= - if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_TYPE=-mios-simulator-version-min= + MIN_IOS_VERSION=7.0 # 6.0 to prevent start linking errors fi + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + fi + export TARGET_NAME="$CURRENTPATH/libfreeimage-$IOS_ARCH.a" export HEADER="Source/FreeImage.h" @@ -186,12 +219,11 @@ function build() { export RANLIB=$TOOLCHAIN/usr/bin/ranlib export LIBTOOL=$TOOLCHAIN/usr/bin/libtool - export EXTRA_PLATFORM_CFLAGS="$EXTRA_PLATFORM_CFLAGS" export EXTRA_PLATFORM_LDFLAGS="$EXTRA_PLATFORM_LDFLAGS -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -Wl,-dead_strip -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/ $MIN_TYPE$MIN_IOS_VERSION " - EXTRA_LINK_FLAGS="-arch $IOS_ARCH -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wno-shorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -DHAVE_UNISTD_H=1 -DOPJ_STATIC -DNO_LCMS -D__ANSI__ -DDISABLE_PERF_MEASUREMENT -DLIBRAW_NODLL -DLIBRAW_LIBRARY_BUILD -DFREEIMAGE_LIB -fexceptions -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Wmost -Wno-four-char-constants -Wno-unknown-pragmas -DNDEBUG -fPIC -fexceptions -fvisibility=hidden" - EXTRA_FLAGS="$EXTRA_LINK_FLAGS -DNDEBUG -ffast-math -DPNG_ARM_NEON_OPT=0 -DDISABLE_PERF_MEASUREMENT $MIN_TYPE$MIN_IOS_VERSION -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/" + EXTRA_LINK_FLAGS="-arch $IOS_ARCH $BITCODE -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wno-shorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -DHAVE_UNISTD_H=1 -DOPJ_STATIC -DNO_LCMS -D__ANSI__ -DDISABLE_PERF_MEASUREMENT -DLIBRAW_NODLL -DLIBRAW_LIBRARY_BUILD -DFREEIMAGE_LIB -fexceptions -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Wmost -Wno-four-char-constants -Wno-unknown-pragmas -DNDEBUG -fPIC -fexceptions -fvisibility=hidden" + EXTRA_FLAGS="$EXTRA_LINK_FLAGS $BITCODE -DNDEBUG -ffast-math -DPNG_ARM_NEON_OPT=0 -DDISABLE_PERF_MEASUREMENT $MIN_TYPE$MIN_IOS_VERSION -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/" export CC="$CC $EXTRA_FLAGS" export CFLAGS="-arch $IOS_ARCH $EXTRA_FLAGS" @@ -243,12 +275,18 @@ function build() { # link into universal lib echo "Running lipo to create fat lib" echo "Please stand by..." - # libfreeimage-armv7s.a \ - lipo -create libfreeimage-armv7.a \ + if [[ "${TYPE}" == "tvos" ]] ; then + lipo -create libfreeimage-arm64.a \ + libfreeimage-x86_64.a \ + -output freeimage.a >> "${LOG}" 2>&1 + elif [[ "$TYPE" == "ios" ]]; then + # libfreeimage-armv7s.a \ + lipo -create libfreeimage-armv7.a \ libfreeimage-arm64.a \ libfreeimage-i386.a \ libfreeimage-x86_64.a \ -output freeimage.a >> "${LOG}" 2>&1 + fi if [ $? != 0 ]; then @@ -260,19 +298,22 @@ function build() { fi lipo -info freeimage.a - echo "--------------------" - echo "Stripping any lingering symbols" - echo "Please stand by..." - # validate all stripped debug: - strip -x freeimage.a >> "${LOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 10 "${LOG}" - echo "Problem while stripping lib - Please check ${LOG}" - exit 1 - else - echo "Strip Successful for ${LOG}" - fi + + if [[ "$TYPE" == "ios" ]]; then + echo "--------------------" + echo "Stripping any lingering symbols" + echo "Please stand by..." + # validate all stripped debug: + strip -x freeimage.a >> "${LOG}" 2>&1 + if [ $? != 0 ]; + then + tail -n 10 "${LOG}" + echo "Problem while stripping lib - Please check ${LOG}" + exit 1 + else + echo "Strip Successful for ${LOG}" + fi + fi cd ../../ echo "--------------------" @@ -352,7 +393,7 @@ function copy() { cp -v Dist/*.h $1/include mkdir -p $1/lib/$TYPE cp -v Dist/libfreeimage.a $1/lib/$TYPE/freeimage.a - elif [ "$TYPE" == "vs" -o "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "vs" -o "$TYPE" == "msys2" ] ; then mkdir -p $1/include #/Win32 #mkdir -p $1/include/x64 cp -v Dist/x32/*.h $1/include #/Win32/ @@ -363,7 +404,7 @@ function copy() { cp -v Dist/x32/FreeImage.dll $1/../../export/$TYPE/FreeImage32.dll cp -v Dist/x64/FreeImage.lib $1/lib/$TYPE/x64/FreeImage.lib cp -v Dist/x64/FreeImage.dll $1/../../export/$TYPE/FreeImage64.dll - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then cp -v Dist/*.h $1/include if [ -d $1/lib/$TYPE/ ]; then rm -r $1/lib/$TYPE/ @@ -414,7 +455,7 @@ function clean() { rm -f builddir/$TYPE rm -f builddir rm -f lib - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then # clean up compiled libraries make clean rm -rf Dist diff --git a/scripts/apothecary/formulas/boost/boost.sh b/scripts/apothecary/formulas/boost/boost.sh index 004590c1abe..b6cb99d67a5 100644 --- a/scripts/apothecary/formulas/boost/boost.sh +++ b/scripts/apothecary/formulas/boost/boost.sh @@ -5,7 +5,7 @@ # # uses a own build system -FORMULA_TYPES=( "osx" "win_cb" "ios" "android" "emscripten" "vs" ) +FORMULA_TYPES=( "osx" "msys2" "ios" "tvos" "android" "emscripten" "vs" ) # define the version VERSION=1.58.0 @@ -25,21 +25,39 @@ function download() { mv boost_${VERSION_UNDERSCORES} boost rm ${TARBALL} - if [ "$TYPE" == "ios" ]; then + if [ "$VERSION" == "1.58.0" ]; then + cp -v boost/boost/config/compiler/visualc.hpp boost/boost/config/compiler/visualc.hpp.orig # back this up as we manually patch it + cp -v boost/libs/filesystem/src/operations.cpp boost/libs/filesystem/src/operations.cpp.orig # back this up as we manually patch it + fi + + if [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]]; then cp -v boost/tools/build/example/user-config.jam boost/tools/build/example/user-config.jam.orig # back this up as we manually patch it fi } # prepare the build environment, executed inside the lib src dir function prepare() { + if [ "$VERSION" == "1.58.0" ]; then + if patch -p0 -u -N --dry-run --silent < $FORMULA_DIR/operations.cpp.patch_1.58 2>/dev/null ; then + patch -p0 -u < $FORMULA_DIR/operations.cpp.patch_1.58 + fi + + if patch -p0 -u -N --dry-run --silent < $FORMULA_DIR/visualc.hpp.patch_1.58 2>/dev/null ; then + patch -p0 -u < $FORMULA_DIR/visualc.hpp.patch_1.58 + fi + fi + if [ "$TYPE" == "osx" ] || [ "$TYPE" == "emscripten" ]; then ./bootstrap.sh --with-toolset=clang --with-libraries=filesystem - elif [ "$TYPE" == "ios" ]; then + elif [[ "${TYPE}" == "ios" || "${TYPE}" == "tvos" ]]; then mkdir -p lib/ mkdir -p build/ - IPHONE_SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + SDKVERSION="" + + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + cp -v tools/build/example/user-config.jam.orig tools/build/example/user-config.jam - cp $XCODE_DEV_ROOT/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IPHONE_SDKVERSION}.sdk/usr/include/{crt_externs,bzlib}.h . + cp $XCODE_DEV_ROOT/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDKVERSION}.sdk/usr/include/{crt_externs,bzlib}.h . BOOST_LIBS_COMMA=$(echo $BOOST_LIBS | sed -e "s/ /,/g") echo "Bootstrapping (with libs $BOOST_LIBS_COMMA)" ./bootstrap.sh --with-libraries=$BOOST_LIBS_COMMA @@ -67,12 +85,26 @@ function build() { elif [ "$TYPE" == "osx" ]; then - ./b2 -j${PARALLEL_MAKE} toolset=clang cxxflags="-std=c++11 -stdlib=libc++ -arch i386 -arch x86_64" linkflags="-stdlib=libc++" threading=multi variant=release --build-dir=build --stage-dir=stage link=static stage + ./b2 -j${PARALLEL_MAKE} toolset=clang cxxflags="-std=c++11 -stdlib=libc++ -arch i386 -arch x86_64 -mmacosx-version-min=${OSX_MIN_SDK_VER}" linkflags="-stdlib=libc++" threading=multi variant=release --build-dir=build --stage-dir=stage link=static stage cd tools/bcp ../../b2 - elif [ "$TYPE" == "ios" ]; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]]; then # set some initial variables - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="x86_64 arm64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi + + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi + set -e CURRENTPATH=`pwd` ARM_DEV_CMD="xcrun --sdk iphoneos" @@ -96,7 +128,7 @@ function build() { ;; esac # Set some locations and variables - IPHONE_SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + IPHONE_SDKVERSION="$SDKVERSION" SRCDIR=`pwd`/build/src IOSBUILDDIR=`pwd`/build/libs/boost/lib IOSINCLUDEDIR=`pwd`/build/libs/boost/include/boost @@ -104,31 +136,55 @@ function build() { OUTPUT_DIR_LIB=`pwd`/lib/boost/ios OUTPUT_DIR_SRC=`pwd`/lib/boost/include/boost BOOST_SRC=$CURRENTPATH - local CROSS_TOP_IOS="${DEVELOPER}/Platforms/iPhoneOS.platform/Developer" - local CROSS_SDK_IOS="iPhoneOS${SDKVERSION}.sdk" - local CROSS_TOP_SIM="${DEVELOPER}/Platforms/iPhoneSimulator.platform/Developer" - local CROSS_SDK_SIM="iPhoneSimulator${SDKVERSION}.sdk" + BITCODE="" + MIN_IOS_VERSION=$IOS_MIN_SDK_VER + if [ "${TYPE}" == "tvos" ]; then + local CROSS_TOP_IOS="${DEVELOPER}/Platforms/AppleTVOS.platform/Developer" + local CROSS_SDK_IOS="AppleTVOS${SDKVERSION}.sdk" + local CROSS_TOP_SIM="${DEVELOPER}/Platforms/AppleTVSimulator.platform/Developer" + local CROSS_SDK_SIM="AppleTVSimulator${SDKVERSION}.sdk" + local TARGET_OS="iphone" + local ARCH="-arch arm64" + local ARCHSIM="-arch x86_64" + local TARGET_TYPE="iphone" + local TARGET_TYPE_SIM="iphonesim" + MIN_TYPE=-mtvos-version-min= + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + elif [ "$TYPE" == "ios" ]; then + local CROSS_TOP_IOS="${DEVELOPER}/Platforms/iPhoneOS.platform/Developer" + local CROSS_SDK_IOS="iPhoneOS${SDKVERSION}.sdk" + local CROSS_TOP_SIM="${DEVELOPER}/Platforms/iPhoneSimulator.platform/Developer" + local CROSS_SDK_SIM="iPhoneSimulator${SDKVERSION}.sdk" + local TARGET_OS="iphone" + local ARCH="-arch armv7 -arch arm64" + local ARCHSIM="-arch i386 -arch x86_64" + local TARGET_TYPE="iphone" + local TARGET_TYPE_SIM="iphonesim" + MIN_TYPE=-miphoneos-version-min= + fi + local BUILD_TOOLS="${DEVELOPER}" # Patch the user-config file -- Add some dynamic flags cat >> tools/build/example/user-config.jam < $XCODE_DEV_ROOT/Platforms/iPhoneOS.platform/Developer -: arm iphone +using darwin : ${IPHONE_SDKVERSION}~$TARGET_TYPE +: $XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ $ARCH $EXTRA_CPPFLAGS $BITCODE "-isysroot ${CROSS_TOP_IOS}/SDKs/${CROSS_SDK_IOS}" -I${CROSS_TOP_IOS}/SDKs/${CROSS_SDK_IOS}/usr/include/ +: $CROSS_TOP_IOS +: arm $TARGET_OS ; -using darwin : ${IPHONE_SDKVERSION}~iphonesim -: $XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -arch i386 -arch x86_64 $EXTRA_CPPFLAGS "-isysroot ${CROSS_TOP_SIM}/SDKs/${CROSS_SDK_SIM}" -I${CROSS_TOP_SIM}/SDKs/${CROSS_SDK_SIM}/usr/include/ -: $XCODE_DEV_ROOT/Platforms/iPhoneSimulator.platform/Developer -: x86 iphone +using darwin : ${IPHONE_SDKVERSION}~$TARGET_TYPE_SIM +: $XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ $ARCHSIM $EXTRA_CPPFLAGS $BITCODE "-isysroot ${CROSS_TOP_SIM}/SDKs/${CROSS_SDK_SIM}" -I${CROSS_TOP_SIM}/SDKs/${CROSS_SDK_SIM}/usr/include/ +: $CROSS_TOP_SIM +: x86 $TARGET_OS ; EOF # Build the Library with ./b2 /bjam echo "Boost iOS Device Staging" - ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~iphone cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" --build-dir=iphone-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphone-build/stage --prefix=$PREFIXDIR architecture=arm target-os=iphone macosx-version=iphone-${IPHONE_SDKVERSION} define=_LITTLE_ENDIAN link=static stage + ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~$TARGET_TYPE cxxflags="-stdlib=libc++ $MIN_TYPE$MIN_IOS_VERSION $BITCODE" linkflags="-stdlib=libc++" --build-dir=iphone-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphone-build/stage --prefix=$PREFIXDIR architecture=arm target-os=iphone define=_LITTLE_ENDIAN link=static stage echo "Boost iOS Device Install" - ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~iphone cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" --build-dir=iphone-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphone-build/stage --prefix=$PREFIXDIR architecture=arm target-os=iphone macosx-version=iphone-${IPHONE_SDKVERSION} define=_LITTLE_ENDIAN link=static install + ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~$TARGET_TYPE cxxflags="-stdlib=libc++ $MIN_TYPE$MIN_IOS_VERSION $BITCODE" linkflags="-stdlib=libc++" --build-dir=iphone-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphone-build/stage --prefix=$PREFIXDIR architecture=arm target-os=iphone define=_LITTLE_ENDIAN link=static install echo "Boost iOS Simulator Install" - ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~iphonesim cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" --build-dir=iphonesim-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphonesim-build/stage architecture=x86 target-os=iphone macosx-version=iphonesim-${IPHONE_SDKVERSION} link=static stage + ./b2 -j${PARALLEL_MAKE} --toolset=darwin-${IPHONE_SDKVERSION}~$TARGET_TYPE_SIM cxxflags="-stdlib=libc++ $MIN_TYPE$MIN_IOS_VERSION $BITCODE" linkflags="-stdlib=libc++" --build-dir=iphonesim-build variant=release -sBOOST_BUILD_USER_CONFIG=$BOOST_SRC/tools/build/example/user-config.jam --stagedir=iphonesim-build/stage architecture=x86 target-os=iphone link=static stage mkdir -p $OUTPUT_DIR_LIB mkdir -p $OUTPUT_DIR_SRC mkdir -p $IOSBUILDDIR/armv7/ $IOSBUILDDIR/arm64/ $IOSBUILDDIR/i386/ $IOSBUILDDIR/x86_64/ @@ -137,9 +193,11 @@ EOF for NAME in $BOOST_LIBS; do ALL_LIBS="$ALL_LIBS $NAME" echo "Splitting '$NAME' to $IOSBUILDDIR/*/$NAME.a" - $ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin armv7 -o $IOSBUILDDIR/armv7/$NAME.a + if [[ "$TYPE" == "ios" ]]; then + $ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin armv7 -o $IOSBUILDDIR/armv7/$NAME.a + $ARM_DEV_CMD lipo "iphonesim-build/stage/lib/libboost_$NAME.a" -thin i386 -o $IOSBUILDDIR/i386/$NAME.a + fi $ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin arm64 -o $IOSBUILDDIR/arm64/$NAME.a - $ARM_DEV_CMD lipo "iphonesim-build/stage/lib/libboost_$NAME.a" -thin i386 -o $IOSBUILDDIR/i386/$NAME.a $ARM_DEV_CMD lipo "iphonesim-build/stage/lib/libboost_$NAME.a" -thin x86_64 -o $IOSBUILDDIR/x86_64/$NAME.a done echo "done" @@ -151,40 +209,57 @@ EOF mkdir -p $IOSBUILDDIR/i386/$NAME-obj mkdir -p $IOSBUILDDIR/x86_64/$NAME-obj echo Decomposing $NAME ... - (cd $IOSBUILDDIR/armv7/$NAME-obj; ar -x ../$NAME.a; ); + if [[ "$TYPE" == "ios" ]]; then + (cd $IOSBUILDDIR/armv7/$NAME-obj; ar -x ../$NAME.a; ); + (cd $IOSBUILDDIR/i386/$NAME-obj; ar -x ../$NAME.a; ); + fi (cd $IOSBUILDDIR/arm64/$NAME-obj; ar -x ../$NAME.a; ); - (cd $IOSBUILDDIR/i386/$NAME-obj; ar -x ../$NAME.a; ); (cd $IOSBUILDDIR/x86_64/$NAME-obj; ar -x ../$NAME.a; ); done echo "done" echo "---------------" # remove broken symbol file (empty symbol) + if [[ "$TYPE" == "ios" ]]; then + rm $IOSBUILDDIR/armv7/filesystem-obj/windows_file_codecvt.o; + rm $IOSBUILDDIR/i386/filesystem-obj/windows_file_codecvt.o; + fi rm $IOSBUILDDIR/arm64/filesystem-obj/windows_file_codecvt.o; - rm $IOSBUILDDIR/armv7/filesystem-obj/windows_file_codecvt.o; - rm $IOSBUILDDIR/i386/filesystem-obj/windows_file_codecvt.o; rm $IOSBUILDDIR/x86_64/filesystem-obj/windows_file_codecvt.o; echo "Re-forging architecture's .a files" for NAME in $ALL_LIBS; do echo ar crus $NAME ... - (cd $IOSBUILDDIR/armv7; $ARM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) + if [[ "$TYPE" == "ios" ]]; then + (cd $IOSBUILDDIR/i386; $SIM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) + (cd $IOSBUILDDIR/armv7; $ARM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) + fi (cd $IOSBUILDDIR/arm64; $ARM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) - (cd $IOSBUILDDIR/i386; $SIM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) (cd $IOSBUILDDIR/x86_64; $SIM_DEV_CMD ar crus re-$NAME.a $NAME-obj/*.o; ) done echo "done" echo "---------------" echo "Decomposing each architecture's .a files" for NAME in $ALL_LIBS; do - echo "Lipo -c for $NAME for all iOS Architectures (arm64, armv7, i386, x86_64)" - lipo -c $IOSBUILDDIR/armv7/re-$NAME.a \ - $IOSBUILDDIR/arm64/re-$NAME.a \ - $IOSBUILDDIR/i386/re-$NAME.a \ - $IOSBUILDDIR/x86_64/re-$NAME.a \ - -output $OUTPUT_DIR_LIB/boost_$NAME.a - echo "---------------" - echo "Now strip the binary" - strip -x $OUTPUT_DIR_LIB/boost_$NAME.a + + if [[ "$TYPE" == "tvos" ]]; then + echo "Lipo -c for $NAME for all tvOS Architectures (arm64, x86_64)" + lipo -c $IOSBUILDDIR/arm64/re-$NAME.a \ + $IOSBUILDDIR/x86_64/re-$NAME.a \ + -output $OUTPUT_DIR_LIB/boost_$NAME.a + elif [[ "$TYPE" == "ios" ]]; then + echo "Lipo -c for $NAME for all iOS Architectures (arm64, armv7, i386, x86_64)" + lipo -c $IOSBUILDDIR/armv7/re-$NAME.a \ + $IOSBUILDDIR/arm64/re-$NAME.a \ + $IOSBUILDDIR/i386/re-$NAME.a \ + $IOSBUILDDIR/x86_64/re-$NAME.a \ + -output $OUTPUT_DIR_LIB/boost_$NAME.a + fi + echo "---------------" + if [[ "$TYPE" == "ios" ]]; then + echo "Now strip the binary" + strip -x $OUTPUT_DIR_LIB/boost_$NAME.a + echo "---------------" + fi done echo "done" echo "---------------" @@ -247,7 +322,7 @@ function copy() { rsync -ar install_dir/boost/* $1/include/boost/ cp stage/lib/libboost_filesystem.a $1/lib/$TYPE/boost_filesystem.a cp stage/lib/libboost_system.a $1/lib/$TYPE/boost_system.a - elif [ "$TYPE" == "ios" ]; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then OUTPUT_DIR_LIB=`pwd`/lib/boost/ios/ OUTPUT_DIR_SRC=`pwd`/lib/boost/include/boost #rsync -ar $OUTPUT_DIR_SRC/* $1/include/boost/ @@ -274,7 +349,7 @@ function copy() { function clean() { if [ "$TYPE" == "wincb" ] ; then rm -f *.lib - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then rm -rf build iphone-build iphonesim-build lib ./b2 --clean else diff --git a/scripts/apothecary/formulas/boost/operations.cpp.patch_1.58 b/scripts/apothecary/formulas/boost/operations.cpp.patch_1.58 new file mode 100644 index 00000000000..8be133be856 --- /dev/null +++ b/scripts/apothecary/formulas/boost/operations.cpp.patch_1.58 @@ -0,0 +1,24 @@ +--- libs/filesystem/src/operations.cpp 2015-09-15 14:34:34.000000000 -0500 ++++ libs/filesystem/src/operations.cpp.new 2015-09-15 14:33:18.000000000 -0500 +@@ -1400,7 +1400,7 @@ + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + +- // Mac OS X Lion and some other platforms don't support fchmodat(). ++ // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to +@@ -1413,7 +1413,11 @@ + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" + # if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \ + && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \ +- && !(defined(linux) || defined(__linux) || defined(__linux__)) ++ && !(defined(linux) || defined(__linux) || defined(__linux__)) \ ++ && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ ++ && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) \ ++ && !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \ ++ && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), + !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) + # else // fallback if fchmodat() not supported diff --git a/scripts/apothecary/formulas/boost/visualc.hpp.patch_1.58 b/scripts/apothecary/formulas/boost/visualc.hpp.patch_1.58 new file mode 100644 index 00000000000..9bb94b5289d --- /dev/null +++ b/scripts/apothecary/formulas/boost/visualc.hpp.patch_1.58 @@ -0,0 +1,11 @@ +--- boost/config/compiler/visualc.hpp 2015-09-15 14:29:28.000000000 -0500 ++++ boost/config/compiler/visualc.hpp.new 2015-09-15 14:30:06.000000000 -0500 +@@ -285,7 +285,7 @@ + + // + // last known and checked version is 19.00.22129 (VC14 Preview): +-#if (_MSC_VER > 1800 && _MSC_FULL_VER > 190022310) ++#if (_MSC_VER > 1900 && _MSC_FULL_VER > 190022310) + # if defined(BOOST_ASSERT_CONFIG) + # error "Unknown compiler version - please run the configure tests and report the results" + # else diff --git a/scripts/apothecary/formulas/cairo.sh b/scripts/apothecary/formulas/cairo.sh index bc37034f032..f2bc104f0c8 100644 --- a/scripts/apothecary/formulas/cairo.sh +++ b/scripts/apothecary/formulas/cairo.sh @@ -12,7 +12,7 @@ # prefix (install location) and use a custom copy of pkg-config which returns # the dependent lib cflags/ldflags for that prefix (cairo/apothecary-build) -FORMULA_TYPES=( "osx" "vs" "win_cb" ) +FORMULA_TYPES=( "osx" "vs" "msys2" ) FORMULA_DEPENDS=( "pkg-config" "zlib" "libpng" "pixman" "freetype" ) @@ -168,7 +168,7 @@ function copy() { fi cd cairo - elif [ "$TYPE" == "osx" -o "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "osx" -o "$TYPE" == "msys2" ] ; then # make the path in the libs dir mkdir -p $1/include/cairo diff --git a/scripts/apothecary/formulas/fmodex.sh b/scripts/apothecary/formulas/fmodex.sh index 2cc6405e536..89313f7a291 100644 --- a/scripts/apothecary/formulas/fmodex.sh +++ b/scripts/apothecary/formulas/fmodex.sh @@ -7,10 +7,11 @@ # FmodEX is downloaded as a binary from the fmod.org website and copied # into the openFrameworks library directory. -FORMULA_TYPES=( "osx" "vs" "win_cb" ) + +FORMULA_TYPES=( "osx" "vs" "msys2" ) # define the version -VER=44221 +VER=44459 # tools for git use GIT_URL= @@ -21,20 +22,30 @@ function download() { mkdir -p "fmodex" - case $TYPE in - "osx" ) + + set -e + + if [ "$TYPE" == "osx" ]; then # download drive image for fmodex from fmod.org - curl -O http://www.fmod.org/download/fmodex/api/Mac/fmodapi${VER}mac-installer.dmg + + mkdir -p "fmodex/docs" + + echo "Manually download the fmod dmg from the following link. It requires a login." + echo http://www.fmod.org/download/fmodex/api/Mac/fmodapi${VER}mac-installer.dmg + echo "Once you have downloaded it. Copy it and place the dmg in apothecary/build/" + #curl -O http://www.fmod.org/download/fmodex/api/Mac/fmodapi${VER}mac-installer.dmg # mount dmg hdiutil attach fmodapi${VER}mac-installer.dmg -quiet # copy contents into staging folder cp -R "/Volumes/FMOD Programmers API Mac/FMOD Programmers API/api/" "fmodex" + cp -R "/Volumes/FMOD Programmers API Mac/FMOD Programmers API/documentation/" "fmodex/docs/" # remove installer dmg rm fmodapi${VER}mac-installer.dmg # unmount drive image hdiutil detach "/Volumes/FMOD Programmers API Mac/" -quiet - ;; - esac + + + fi echo "downloaded fmodex" } @@ -47,21 +58,39 @@ function prepare() { # executed inside the lib src dir function build() { - echo "build not needed for $TYPE" + + if [ "$TYPE" == "osx" ]; then + + cd lib + install_name_tool -id "@executable_name/libfmodex.dylib" libfmodex.dylib + cd ../ + + else + echo "build not needed for $TYPE" + + fi + + } # executed inside the lib src dir, first arg $1 is the dest libs dir root function copy() { - if [ "$TYPE" == "osx" ] ; then + if [ "$TYPE" == "osx" ]; then # headers mkdir -p $1/include cp -Rv inc/* $1/include # library files cp -Rv lib/libfmodex.dylib $1/lib/$TYPE/ + + cp -Rv lib/libfmodex.dylib $1/../../export/$TYPE/libs/ fi - echoWarning "TODO: Copy License" + # copy license files + rm -rf $1/license # remove any older files if exists + mkdir -p $1/license + cp -v docs/LICENSE.TXT $1/license/ + } # executed inside the lib src dir diff --git a/scripts/apothecary/formulas/freetype/emscripten.patch b/scripts/apothecary/formulas/freetype/emscripten.patch new file mode 100644 index 00000000000..ab5a59574ae --- /dev/null +++ b/scripts/apothecary/formulas/freetype/emscripten.patch @@ -0,0 +1,144 @@ +From 5af357ae531632a4ea4991863f4ba77c3366eda2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= +Date: Thu, 19 Sep 2013 13:45:29 +0300 +Subject: [PATCH] Fix function pointer signature cast mismatches that affect + compiling FreeType to Emscripten asm.js target. See + https://groups.google.com/forum/#!topic/emscripten-discuss/rLphBQHFs6o and + https://github.com/kripken/emscripten/pull/1104 for more information on this + topic. + +--- + src/autofit/afdummy.c | 4 +++- + src/autofit/aftypes.h | 2 +- + src/cid/cidload.c | 28 +++++++++++++--------------- + 3 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/src/autofit/afdummy.c b/src/autofit/afdummy.c +index 03ca25f..26e19e9 100644 +--- a/src/autofit/afdummy.c ++++ b/src/autofit/afdummy.c +@@ -39,10 +39,12 @@ + + static FT_Error + af_dummy_hints_apply( AF_GlyphHints hints, +- FT_Outline* outline ) ++ FT_Outline* outline, ++ AF_StyleMetrics metrics ) + { + FT_Error error; + ++ FT_UNUSED(metrics); + + error = af_glyph_hints_reload( hints, outline ); + if ( !error ) +diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h +index 78e3fd7..6fd61e0 100644 +--- a/src/autofit/aftypes.h ++++ b/src/autofit/aftypes.h +@@ -214,7 +214,7 @@ extern void* _af_debug_hints; + (*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + +- typedef void ++ typedef FT_Error + (*AF_WritingSystem_ApplyHintsFunc)( AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); +diff --git a/src/cid/cidload.c b/src/cid/cidload.c +index 6f35860..51341c9 100644 +--- a/src/cid/cidload.c ++++ b/src/cid/cidload.c +@@ -146,7 +146,7 @@ + } + + +- FT_CALLBACK_DEF( FT_Error ) ++ FT_CALLBACK_DEF( void ) + cid_parse_font_matrix( CID_Face face, + CID_Parser* parser ) + { +@@ -170,14 +170,18 @@ + result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); + + if ( result < 6 ) +- return FT_THROW( Invalid_File_Format ); ++ { ++ FT_THROW( Invalid_File_Format ); ++ return; ++ } + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); +- return FT_THROW( Invalid_File_Format ); ++ FT_THROW( Invalid_File_Format ); ++ return; + } + + /* Set Units per EM based on FontMatrix values. We set the value to */ +@@ -206,12 +210,10 @@ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } +- +- return FT_Err_Ok; + } + + +- FT_CALLBACK_DEF( FT_Error ) ++ FT_CALLBACK_DEF( void ) + parse_fd_array( CID_Face face, + CID_Parser* parser ) + { +@@ -225,8 +227,8 @@ + if ( num_dicts < 0 ) + { + FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); +- error = FT_THROW( Invalid_File_Format ); +- goto Exit; ++ FT_THROW( Invalid_File_Format ); ++ return; + } + + if ( !cid->font_dicts ) +@@ -235,7 +237,7 @@ + + + if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) +- goto Exit; ++ return; + + cid->num_dicts = num_dicts; + +@@ -249,9 +251,7 @@ + dict->private_dict.lenIV = 4; + } + } +- +- Exit: +- return error; ++ FT_UNUSED(error); + } + + +@@ -259,7 +259,7 @@ + /* and CID_FaceDictRec (both are public header files and can't */ + /* changed); we simply copy the value */ + +- FT_CALLBACK_DEF( FT_Error ) ++ FT_CALLBACK_DEF( void ) + parse_expansion_factor( CID_Face face, + CID_Parser* parser ) + { +@@ -273,8 +273,6 @@ + dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); + dict->private_dict.expansion_factor = dict->expansion_factor; + } +- +- return FT_Err_Ok; + } + + + diff --git a/scripts/apothecary/formulas/freetype.sh b/scripts/apothecary/formulas/freetype/freetype.sh similarity index 71% rename from scripts/apothecary/formulas/freetype.sh rename to scripts/apothecary/formulas/freetype/freetype.sh index d2e784c621a..5172ba9682a 100644 --- a/scripts/apothecary/formulas/freetype.sh +++ b/scripts/apothecary/formulas/freetype/freetype.sh @@ -6,7 +6,7 @@ # # an autotools project -FORMULA_TYPES=( "osx" "vs" "win_cb" "ios" "android" "emscripten" ) +FORMULA_TYPES=( "osx" "vs" "msys2" "ios" "tvos" "android" "emscripten" ) # define the version VER=2.5.5 @@ -38,7 +38,7 @@ function build() { # these flags are used to create a fat 32/64 binary with i386->libstdc++, x86_64->libc++ # see https://gist.github.com/tgfrerer/8e2d973ed0cfdd514de6 - local FAT_CFLAGS="-arch i386 -arch x86_64 -stdlib=libc++" + local FAT_CFLAGS="-arch i386 -arch x86_64 -stdlib=libc++ -mmacosx-version-min=${OSX_MIN_SDK_VER}" set -e CURRENTPATH=`pwd` @@ -60,7 +60,7 @@ function build() { local TOOLCHAIN=$XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain ./configure --prefix=$BUILD_TO_DIR --without-bzip2 --with-harfbuzz=no --enable-static=yes --enable-shared=no \ - CFLAGS="$FAT_CFLAGS -pipe -Wno-trigraphs -fpascal-strings -O2 -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden" + CFLAGS="$FAT_CFLAGS -fPIC -pipe -Wno-trigraphs -fpascal-strings -O2 -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden" make clean make -j${PARALLEL_MAKE} make install @@ -92,7 +92,7 @@ function build() { vs-build "freetype.vcxproj" Build "Release|x64" cd ../../../ - elif [ "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "msys2" ] ; then # configure with arch if [ $ARCH == 32 ] ; then ./configure CFLAGS="-arch i386" @@ -103,7 +103,7 @@ function build() { make clean; make -j${PARALLEL_MAKE} - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then CSTANDARD=c11 # c89 | c99 | c11 | gnu11 CPPSTANDARD=c++11 # c89 | c99 | c11 | gnu11 @@ -111,7 +111,12 @@ function build() { COMPILER_CPPTYPE=clang++ # clang, gcc STDLIB=libc++ - IOS_ARCHS="i386 x86_64 armv7 arm64" # armv7s + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="arm64 x86_64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` set -e @@ -121,6 +126,13 @@ function build() { TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi + mkdir -p "builddir/$TYPE" # Validate environment @@ -137,10 +149,12 @@ function build() { ;; esac - unset IOS_DEVROOT IOS_SDKROOT + local TOOLCHAIN=$XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain - local IOS_DEVROOT=$XCODE_DEV_ROOT/Platforms/iPhoneOS.platform/Developer - local IOS_SDKROOT=$IOS_DEVROOT/SDKs/iPhoneOS$IOS_SDK_VER.sdk + MIN_IOS_VERSION=$IOS_MIN_SDK_VER + # min iOS version for arm64 is iOS 7 + + local IOS_CC=$TOOLCHAIN/usr/bin/cc local IOS_HOST="arm-apple-darwin" local IOS_PREFIX="/usr/local/iphone" @@ -153,43 +167,62 @@ function build() { export AS=$TOOLCHAIN/usr/bin/as export NM=$TOOLCHAIN/usr/bin/nm export RANLIB=$TOOLCHAIN/usr/bin/ranlib - export LDFLAGS="-L$IOS_SDKROOT/usr/lib/" - EXTRA_LINK_FLAGS="-std=$CSTANDARD -stdlib=$STDLIB -Os -fPIC -Wno-trigraphs -fpascal-strings -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden" - EXTRA_FLAGS="$EXTRA_LINK_FLAGS -fvisibility-inlines-hidden" + # loop through architectures! yay for loops! for IOS_ARCH in ${IOS_ARCHS} do set +e - #export ALL_IOS_ARCH="-arch armv7 -arch armv7s -arch arm64" + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" - + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + fi else - PLATFORM="iPhoneOS" + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + fi fi export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" export CROSS_SDK="${PLATFORM}${SDKVERSION}.sdk" export BUILD_TOOLS="${DEVELOPER}" - MIN_IOS_VERSION=$IOS_MIN_SDK_VER - # min iOS version for arm64 is iOS 7 - - if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures + if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors + MIN_IOS_VERSION=7.0 # 6.0 to prevent start linking errors fi - MIN_TYPE=-miphoneos-version-min= - if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_TYPE=-mios-simulator-version-min= - fi + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + fi + + export EXTRA_LINK_FLAGS="-std=$CSTANDARD $BITCODE -DNDEBUG -stdlib=$STDLIB $MIN_TYPE$MIN_IOS_VERSION -Os -fPIC -Wno-trigraphs -fpascal-strings -Wreturn-type -Wunused-variable -fmessage-length=0 -fvisibility=hidden" + export EXTRA_FLAGS="-arch $IOS_ARCH $EXTRA_LINK_FLAGS $BITCODE -DNDEBUG -fvisibility-inlines-hidden $MIN_TYPE$MIN_IOS_VERSION" - export CFLAGS="-arch $IOS_ARCH $EXTRA_FLAGS -pipe -no-cpp-precomp -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$MIN_IOS_VERSION -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/ -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/libxml2" + export PLATFORM_INCLUDE="-I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/ -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/libxml2" + export CFLAGS="-arch $IOS_ARCH $EXTRA_FLAGS -pipe -no-cpp-precomp -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $PLATFORM_INCLUDE" export LINKFLAGS="$CFLAGS $EXTRA_LINK_FLAGS" export LDFLAGS="-L${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/lib/ $LINKFLAGS" export CXXFLAGS="$CFLAGS $EXTRA_FLAGS" @@ -238,6 +271,8 @@ function build() { echo "-----------------" echo "Build Successful for $IOS_ARCH" + + unset CFLAGS LINKFLAGS LDFLAGS CXXFLAGS PLATFORM_INCLUDE EXTRA_FLAGS EXTRA_LINK_FLAGS done echo "-----------------" @@ -251,13 +286,20 @@ function build() { # link into universal lib cd lib/$TYPE/ - # libfreetype-armv7s.a \ - lipo -create libfreetype-armv7.a \ - libfreetype-arm64.a \ - libfreetype-i386.a \ - libfreetype-x86_64.a \ - -output libfreetype.a \ - >> "${LOG}" 2>&1 + if [ "${TYPE}" == "tvos" ]; then + lipo -create libfreetype-arm64.a \ + libfreetype-x86_64.a \ + -output libfreetype.a \ + >> "${LOG}" 2>&1 + elif [ "$TYPE" == "ios" ]; then + # libfreetype-armv7s.a \ + lipo -create libfreetype-armv7.a \ + libfreetype-arm64.a \ + libfreetype-i386.a \ + libfreetype-x86_64.a \ + -output libfreetype.a \ + >> "${LOG}" 2>&1 + fi if [ $? != 0 ]; then @@ -270,25 +312,27 @@ function build() { cd ../../ lipo -info lib/$TYPE/libfreetype.a - echo "--------------------" - echo "Stripping any lingering symbols" + if [[ "$TYPE" == "ios" ]]; then + echo "--------------------" + echo "Stripping any lingering symbols" - SLOG="$CURRENTPATH/lib/$TYPE/freetype-stripping.log" + SLOG="$CURRENTPATH/lib/$TYPE/freetype-stripping.log" - strip -x lib/$TYPE/libfreetype.a >> "${SLOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 100 "${SLOG}" - echo "Problem while stripping lib - Please check ${SLOG}" - exit 1 - else - echo "Strip Successful for ${SLOG}" + strip -x lib/$TYPE/libfreetype.a >> "${SLOG}" 2>&1 + if [ $? != 0 ]; + then + tail -n 100 "${SLOG}" + echo "Problem while stripping lib - Please check ${SLOG}" + exit 1 + else + echo "Strip Successful for ${SLOG}" + fi fi echo "--------------------" echo "Build Successful for FreeType $TYPE $VER" - unset IOS_DEVROOT IOS_SDKROOT IOS_AR IOS_HOST IOS_PREFIX CPP CXX CXXCPP CXXCPP CC LD AS AR NM RANLIB LDFLAGS STDLIB + unset IOS_AR IOS_HOST IOS_PREFIX CPP CXX CXXCPP CXXCPP CC LD AS AR NM RANLIB LDFLAGS STDLIB elif [ "$TYPE" == "android" ] ; then @@ -321,6 +365,7 @@ function build() { echo "error emscripten is not installed or environment not set" exit 1 fi + patch -p0 -u < $FORMULA_DIR/emscripten.patch local BUILD_TO_DIR=$BUILD_DIR/freetype/build/$TYPE ./configure --prefix=$BUILD_TO_DIR --with-harfbuzz=no --enable-static=yes --enable-shared=no --with-zlib=no --with-png=no make clean @@ -359,16 +404,16 @@ function copy() { if [ "$TYPE" == "osx" ] ; then cp -v lib/$TYPE/libfreetype.a $1/lib/$TYPE/freetype.a - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then cp -v lib/$TYPE/libfreetype.a $1/lib/$TYPE/freetype.a elif [ "$TYPE" == "vs" ] ; then mkdir -p $1/lib/$TYPE/Win32 mkdir -p $1/lib/$TYPE/x64 cp -v objs/vc2010/Win32/freetype$FVER.lib $1/lib/$TYPE/Win32/libfreetype.lib cp -v objs/vc2010/x64/freetype$FVER.lib $1/lib/$TYPE/x64/libfreetype.lib - elif [ "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "msys2" ] ; then # cp -v lib/$TYPE/libfreetype.a $1/lib/$TYPE/libfreetype.a - echoWarning "TODO: copy win_cb lib" + echoWarning "TODO: copy msys2 lib" elif [ "$TYPE" == "android" ] ; then cp -v build/$TYPE/armeabi-v7a/lib/libfreetype.a $1/lib/$TYPE/armeabi-v7a/libfreetype.a cp -v build/$TYPE/x86/lib/libfreetype.a $1/lib/$TYPE/x86/libfreetype.a @@ -392,7 +437,7 @@ function clean() { elif [ "$TYPE" == "android" ] ; then make clean rm -f build/$TYPE - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then make clean rm -f *.a *.lib rm -f builddir/$TYPE diff --git a/scripts/apothecary/formulas/glew.sh b/scripts/apothecary/formulas/glew.sh index 30f03151427..e767fde0fe9 100644 --- a/scripts/apothecary/formulas/glew.sh +++ b/scripts/apothecary/formulas/glew.sh @@ -8,7 +8,7 @@ # use "make glew.lib" to build only the lib without demos/tests # the OPT flag is used for CFLAGS (& LDFLAGS I think?) -FORMULA_TYPES=( "osx" "vs" "win_cb" ) +FORMULA_TYPES=( "osx" "vs" "msys2" ) # define the version VER=1.11.0 @@ -58,7 +58,7 @@ function build() { vs-build "glew_static.vcxproj" Build "Release|x64" #mv lib/Release/x64/glew32s.lib glew64s.lib cd ../../ - elif [ "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "msys2" ] ; then make clean make fi @@ -85,7 +85,7 @@ function copy() { cp -v lib/Release/x64/glew32s.lib $1/lib/$TYPE/x64 cp -v lib/Release/Win32/glew32s.lib $1/lib/$TYPE/Win32 - elif [ "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "msys2" ] ; then # TODO: add cb formula mkdir -p $1/lib/$TYPE cp -v lib/libglew32.a $1/lib/$TYPE diff --git a/scripts/apothecary/formulas/glfw.sh b/scripts/apothecary/formulas/glfw.sh index c91987107b2..4a7c2b98068 100644 --- a/scripts/apothecary/formulas/glfw.sh +++ b/scripts/apothecary/formulas/glfw.sh @@ -6,7 +6,7 @@ # # uses a CMake build system -FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "win_cb" "ios" "android" ) +FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "msys2" "ios" "android" ) # define the version VER=3.0.4 @@ -50,6 +50,18 @@ function build() { cmake .. -G "Visual Studio $VS_VER Win64" vs-build "GLFW.sln" Build "Release|x64" fi + elif [ "$TYPE" == "msys2" ]; then + + # *nix build system + cmake . -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$BUILD_ROOT_DIR \ + -DGLFW_BUILD_DOCS=OFF \ + -DGLFW_BUILD_TESTS=OFF \ + -DGLFW_BUILD_EXAMPLES=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_C_COMPILER=/mingw32/bin/gcc.exe + + make -j${PARALLEL_MAKE} + make install else # *nix build system @@ -66,7 +78,6 @@ function build() { make clean make -j${PARALLEL_MAKE} - make install fi } @@ -88,12 +99,23 @@ function copy() { cp -v build_vs_64/src/Release/glfw3.lib $1/lib/$TYPE/x64/glfw3.lib fi + elif [ "$TYPE" == "osx" ]; then + # Standard *nix style copy. + # copy headers + if [ -d $BUILD_ROOT_DIR/include/GLFW/ ] ; then + cp -Rv $BUILD_ROOT_DIR/include/GLFW/* $1/include/GLFW/ + fi + # copy lib + if [ -d $BUILD_ROOT_DIR/lib/ ] ; then + cp -Rv $BUILD_ROOT_DIR/lib/libglfw3.a $1/lib/$TYPE/glfw3.a + fi + else # Standard *nix style copy. # copy headers cp -Rv $BUILD_ROOT_DIR/include/GLFW/* $1/include/GLFW/ # copy lib - cp -Rv $BUILD_ROOT_DIR/lib/libglfw3.a $1/lib/$TYPE/glfw3.a + cp -Rv $BUILD_ROOT_DIR/lib/libglfw3.a $1/lib/$TYPE/libglfw3.a fi # copy license file diff --git a/scripts/apothecary/formulas/kiss.sh b/scripts/apothecary/formulas/kiss.sh index 28074e8ec43..75d07bef43c 100644 --- a/scripts/apothecary/formulas/kiss.sh +++ b/scripts/apothecary/formulas/kiss.sh @@ -5,7 +5,7 @@ # http://sourceforge.net/projects/kissfft/ # # has a Makefile -FORMULA_TYPES=( "osx" "linux" "linux64" "win_cb" "ios" "android" ) +FORMULA_TYPES=( "osx" "linux" "linux64" "msys2" "ios" "android" ) # define the version VER=130 diff --git a/scripts/apothecary/formulas/kiss/kiss.sh b/scripts/apothecary/formulas/kiss/kiss.sh index 40e142b06a5..70b17e5404c 100644 --- a/scripts/apothecary/formulas/kiss/kiss.sh +++ b/scripts/apothecary/formulas/kiss/kiss.sh @@ -5,7 +5,7 @@ # http://sourceforge.net/projects/kissfft/ # # has a Makefile -FORMULA_TYPES=( "osx" "linux" "linux64" "win_cb" "ios" "android" ) +FORMULA_TYPES=( "osx" "linux" "linux64" "msys2" "ios" "android" ) # define the version VER=130 diff --git a/scripts/apothecary/formulas/openssl/openssl.sh b/scripts/apothecary/formulas/openssl/openssl.sh index 4acd48ea617..04a9ac0b59c 100644 --- a/scripts/apothecary/formulas/openssl/openssl.sh +++ b/scripts/apothecary/formulas/openssl/openssl.sh @@ -3,9 +3,10 @@ # openssl # define the version -FORMULA_TYPES=( "osx" "vs" "win_cb" "ios" "android" ) +FORMULA_TYPES=( "osx" "vs" "msys2" "ios" "tvos" "android" ) -VER=1.0.2c +VER=1.0.2d +VERDIR=1.0.2 CSTANDARD=gnu11 # c89 | c99 | c11 | gnu11 COMPILER_TYPE=clang # clang, gcc @@ -43,7 +44,7 @@ function download() { # prepare the build environment, executed inside the lib src dir function prepare() { - if [ "$TYPE" == "ios" ] ; then + if [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then # create output directories mkdir -p "src" mkdir -p "bin" @@ -71,6 +72,11 @@ function prepare() { elif [ "$TYPE" == "osx" ] ; then mkdir -p lib/$TYPE mkdir -p lib/include + + cp Makefile Makefile.orig + cp Configure Configure1.orig + + #cp $FORMULA_DIR/Configure Configure elif [ "$TYPE" == "vs" ] ; then if patch -p1 -u -N --dry-run --silent < $FORMULA_DIR/winOpenSSL.patch 2>/dev/null ; then patch -p1 -u < $FORMULA_DIR/winOpenSSL.patch @@ -82,9 +88,46 @@ function prepare() { function build() { if [ "$TYPE" == "osx" ] ; then + + set -e + CURRENTPATH=`pwd` + + DEVELOPER=$XCODE_DEV_ROOT + TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain + SDKVERSION="" + SDKVERSION=`xcrun -sdk macosx --show-sdk-version` + + if [ "${COMPILER_TYPE}" == "clang" ]; then + export THECOMPILER=clang + else + export THECOMPILER=gcc + fi + + # Validate environment + case $XCODE_DEV_ROOT in + *\ * ) + echo "Your Xcode path contains whitespaces, which is not supported." + exit 1 + ;; + esac + case $CURRENTPATH in + *\ * ) + echo "Your path contains whitespaces, which is not supported by 'make install'." + exit 1 + ;; + esac + local TOOLCHAIN=$XCODE_DEV_ROOT/Toolchains/XcodeDefault.xctoolchain + + export OSX_CC=$TOOLCHAIN/usr/bin/$THECOMPILER + export OSX_CXX=$TOOLCHAIN/usr/bin/$THECOMPILER++ + export LD=$TOOLCHAIN/usr/bin/ld + export AR=$TOOLCHAIN/usr/bin/ar + export AS=$TOOLCHAIN/usr/bin/as + export NM=$TOOLCHAIN/usr/bin/nm + export RANLIB=$TOOLCHAIN/usr/bin/ranlib local BUILD_OPTS="-no-shared -no-asm -no-ec_nistp_64_gcc_128 -no-gmp -no-jpake -no-krb5 -no-md2 -no-rc5 -no-rfc3779 -no-sctp -no-shared -no-store -no-unit-test -no-zlib -no-zlib-dynamic" - local OSX_ARCHS="x86_64 i386" + local OSX_ARCHS="i386 x86_64" VERSION=$VER CURRENTPATH=`pwd` @@ -94,6 +137,9 @@ function build() { for OSX_ARCH in ${OSX_ARCHS} do + make -j 1 clean + rm -rf build/$TYPE/OSX_ARCH + rm -rf *.a # remove temp lib from main directory # Back up configure & makefile cp "Configure" "Configure.orig" @@ -104,59 +150,30 @@ function build() { #create logfile LOG="$CURRENTPATH/build/$TYPE/$OSX_ARCH/build-openssl-${VER}.log" - - - if [ "${COMPILER_TYPE}" == "clang" ]; then - export THECOMPILER=clang - else - export THECOMPILER=gcc - fi - - echo "Using Compiler: $THECOMPILER" - - # unset LANG if defined - if test ${LANG+defined}; - then - OLD_LANG=$LANG - unset LANG - fi - - # unset LC_CTYPE if defined - if test ${LC_CTYPE+defined}; - then - OLD_LC_CTYPE=$LC_CTYPE - LC_CTYPE=C - fi + echo "Using Compiler: $THECOMPILER for $OSX_ARCH" # patch the Configure file to make sure the correct compiler is invoked. - sed -ie "s!\"darwin-i386-cc\",\"cc:-arch i386 -g3!\"darwin-i386-cc\",\"${THECOMPILER}:-arch i386 -g3!" Configure - sed -ie "s!\"darwin64-x86_64-cc\",\"cc:-arch x86_64 -O3!\"darwin64-x86_64-cc\",\"$THECOMPILER:-arch x86_64 -O3!" Configure - - # reset LANG if it was defined - if test ${OLD_LANG+defined}; - then - export LANG=$OLD_LANG - fi - - # reset LC_CTYPE if it was defined - if test ${OLD_LC_CTYPE+defined}; - then - export LC_CTYPE=$OLD_LC_CTYPE - fi + export LC_CTYPE=C + export LANG=C + sed -ie "s!\"darwin-i386-cc\",\"cc:-arch i386 -O3!\"darwin-i386-cc\",\"cc:-arch i386 -O3!" Configure + + export LC_CTYPE=C + export LANG=C + sed -ie "s!\"darwin64-x86_64-cc\",\"cc:-arch x86_64 -O3!\"darwin64-x86_64-cc\",\"cc:-arch x86_64 -O3!" Configure OSX_C_FLAGS="" # Flags for stdlib, std and arch CONFIG_TARGET="" # Which one of the target presets to use if [[ "${OSX_ARCH}" == "i386" ]]; then # 386 -> libstdc++ - OSX_C_FLAGS="-arch ${OSX_ARCH} -std=${CSTANDARD} -stdlib=libstdc++" + OSX_C_FLAGS="-arch ${OSX_ARCH} -std=${CSTANDARD} -fPIC -stdlib=libc++ -mmacosx-version-min=${OSX_MIN_SDK_VER}" CONFIG_TARGET=darwin-i386-cc - export CC="${THECOMPILER} ${OSX_C_FLAGS}" + export CC="${OSX_CC} ${OSX_C_FLAGS}" elif [ "${OSX_ARCH}" == "x86_64" ]; then # 86_64 -> libc++ - OSX_C_FLAGS="-arch ${OSX_ARCH} -std=${CSTANDARD} -stdlib=libc++" + OSX_C_FLAGS="-arch ${OSX_ARCH} -std=${CSTANDARD} -fPIC -stdlib=libc++ -mmacosx-version-min=${OSX_MIN_SDK_VER}" CONFIG_TARGET=darwin64-x86_64-cc - export CC="${THECOMPILER} ${OSX_C_FLAGS}" + export CC="${OSX_CC} ${OSX_C_FLAGS}" fi echo "Configure for target: $CONFIG_TARGET" @@ -198,14 +215,24 @@ function build() { then export LC_CTYPE=$OLD_LC_CTYPE fi - - echo "Running make for ${OSX_ARCH}" - echo "Please stand by..." - - # Must run at -j 1 (single thread only else will fail) - # this is super annoying, but true for OS X, as well as iOS. - make -j 1 >> "${LOG}" 2>&1 - + set -o pipefail # trace ERR through pipes + set -o errtrace # trace ERR through 'time command' and other functions + + export BUILD_OUTPUT=$LOG + export PING_SLEEP=30s + export PING_LOOP_PID + trap 'error_handler ${LINENO} ${?}' ERR + bash -c "while true; do echo \$(date) - Building OpenSSL ...; sleep $PING_SLEEP; done" & +PING_LOOP_PID=$! + echo "Running make for ${OSX_ARCH}" + echo "Please stand by..." + # Must run at -j 1 (single thread only else will fail) + # this is super annoying, but true for OS X, as well as iOS. + make -j 1 >> "${BUILD_OUTPUT}" 2>&1 + dump_output + kill $PING_LOOP_PID + trap - ERR + if [ $? != 0 ]; then tail -n 100 "${LOG}" @@ -217,16 +244,17 @@ function build() { set -e make -j 1 install >> "${LOG}" 2>&1 - make -j 1 clean >> "${LOG}" 2>&1 + make -j 1 clean # restore configure & makefile cp "Configure.orig" "Configure" cp "Makefile.orig" "Makefile" - unset CC CFLAG CFLAGS EXTRAFLAGS THECOMPILER + rm -rf *.a # remove temp lib from main directory + unset CC CFLAG CFLAGS EXTRAFLAGS done - + unset THECOMPILER # Stage includes echo "Staging includes" @@ -240,7 +268,7 @@ function build() { cd lib/$TYPE SLOG="$CURRENTPATH/lib/$TYPE-stripping.log" local TOBESTRIPPED - for TOBESTRIPPED in $( ls -1) ; do + for TOBESTRIPPED in $( ls *.a) ; do strip -x $TOBESTRIPPED >> "${SLOG}" 2>&1 if [ $? != 0 ]; then @@ -253,6 +281,8 @@ function build() { done cd ../../ + + echo "Build Finished!" # ------------ END OS X Recipe. @@ -273,7 +303,7 @@ function build() { mkdir ms/x64 cmd //c buildwin.cmd x64 "${WINPATH}" fi - # elif [ "$TYPE" == "win_cb" ] ; then + # elif [ "$TYPE" == "msys2" ] ; then # # local BUILD_OPTS="--no-tests --no-samples --static --omit=CppUnit,CppUnit/WinTestRunner,Data/MySQL,Data/ODBC,PageCompiler,PageCompiler/File2Page,CppParser,PocoDoc,ProGen" # # # Locate the path of the openssl libs distributed with openFrameworks. @@ -283,7 +313,7 @@ function build() { # # local OF_LIBS_OPENSSL_ABS_PATH=$(cd $(dirname $OF_LIBS_OPENSSL); pwd)/$(basename $OF_LIBS_OPENSSL) # # local OPENSSL_INCLUDE=$OF_LIBS_OPENSSL_ABS_PATH/include - # # local OPENSSL_LIBS=$OF_LIBS_OPENSSL_ABS_PATH/lib/win_cb + # # local OPENSSL_LIBS=$OF_LIBS_OPENSSL_ABS_PATH/lib/msys2 # # ./configure $BUILD_OPTS \ # # --include-path=$OPENSSL_INCLUDE \ @@ -295,11 +325,11 @@ function build() { # # # Delete debug libs. # # lib/MinGW/i686/*d.a - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then # This was quite helpful as a reference: https://github.com/x2on/OpenSSL-for-iPhone # Refer to the other script if anything drastic changes for future versions - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + set -e CURRENTPATH=`pwd` @@ -307,9 +337,20 @@ function build() { TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER - local IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="x86_64 arm64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi local STDLIB="libc++" + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi # Validate environment case $XCODE_DEV_ROOT in @@ -330,6 +371,7 @@ function build() { do # make sure backed up cp "Configure" "Configure.orig" + cp "apps/speed.c" "apps/speed.c.orig" cp "Makefile" "Makefile.orig" if [ "${COMPILER_TYPE}" == "clang" ]; then @@ -339,9 +381,28 @@ function build() { fi echo "The compiler: $THECOMPILER" + ## Fix for tvOS fork undef 9.0 + if [ "${TYPE}" == "tvos" ]; then + + # Patch apps/speed.c to not use fork() since it's not available on tvOS + LC_ALL=C sed -i -- 's/define HAVE_FORK 1/define HAVE_FORK 0/' "apps/speed.c" + # Patch Configure to build for tvOS, not iOS + LC_ALL=C sed -i -- 's/D\_REENTRANT\:iOS/D\_REENTRANT\:tvOS/' "Configure" + chmod u+x ./Configure + # export LC_CTYPE=C + # export LANG=C + # sed -ie "s!\"defined(OPENSSL_SYS_NETWARE)\"!\"defined(OPENSSL_SYS_NETWARE) || defined(TARGET_IOS)\"!" "./apps/speed.c" + + # sed -ie "s!\"-D_REENTRANT:iOS\"!\"-D_REENTRANT:tvOS\"!" "./Configure" + fi + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + fi # unset LANG if defined if test ${LANG+defined}; @@ -357,8 +418,8 @@ function build() { LC_CTYPE=C fi - sed -ie "s!\"debug-darwin-i386-cc\",\"cc:-arch i386 -g3!\"debug-darwin-i386-cc\",\"$THECOMPILER:-arch i386 -g3!" Configure - sed -ie "s!\"darwin64-x86_64-cc\",\"cc:-arch x86_64 -O3!\"darwin64-x86_64-cc\",\"$THECOMPILER:-arch x86_64 -O3!" Configure + LC_ALL=C sed -ie "s!\"debug-darwin-i386-cc\",\"cc:-arch i386 -g3!\"debug-darwin-i386-cc\",\"$THECOMPILER:-arch i386 -g3!" Configure + LC_ALL=C sed -ie "s!\"darwin64-x86_64-cc\",\"cc:-arch x86_64 -O3!\"darwin64-x86_64-cc\",\"$THECOMPILER:-arch x86_64 -O3!" Configure # reset LANG if it was defined if test ${OLD_LANG+defined}; @@ -374,8 +435,12 @@ function build() { else cp "crypto/ui/ui_openssl.c" "crypto/ui/ui_openssl.c.orig" - sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c" - PLATFORM="iPhoneOS" + LC_ALL=C sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c" + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + fi # unset LANG if defined if test ${LANG+defined}; @@ -391,7 +456,7 @@ function build() { LC_CTYPE=C fi - sed -ie "s!\"iphoneos-cross\",\"llvm-gcc:-O3!\"iphoneos-cross\",\"$THECOMPILER:-Os!" Configure + LC_ALL=C sed -ie "s!\"iphoneos-cross\",\"llvm-gcc:-O3!\"iphoneos-cross\",\"$THECOMPILER:-Os!" Configure # reset LANG if it was defined if test ${OLD_LANG+defined}; @@ -410,27 +475,32 @@ function build() { export CROSS_SDK="${PLATFORM}${SDKVERSION}.sdk" export BUILD_TOOLS="${DEVELOPER}" - export CC="${THECOMPILER} -arch ${IOS_ARCH} -std=${CSTANDARD}" + MIN_IOS_VERSION=$IOS_MIN_SDK_VER + # min iOS version for arm64 is iOS 7 + + if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures + elif [ "${IOS_ARCH}" == "i386" ]; then + MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + fi + + export CC="${THECOMPILER} -arch ${IOS_ARCH} -std=${CSTANDARD} $BITCODE" mkdir -p "$CURRENTPATH/build/$TYPE/$IOS_ARCH" LOG="$CURRENTPATH/build/$TYPE/$IOS_ARCH/build-openssl-${VER}.log" - MIN_IOS_VERSION=$IOS_MIN_SDK_VER - # min iOS version for arm64 is iOS 7 - - if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures - elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors - fi + echo "Compiler: $CC" echo "Building openssl-${VER} for ${PLATFORM} ${SDKVERSION} ${IOS_ARCH} : iOS Minimum=$MIN_IOS_VERSION" set +e - if [ [ "$VERSION" =~ 1.0.0. ] ]; then - echo "Building for OpenSSL Version before 1.0.0" - ./Configure BSD-generic32 -no-asm --openssldir="$CURRENTPATH/build/$TYPE/$IOS_ARCH" > "${LOG}" 2>&1 - elif [ "${IOS_ARCH}" == "i386" ]; then + if [ "${IOS_ARCH}" == "i386" ]; then echo "Configuring i386" ./Configure darwin-i386-cc -no-asm --openssldir="$CURRENTPATH/build/$TYPE/$IOS_ARCH" > "${LOG}" 2>&1 elif [ "${IOS_ARCH}" == "x86_64" ]; then @@ -448,10 +518,17 @@ function build() { exit 1 fi - MIN_TYPE=-miphoneos-version-min= - if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_TYPE=-mios-simulator-version-min= - fi + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi # unset LANG if defined if test ${LANG+defined}; @@ -467,7 +544,7 @@ function build() { LC_CTYPE=C fi - sed -ie "s!^CFLAG=!CFLAG=-isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -arch $IOS_ARCH -Os -fPIC -stdlib=libc++ $MIN_TYPE$MIN_IOS_VERSION !" Makefile + LC_ALL=C sed -ie "s!^CFLAG=!CFLAG=-isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -arch $IOS_ARCH -Os -fPIC $BITCODE -stdlib=libc++ $MIN_TYPE$MIN_IOS_VERSION !" Makefile # reset LANG if it was defined if test ${OLD_LANG+defined}; @@ -481,10 +558,21 @@ function build() { export LC_CTYPE=$OLD_LC_CTYPE fi + export BUILD_OUTPUT=$LOG + export PING_SLEEP=30s + export PING_LOOP_PID + trap 'error_handler' ERR + bash -c "while true; do echo \$(date) - Building OpenSSL ...; sleep $PING_SLEEP; done" & +PING_LOOP_PID=$! + echo "Running make for ${IOS_ARCH}" echo "Please stand by..." # Must run at -j 1 (single thread only else will fail) - make >> "${LOG}" 2>&1 + make >> "${BUILD_OUTPUT}" 2>&1 + dump_output + kill $PING_LOOP_PID + trap - ERR + if [ $? != 0 ]; then tail -n 100 "${LOG}" @@ -508,6 +596,9 @@ function build() { cp "crypto/ui/ui_openssl.c.orig" "crypto/ui/ui_openssl.c" cp "Makefile.orig" "Makefile" cp "Configure.orig" "Configure" + cp "apps/speed.c.orig" "apps/speed.c" + + unset CC CFLAG CFLAGS EXTRAFLAGS THECOMPILER @@ -518,19 +609,30 @@ function build() { unset IOS_DEVROOT IOS_SDKROOT cd lib/$TYPE/ - # stripping the lib prefix to bypass any issues with existing sdk libraries - echo "Creating Fat Lib for crypto" - lipo -create armv7/crypto.a \ - arm64/crypto.a \ - i386/crypto.a \ - x86_64/crypto.a \ - -output crypto.a - echo "Creating Fat Lib for ssl" - lipo -create armv7/ssl.a \ - arm64/ssl.a \ - i386/ssl.a \ - x86_64/ssl.a \ - -output ssl.a + + # stripping the lib prefix to bypass any issues with existing sdk libraries + echo "Creating Fat Lib for crypto" + if [ "${TYPE}" == "tvos" ]; then + lipo -create arm64/crypto.a \ + x86_64/crypto.a \ + -output crypto.a + echo "Creating Fat Lib for ssl" + lipo -create arm64/ssl.a \ + x86_64/ssl.a \ + -output ssl.a + elif [ "$TYPE" == "ios" ]; then + lipo -create armv7/crypto.a \ + arm64/crypto.a \ + i386/crypto.a \ + x86_64/crypto.a \ + -output crypto.a + echo "Creating Fat Lib for ssl" + lipo -create armv7/ssl.a \ + arm64/ssl.a \ + i386/ssl.a \ + x86_64/ssl.a \ + -output ssl.a + fi cd ../../ # copy includes @@ -551,7 +653,7 @@ function build() { perl -pi -e 's/^_ANDROID_EABI=(.*)$/#_ANDROID_EABI=\1/g' Setenv-android.sh perl -pi -e 's/^_ANDROID_ARCH=(.*)$/#_ANDROID_ARCH=\1/g' Setenv-android.sh perl -pi -e 's/^_ANDROID_API=(.*)$/#_ANDROID_API=\1/g' Setenv-android.sh - export _ANDROID_API=android-21 + export _ANDROID_API=$ANDROID_PLATFORM # armv7 echoInfo "Compiling armv7" @@ -606,10 +708,18 @@ function copy() { # opensslconf.h that detects the platform and includes the # correct one. Then every platform checkouts the rest of the config # files that were deleted here - mv include/openssl/opensslconf.h include/openssl/opensslconf_${TYPE}.h - cp -RHv include/openssl/* $1/include/openssl/ - cp -v $FORMULA_DIR/opensslconf.h $1/include/openssl/opensslconf.h - + if [[ "$TYPE" == "osx" || "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then + if [ -f lib/include/openssl/opensslconf.h ]; then + mv lib/include/openssl/opensslconf.h lib/include/openssl/opensslconf_${TYPE}.h + fi + cp -RHv lib/include/openssl/* $1/include/openssl/ + cp -v $FORMULA_DIR/opensslconf.h $1/include/openssl/opensslconf.h + + elif [ -f include/openssl/opensslconf.h ]; then + mv include/openssl/opensslconf.h include/openssl/opensslconf_${TYPE}.h + cp -RHv include/openssl/* $1/include/openssl/ + cp -v $FORMULA_DIR/opensslconf.h $1/include/openssl/opensslconf.h + fi # suppress file not found errors #same here doesn't seem to be a solid reason to delete the files #rm -rf $1/lib/$TYPE/* 2> /dev/null @@ -618,17 +728,27 @@ function copy() { if [ "$TYPE" == "osx" ] ; then mkdir -p $1/lib/$TYPE cp -v lib/$TYPE/*.a $1/lib/$TYPE - git checkout $1/include/openssl/opensslconf_ios.h - git checkout $1/include/openssl/opensslconf_android.h - git checkout $1/include/openssl/opensslconf_vs.h - git checkout $1/include/openssl/opensslconf_win32.h - elif [ "$TYPE" == "ios" ] ; then + if [[ "$CHECKOUT" == "NO" ]]; then + echo "no git checkout" + else + git checkout $1/include/openssl/opensslconf_osx.h + git checkout $1/include/openssl/opensslconf_ios.h + git checkout $1/include/openssl/opensslconf_android.h + git checkout $1/include/openssl/opensslconf_vs.h + git checkout $1/include/openssl/opensslconf_win32.h + fi + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then mkdir -p $1/lib/$TYPE cp -v lib/$TYPE/*.a $1/lib/$TYPE - git checkout $1/include/openssl/opensslconf_osx.h - git checkout $1/include/openssl/opensslconf_android.h - git checkout $1/include/openssl/opensslconf_vs.h - git checkout $1/include/openssl/opensslconf_win32.h + if [[ "$CHECKOUT" == "NO" ]]; then + echo "no git checkout" + else + git checkout $1/include/openssl/opensslconf_osx.h + git checkout $1/include/openssl/opensslconf_ios.h + git checkout $1/include/openssl/opensslconf_android.h + git checkout $1/include/openssl/opensslconf_vs.h + git checkout $1/include/openssl/opensslconf_win32.h + fi elif [ "$TYPE" == "vs" ] ; then if [ $ARCH == 32 ] ; then rm -rf $1/lib/$TYPE/Win32 @@ -652,7 +772,7 @@ function copy() { git checkout $1/include/openssl/opensslconf_osx.h git checkout $1/include/openssl/opensslconf_android.h git checkout $1/include/openssl/opensslconf_win32.h - # elif [ "$TYPE" == "win_cb" ] ; then + # elif [ "$TYPE" == "msys2" ] ; then # mkdir -p $1/lib/$TYPE # cp -v lib/MinGW/i686/*.a $1/lib/$TYPE @@ -693,7 +813,7 @@ function copy() { # executed inside the lib src dir function clean() { echoWarning "TODO: clean $TYPE lib" - if [ "$TYPE" == "ios" ] ; then + if [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then make clean # clean up old build folder rm -rf /build @@ -712,6 +832,13 @@ function clean() { # make clean ANDROID_ABI=armeabi-v7a # make clean ANDROID_ABI=x86 # unset PATH + elif [[ "$TYPE" == "osx" ]] ; then + make clean + # clean up old build folder + rm -rf /build + # clean up compiled libraries + rm -rf /lib + rm -rf *.a else make clean fi diff --git a/scripts/apothecary/formulas/openssl/opensslconf.h b/scripts/apothecary/formulas/openssl/opensslconf.h index 2842f5d1f0d..2fef8fc06f1 100644 --- a/scripts/apothecary/formulas/openssl/opensslconf.h +++ b/scripts/apothecary/formulas/openssl/opensslconf.h @@ -1,9 +1,12 @@ +#include #if defined(_MSC_VER) # include #elif defined( __WIN32__ ) || defined( _WIN32 ) # include -#elif TARGET_OS_IPHONE_SIMULATOR || TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE || TARGET_IPHONE +#elif TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) # include +#elif TARGET_OS_TV +# include #elif defined(__APPLE_CC__) # include #elif defined (__ANDROID__) diff --git a/scripts/apothecary/formulas/poco/AppleTV b/scripts/apothecary/formulas/poco/AppleTV new file mode 100644 index 00000000000..8dda7cb6367 --- /dev/null +++ b/scripts/apothecary/formulas/poco/AppleTV @@ -0,0 +1,98 @@ +# +# $Id$ +# +# AppleTV +# +# Build settings for tvOS 9.0 and newer +# + +# +# General Settings +# +# tvOS does not allow dynamic linking to user libraries +# +LINKMODE ?= STATIC + +# +# If the SDK is defined use it +# Otherwise find the latest version installed +# +# TVOS_SDK_VERSION = 9.0 + +# if TVOS_SDK_VERSION_MIN is defined use that +# Otherwise use the version found. + +TVOS_SDK ?= AppleTVOS +TVOS_SDK_ROOT ?= $(shell xcode-select -print-path)/Platforms/$(TVOS_SDK).platform/Developer/SDKs +TVOS_SDK_ROOT_DIR = $(TVOS_SDK_ROOT)/$(TVOS_SDK) +TVOS_SDK_BASE = $(shell ls -d $(TVOS_SDK_ROOT_DIR)$(TVOS_SDK_VERSION)*.sdk | tail -1) +TVOS_SDK_VERSION_MIN ?= $(patsubst %.sdk,%,$(patsubst $(TVOS_SDK_ROOT_DIR)%,%,$(TVOS_SDK_BASE))) + +POCO_TARGET_OSNAME ?= $(TVOS_SDK) +POCO_TARGET_OSARCH ?= arm64 +TOOL_PREFIX ?= $(shell xcode-select -print-path)/Platforms/$(TVOS_SDK).platform/Developer/usr/bin +OSFLAGS ?= -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-version-min=$(TVOS_SDK_VERSION_MIN) -fembed-bitcode + +# +# Tools +# +# If GCC_VER is defined then use it. +# Otherwise select the latest version +# + +CC = $(shell xcrun -find clang) +CXX = $(shell xcrun -find clang++) + +LINK = $(CXX) -bind_at_load +LIB = libtool -static -o +RANLIB = ranlib +SHLIB = $(CXX) $(OSFLAGS) -dynamiclib -Wl,-install_name,$@ -o $@ +DYLIB = $(CXX) $(OSFLAGS) -dynamic -bundle -read_only_relocs suppress -Wl,-bind_at_load -o $@ +SHLIBLN = $(POCO_BASE)/build/script/shlibln +STRIP = +DEP = $(POCO_BASE)/build/script/makedepend.gcc +SHELL = sh +RM = rm -rf +CP = cp +MKDIR = mkdir -p + +# +# Extension for Shared Libraries +# +SHAREDLIBEXT = .$(target_version).dylib +SHAREDLIBLINKEXT = .dylib + +# +# Compiler and Linker Flags +# +CFLAGS = $(OSFLAGS) +CFLAGS32 = +CFLAGS64 = +CXXFLAGS = $(OSFLAGS) -std=c++11 -stdlib=libc++ -Wall -Wno-sign-compare +CXXFLAGS32 = +CXXFLAGS64 = +LINKFLAGS = $(OSFLAGS) -stdlib=libc++ +LINKFLAGS32 = +LINKFLAGS64 = +STATICOPT_CC = +STATICOPT_CXX = +STATICOPT_LINK = +SHAREDOPT_CC = -fPIC -fembed-bitcode +SHAREDOPT_CXX = -fPIC -fembed-bitcode +SHAREDOPT_LINK = +DEBUGOPT_CC = -g -D_DEBUG=$(DEBUGLEVEL) +DEBUGOPT_CXX = -g -D_DEBUG=$(DEBUGLEVEL) +DEBUGOPT_LINK = +RELEASEOPT_CC = -DNDEBUG -O2 +RELEASEOPT_CXX = -DNDEBUG -O +RELEASEOPT_LINK = + +# +# System Specific Flags +# +SYSFLAGS = -DPOCO_HAVE_IPv6 -DPOCO_NO_FPENVIRONMENT -DPOCO_NO_STAT64 -DPOCO_NO_SHAREDLIBS -DPOCO_NO_NET_IFTYPES -DPOCO_NO_FORK_EXEC + +# +# System Specific Libraries +# +SYSLIBS = -ldl \ No newline at end of file diff --git a/scripts/apothecary/formulas/poco/AppleTVSimulator b/scripts/apothecary/formulas/poco/AppleTVSimulator new file mode 100644 index 00000000000..0c002acb6fb --- /dev/null +++ b/scripts/apothecary/formulas/poco/AppleTVSimulator @@ -0,0 +1,13 @@ +# +# $Id$ +# +# AppleTVSimulator +# +# Build settings for tvOS 9.0 Simulator +# + +TVOS_SDK = AppleTVSimulator +POCO_TARGET_OSARCH = x86_64 +OSFLAGS = -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-simulator-version-min=$(TVOS_SDK_VERSION_MIN) -fembed-bitcode + +include $(POCO_BASE)/build/config/AppleTV \ No newline at end of file diff --git a/scripts/apothecary/formulas/poco/MinGWConfig64 b/scripts/apothecary/formulas/poco/MinGWConfig64 new file mode 100644 index 00000000000..bcca60e3e82 --- /dev/null +++ b/scripts/apothecary/formulas/poco/MinGWConfig64 @@ -0,0 +1,74 @@ +# +# $Id: //poco/1.4/build/config/MinGW#2 $ +# +# MinGW32 +# +# Make settings for MinGW32 +# + +# +# General Settings +# +LINKMODE = STATIC +POCO_TARGET_OSNAME = MinGW +POCO_TARGET_OSARCH = i686 + +# +# Define Tools +# +CC = /mingw32/bin/gcc +CXX = /mingw32/bin/g++ +LINK = $(CXX) +LIB = /mingw32/bin/ar -cr +RANLIB = ranlib +SHLIB = $(CXX) -shared -o $@ -Wl,--out-implib=$(dir $@)$(subst cyg,lib,$(basename $(notdir $@))).a +SHLIBLN = $(POCO_BASE)/build/script/shlibln +STRIP = +DEP = $(POCO_BASE)/build/script/makedepend.gcc +SHELL = sh +RM = rm -rf +CP = cp +MKDIR = mkdir -p + +# +# Extension for Shared Libraries +# +SHAREDLIBEXT = .dll +SHAREDLIBLINKEXT = .dll + +BINEXT = .exe + +# +# Compiler and Linker Flags +# +CFLAGS = +CFLAGS32 = +CFLAGS64 = +CXXFLAGS = +CXXFLAGS32 = +CXXFLAGS64 = +LINKFLAGS = -Wl,--allow-multiple-definition +LINKFLAGS32 = +LINKFLAGS64 = +STATICOPT_CC = +STATICOPT_CXX = +STATICOPT_LINK = -static +SHAREDOPT_CC = +SHAREDOPT_CXX = +SHAREDOPT_LINK = -shared +DEBUGOPT_CC = -g -D_DEBUG +DEBUGOPT_CXX = -g -D_DEBUG +DEBUGOPT_LINK = -g +RELEASEOPT_CC = -O2 -DNDEBUG +RELEASEOPT_CXX = -O2 -DNDEBUG +RELEASEOPT_LINK = -O2 + +# +# System Specific Flags +# +SYSFLAGS = -D_WIN32 -DMINGW32 -DWINVER=0x501 -DPOCO_NO_FPENVIRONMENT -DPCRE_STATIC -DPOCO_THREAD_STACK_SIZE -DPOCO_STATIC -DPOCO_NO_AUTOMATIC_LIB_INIT -I/mingw32/include + +# +# System Specific Libraries +# +SYSLIBS = -L/mingw64/lib -liphlpapi -lssl -lcrypto -lws2_32 diff --git a/scripts/apothecary/formulas/poco/poco.sh b/scripts/apothecary/formulas/poco/poco.sh index 3641544c556..217c78e2991 100644 --- a/scripts/apothecary/formulas/poco/poco.sh +++ b/scripts/apothecary/formulas/poco/poco.sh @@ -14,6 +14,8 @@ VER=1.6.0-release GIT_URL=https://github.com/pocoproject/poco GIT_TAG=poco-1.6.0-release +FORMULA_TYPES=( "osx" "ios" "tvos" "android" "emscripten" "vs" "linux" "linux64" "linuxarmv6l" "linuxarmv7l") + #dependencies FORMULA_DEPENDS=( "openssl" ) @@ -48,21 +50,27 @@ function prepare() { git reset --hard $SHA fi - # manually prepare dependencies - apothecaryDependencies download - apothecaryDependencies prepare - - # Build and copy all dependencies in preparation - apothecaryDepend build openssl - apothecaryDepend copy openssl + if [ "$TYPE" != "msys2" ] && [ "$TYPE" != "linux" ] && [ "$TYPE" != "ios" ] && [ "$TYPE" != "tvos" ]; then + # manually prepare dependencies + apothecaryDependencies download + apothecaryDependencies prepare + # Build and copy all dependencies in preparation + apothecaryDepend build openssl + apothecaryDepend copy openssl + fi # make backups of the ios config files since we need to edit them - if [ "$TYPE" == "ios" ] ; then + if [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then mkdir -p lib/$TYPE mkdir -p lib/iPhoneOS cd build/config + if [[ "$TYPE" == "tvos" ]]; then + cp $FORMULA_DIR/AppleTV AppleTV + cp $FORMULA_DIR/AppleTVSimulator AppleTVSimulator + fi + cp iPhoneSimulator-clang-libc++ iPhoneSimulator-clang-libc++.orig cp iPhone-clang-libc++ iPhone-clang-libc++.orig @@ -154,7 +162,16 @@ function build() { echo "--------------------" echo "Running make" LOG="$CURRENTPATH/build/$TYPE/poco-make-i386-${VER}.log" - make -j${PARALLEL_MAKE} >> "${LOG}" 2>&1 + export BUILD_OUTPUT=$LOG + export PING_SLEEP=30s + export PING_LOOP_PID + trap 'error_handler' ERR + bash -c "while true; do echo \$(date) - Building Poco ...; sleep $PING_SLEEP; done" & +PING_LOOP_PID=$! + make -j${PARALLEL_MAKE} >> "${BUILD_OUTPUT}" 2>&1 + dump_output + kill $PING_LOOP_PID + trap - ERR if [ $? != 0 ]; then tail -n 100 "${LOG}" @@ -181,24 +198,25 @@ function build() { echo "--------------------" echo "Running make" LOG="$CURRENTPATH/build/$TYPE/poco-make-x86_64-${VER}.log" - make -j${PARALLEL_MAKE} >> "${LOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 100 "${LOG}" - echo "Problem while make - Please check ${LOG}" - exit 1 - else - tail -n 100 "${LOG}" - echo "Make Successful" - fi + export BUILD_OUTPUT=$LOG + export PING_SLEEP=30s + export PING_LOOP_PID + trap 'error_handler' ERR + bash -c "while true; do echo \$(date) - Building Poco ...; sleep $PING_SLEEP; done" & +PING_LOOP_PID=$! + + make -j${PARALLEL_MAKE} >> "${BUILD_OUTPUT}" 2>&1 + dump_output + kill $PING_LOOP_PID + trap - ERR unset POCO_ENABLE_CPP11 cd lib/Darwin # delete debug builds - rm i386/*d.a - rm x86_64/*d.a + rm -f i386/*d.a + rm -f x86_64/*d.a # link into universal lib, strip "lib" from filename local lib @@ -217,40 +235,40 @@ function build() { cmd //c buildwin.cmd ${VS_VER}0 upgrade static_md both x64 nosamples notests cmd //c buildwin.cmd ${VS_VER}0 build static_md both x64 nosamples notests fi - elif [ "$TYPE" == "win_cb" ] ; then - local BUILD_OPTS="--no-tests --no-samples --static --omit=CppUnit,CppUnit/WinTestRunner,Data/MySQL,Data/ODBC,PageCompiler,PageCompiler/File2Page,CppParser,PDF,PocoDoc,ProGen" - - # Locate the path of the openssl libs distributed with openFrameworks. - local OF_LIBS_OPENSSL="$LIBS_DIR/openssl/" - - # get the absolute path to the included openssl libs - local OF_LIBS_OPENSSL_ABS_PATH=$(cd $(dirname $OF_LIBS_OPENSSL); pwd)/$(basename $OF_LIBS_OPENSSL) - - local OPENSSL_INCLUDE=$OF_LIBS_OPENSSL_ABS_PATH/include - local OPENSSL_LIBS=$OF_LIBS_OPENSSL_ABS_PATH/lib/win_cb + elif [ "$TYPE" == "msys2" ] ; then + cp $FORMULA_DIR/MinGWConfig64 build/config/MinGW + local BUILD_OPTS="--no-tests --no-samples --static --no-sharedlibs --omit=CppUnit,CppUnit/WinTestRunner,Data/MySQL,Data/ODBC,PageCompiler,PageCompiler/File2Page,CppParser,PDF,PocoDoc,ProGen" ./configure $BUILD_OPTS \ - --include-path=$OPENSSL_INCLUDE \ - --library-path=$OPENSSL_LIBS \ --config=MinGW make -j${PARALLEL_MAKE} # Delete debug libs. - lib/MinGW/i686/*d.a - - elif [ "$TYPE" == "ios" ] ; then + rm -f lib/MinGW/i686/*d.a + rm -f lib/MinGW/x86_64/*d.a - - SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then set -e + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi CURRENTPATH=`pwd` DEVELOPER=$XCODE_DEV_ROOT TOOLCHAIN=${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain VERSION=$VER - local IOS_ARCHS="i386 x86_64 armv7 arm64" + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="x86_64 arm64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi + echo "--------------------" echo $CURRENTPATH @@ -283,7 +301,7 @@ function build() { local OF_LIBS_OPENSSL_ABS_PATH=$(cd $(dirname $OF_LIBS_OPENSSL); pwd)/$(basename $OF_LIBS_OPENSSL) local OPENSSL_INCLUDE=$OF_LIBS_OPENSSL_ABS_PATH/include - local OPENSSL_LIBS=$OF_LIBS_OPENSSL_ABS_PATH/lib/ios + local OPENSSL_LIBS=$OF_LIBS_OPENSSL_ABS_PATH/lib/$TYPE local BUILD_OPTS="--no-tests --no-samples --static --omit=CppUnit,CppUnit/WinTestRunner,Data/MySQL,Data/ODBC,PageCompiler,PageCompiler/File2Page,CppParser,PDF,PocoDoc,ProGen --include-path=$OPENSSL_INCLUDE --library-path=$OPENSSL_LIBS" @@ -295,27 +313,57 @@ function build() { do MIN_IOS_VERSION=$IOS_MIN_SDK_VER # min iOS version for arm64 is iOS 7 - + if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors + MIN_IOS_VERSION=7.0 # 6.0 to prevent start linking errors fi export IPHONE_SDK_VERSION_MIN=$IOS_MIN_SDK_VER export POCO_TARGET_OSARCH=$IOS_ARCH MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" - BUILD_POCO_CONFIG=$BUILD_POCO_CONFIG_SIMULATOR - MIN_TYPE=-mios-simulator-version-min= + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + BUILD_POCO_CONFIG="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + BUILD_POCO_CONFIG=$BUILD_POCO_CONFIG_SIMULATOR + fi else - PLATFORM="iPhoneOS" - BUILD_POCO_CONFIG=$BUILD_POCO_CONFIG_SIMULATOR + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + BUILD_POCO_CONFIG="AppleTV" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + BUILD_POCO_CONFIG=$BUILD_POCO_CONFIG_IPHONE + fi fi + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi + + BITCODE="" + NOFORK="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + NOFORK="-DPOCO_NO_FORK_EXEC" + fi + export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" export CROSS_SDK="${PLATFORM}${SDKVERSION}.sdk" export BUILD_TOOLS="${DEVELOPER}" @@ -326,15 +374,15 @@ function build() { if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - export OSFLAGS="-arch $POCO_TARGET_OSARCH -fPIC -DPOCO_ENABLE_CPP11 -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$IPHONE_SDK_VERSION_MIN" + export OSFLAGS="-arch $POCO_TARGET_OSARCH $BITCODE -DNDEBUG $NOFORK -fPIC -DPOCO_ENABLE_CPP11 -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$MIN_IOS_VERSION" else - export OSFLAGS="-arch $POCO_TARGET_OSARCH -fPIC -DPOCO_ENABLE_CPP11 -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$IPHONE_SDK_VERSION_MIN" + export OSFLAGS="-arch $POCO_TARGET_OSARCH $BITCODE -DNDEBUG $NOFORK -fPIC -DPOCO_ENABLE_CPP11 -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$MIN_IOS_VERSION" fi echo "--------------------" echo "Making Poco-${VER} for ${PLATFORM} ${SDKVERSION} ${IOS_ARCH} : iOS Minimum=$MIN_IOS_VERSION" echo "--------------------" echo "Configuring for ${IOS_ARCH} ..." - ./configure $BUILD_OPTS --config=$BUILD_POCO_CONFIG_IPHONE > "${LOG}" 2>&1 + ./configure $BUILD_OPTS --config=$BUILD_POCO_CONFIG > "${LOG}" 2>&1 if [ $? != 0 ]; then tail -n 100 "${LOG}" @@ -345,7 +393,21 @@ function build() { fi echo "--------------------" echo "Running make for ${IOS_ARCH}" - make -j${PARALLEL_MAKE} >> "${LOG}" 2>&1 + echo "${LOG}" + + export BUILD_OUTPUT=$LOG + export PING_SLEEP=30s + export PING_LOOP_PID + trap 'error_handler' ERR + bash -c "while true; do echo \$(date) - Building Poco ...; sleep $PING_SLEEP; done" & +PING_LOOP_PID=$! + + + make -j${PARALLEL_MAKE} >> "${BUILD_OUTPUT}" 2>&1 + dump_output + kill $PING_LOOP_PID + trap - ERR + if [ $? != 0 ]; then tail -n 100 "${LOG}" @@ -362,37 +424,58 @@ function build() { done - cd lib/iPhoneOS - # link into universal lib, strip "lib" from filename - local lib - for lib in $( ls -1 i386) ; do - local renamedLib=$(echo $lib | sed 's|lib||') - if [ ! -e $renamedLib ] ; then - lipo -c armv7/$lib arm64/$lib i386/$lib x86_64/$lib -o ../ios/$renamedLib - fi - done + if [[ "${TYPE}" == "tvos" ]] ; then + cd lib/AppleTVOS + # link into universal lib, strip "lib" from filename + local lib + for lib in $( ls -1 arm64) ; do + local renamedLib=$(echo $lib | sed 's|lib||') + if [ ! -e $renamedLib ] ; then + lipo -c arm64/$lib \ + ../AppleTVSimulator/x86_64/$lib \ + -o ../tvos/$renamedLib + fi + done + elif [[ "$TYPE" == "ios" ]]; then + cd lib/iPhoneOS + # link into universal lib, strip "lib" from filename + local lib + for lib in $( ls -1 arm64) ; do + local renamedLib=$(echo $lib | sed 's|lib||') + if [ ! -e $renamedLib ] ; then + lipo -c armv7/$lib \ + arm64/$lib \ + ../iPhoneSimulator/i386/$lib \ + ../iPhoneSimulator/x86_64/$lib \ + -o ../ios/$renamedLib + fi + done + fi + cd ../../ - echo "--------------------" - echo "Stripping any lingering symbols" - - cd lib/$TYPE - SLOG="$CURRENTPATH/lib/$TYPE-stripping.log" - local TOBESTRIPPED - for TOBESTRIPPED in $( ls -1) ; do - strip -x $TOBESTRIPPED >> "${SLOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 100 "${SLOG}" - echo "Problem while stripping lib - Please check ${SLOG}" - exit 1 - else - echo "Strip Successful for ${SLOG}" - fi - done - - cd ../../ + if [[ "$TYPE" == "ios" ]]; then + echo "--------------------" + echo "Stripping any lingering symbols" + + cd lib/$TYPE + SLOG="$CURRENTPATH/lib/$TYPE-stripping.log" + local TOBESTRIPPED + for TOBESTRIPPED in $( ls -1) ; do + strip -x $TOBESTRIPPED >> "${SLOG}" 2>&1 + if [ $? != 0 ]; + then + tail -n 100 "${SLOG}" + echo "Problem while stripping lib - Please check ${SLOG}" + exit 1 + else + echo "Strip Successful for ${SLOG}" + fi + done + cd ../../ + fi + echo "--------------------" echo "Reseting changed files back to originals" @@ -439,8 +522,8 @@ function build() { echo `pwd` - rm -v lib/Android/armeabi-v7a/*d.a - rm -v lib/Android/x86/*d.a + rm -f lib/Android/armeabi-v7a/*d.a + rm -f lib/Android/x86/*d.a export PATH=$OLD_PATH @@ -449,7 +532,7 @@ function build() { ./configure $BUILD_OPTS make -j${PARALLEL_MAKE} # delete debug builds - rm lib/Linux/$(uname -m)/*d.a + rm -f lib/Linux/$(uname -m)/*d.a else echoWarning "TODO: build $TYPE lib" fi @@ -477,7 +560,7 @@ function copy() { if [ "$TYPE" == "osx" ] ; then mkdir -p $1/lib/$TYPE cp -v lib/Darwin/*.a $1/lib/$TYPE - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]] ; then mkdir -p $1/lib/$TYPE cp -v lib/$TYPE/*.a $1/lib/$TYPE elif [ "$TYPE" == "vs" ] ; then @@ -490,9 +573,10 @@ function copy() { cp -v lib64/*.lib $1/lib/$TYPE/x64 fi - elif [ "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "msys2" ] ; then mkdir -p $1/lib/$TYPE - cp -v lib/MinGW/i686/*.a $1/lib/$TYPE + cp -vf lib/MinGW/i686/*.a $1/lib/$TYPE + #cp -vf lib/MinGW/x86_64/*.a $1/lib/$TYPE elif [ "$TYPE" == "linux" ] ; then mkdir -p $1/lib/$TYPE cp -v lib/Linux/$(uname -m)/*.a $1/lib/$TYPE diff --git a/scripts/apothecary/formulas/portaudio.sh b/scripts/apothecary/formulas/portaudio.sh index 2511f6b8e84..3587028d962 100644 --- a/scripts/apothecary/formulas/portaudio.sh +++ b/scripts/apothecary/formulas/portaudio.sh @@ -6,7 +6,7 @@ # # build not currently needed on any platform -FORMULA_TYPES=( "osx" "vs" "win_cb" ) +FORMULA_TYPES=( "osx" "vs" "msys2" ) # define the version VER=stable_v19_20110326 diff --git a/scripts/apothecary/formulas/rtAudio.sh b/scripts/apothecary/formulas/rtAudio.sh index e57d79972fa..da9db1604a2 100644 --- a/scripts/apothecary/formulas/rtAudio.sh +++ b/scripts/apothecary/formulas/rtAudio.sh @@ -6,7 +6,7 @@ # # uses an autotools build system -FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "win_cb" ) +FORMULA_TYPES=( "osx" "linux" "linux64" "vs" "msys2" ) #FORMULA_DEPENDS=( "pkg-config" ) @@ -76,7 +76,7 @@ function build() { lipo -c librtaudio.a librtaudio-x86_64.a -o librtaudio.a - elif [ "$TYPE" == "vs" -o "$TYPE" == "win_cb" ] ; then + elif [ "$TYPE" == "vs" ] ; then local API="--with-wasapi --with-ds" # asio as well? if [ $ARCH == 32 ] ; then mkdir -p build_vs_32 @@ -91,6 +91,13 @@ function build() { vs-build "rtaudio_static.vcxproj" Build "Release|x64" vs-build "rtaudio_static.vcxproj" Build "Debug|x64" fi + + elif [ "$TYPE" == "msys2" ] ; then + local API="--with-wasapi --with-ds" # asio as well? + mkdir -p build + cd build + cmake .. -G "Unix Makefiles" -DAUDIO_WINDOWS_WASAPI=ON -DAUDIO_WINDOWS_DS=ON -DAUDIO_WINDOWS_ASIO=ON -DCMAKE_C_COMPILER=/mingw32/bin/gcc.exe -DCMAKE_CXX_COMPILER=/mingw32/bin/g++.exe -DBUILD_TESTING=OFF + make fi # clean up env vars @@ -119,8 +126,8 @@ function copy() { fi - elif [ "$TYPE" == "win_cb" ] ; then - echoWarning "TODO: copy win_cb lib" + elif [ "$TYPE" == "msys2" ] ; then + cp -v build/librtaudio_static.a $1/lib/$TYPE/librtaudio.a else cp -v librtaudio.a $1/lib/$TYPE/rtaudio.a diff --git a/scripts/apothecary/formulas/tess2/tess2.sh b/scripts/apothecary/formulas/tess2/tess2.sh index 8e52bdd7203..bcd3c1b5d37 100644 --- a/scripts/apothecary/formulas/tess2/tess2.sh +++ b/scripts/apothecary/formulas/tess2/tess2.sh @@ -8,6 +8,9 @@ # we follow the Homebrew approach which is to use CMake via a custom CMakeLists.txt # on ios, use some build scripts adapted from the Assimp project +# define the version +FORMULA_TYPES=( "osx" "vs" "emscripten" "ios" "tvos" "android" "linux" "linux64" ) + # define the version VER=1.1 @@ -25,7 +28,7 @@ GIT_REV=24e4bdd4158909e9720422208ab0a0aca788e700 # download the source code and unpack it into LIB_NAME function download() { - curl -L $GIT_URL/archive/$GIT_REV.tar.gz -o libtess2-$GIT_REV.tar.gz + curl --insecure -L $GIT_URL/archive/$GIT_REV.tar.gz -o libtess2-$GIT_REV.tar.gz tar -xf libtess2-$GIT_REV.tar.gz mv libtess2-$GIT_REV tess2 rm libtess2*.tar.gz @@ -35,10 +38,7 @@ function download() { function prepare() { # check if the patch was applied, if not then patch - if patch -p1 -u -N --dry-run --silent < $FORMULA_DIR/tess2.patch 2>/dev/null ; then - patch -p1 -u -N < $FORMULA_DIR/tess2.patch - fi - + patch -p1 -u -N < $FORMULA_DIR/tess2.patch # copy in build script and CMake toolchains adapted from Assimp if [ "$OS" == "osx" ] ; then mkdir -p build @@ -63,23 +63,12 @@ function build() { rm -f CMakeCache.txt set +e - # Choose which stdlib to use: - # i386 : libstdc++ - # x86_64 : libc++ - - case $OSX_ARCH in - i386 ) - # choose libstdc++ for i386 - STD_LIB_FLAGS="-stdlib=libstdc++" - ;; - x86_64 ) - STD_LIB_FLAGS="-stdlib=libc++" - ;; - esac + STD_LIB_FLAGS="-stdlib=libc++" + OPTIM_FLAGS="-O3" # choose "fastest" optimisation - export CFLAGS="-arch $OSX_ARCH $OPTIM_FLAGS -DNDEBUG" + export CFLAGS="-arch $OSX_ARCH $OPTIM_FLAGS -DNDEBUG -fPIC -mmacosx-version-min=${OSX_MIN_SDK_VER}" export CPPFLAGS=$CFLAGS export LINKFLAGS="$CFLAGS $STD_LIB_FLAGS" export LDFLAGS="$LINKFLAGS" @@ -90,10 +79,11 @@ function build() { echo "Building library slice for ${OSX_ARCH}..." cmake -G 'Unix Makefiles' \ - . - make clean >> "${LOG}" 2>&1 + . + make clean >> "${LOG}" 2>&1 make -j${PARALLEL_MAKE} >> "${LOG}" 2>&1 + # now we need to create a directory were we can keep our current build result. mkdir -p $TYPE @@ -113,26 +103,31 @@ function build() { LOG="build-tess2-${VER}-lipo.log" lipo -create $LIPO_SLICES \ - -output libtess2.a \ + -output build/libtess2.a \ > "${LOG}" 2>&1 elif [ "$TYPE" == "vs" ] ; then if [ $ARCH == 32 ] ; then mkdir -p build_vs_32 cd build_vs_32 - cmake .. -G "Visual Studio $VS_VER" + cmake .. -G "Visual Studio $VS_VER" -DCMAKE_CXX_FLAGS=-DNDEBUG -DCMAKE_C_FLAGS=-DNDEBUG vs-build "tess2.sln" elif [ $ARCH == 64 ] ; then mkdir -p build_vs_64 cd build_vs_64 - cmake .. -G "Visual Studio $VS_VER Win64" + cmake .. -G "Visual Studio $VS_VER Win64" -DCMAKE_CXX_FLAGS=-DNDEBUG -DCMAKE_C_FLAGS=-DNDEBUG vs-build "tess2.sln" Build "Release|x64" fi - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "${TYPE}" == "tvos" ]] ; then - IOS_ARCHS="i386 x86_64 armv7 arm64" # armv7s + local IOS_ARCHS + if [ "${TYPE}" == "tvos" ]; then + IOS_ARCHS="x86_64 arm64" + elif [ "$TYPE" == "ios" ]; then + IOS_ARCHS="i386 x86_64 armv7 arm64" #armv7s + fi SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` set -e @@ -167,6 +162,13 @@ function build() { export AS=$TOOLCHAIN/usr/bin/as export NM=$$TOOLCHAIN/usr/bin/nm export RANLIB=$TOOLCHAIN/usr/bin/ranlib + + SDKVERSION="" + if [ "${TYPE}" == "tvos" ]; then + SDKVERSION=`xcrun -sdk appletvos --show-sdk-version` + elif [ "$TYPE" == "ios" ]; then + SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` + fi EXTRA_LINK_FLAGS="-stdlib=libc++ -Os -fPIC" EXTRA_FLAGS="$EXTRA_LINK_FLAGS -fvisibility-inlines-hidden" @@ -179,13 +181,19 @@ function build() { rm -f CMakeCache.txt set +e - #export ALL_IOS_ARCH="-arch armv7 -arch armv7s -arch arm64" if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - PLATFORM="iPhoneSimulator" - + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVSimulator" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneSimulator" + fi else - PLATFORM="iPhoneOS" + if [ "${TYPE}" == "tvos" ]; then + PLATFORM="AppleTVOS" + elif [ "$TYPE" == "ios" ]; then + PLATFORM="iPhoneOS" + fi fi export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" @@ -193,24 +201,36 @@ function build() { export BUILD_TOOLS="${DEVELOPER}" MIN_IOS_VERSION=$IOS_MIN_SDK_VER - # min iOS version for arm64 is iOS 7 - if [[ "${IOS_ARCH}" == "arm64" || "${IOS_ARCH}" == "x86_64" ]]; then MIN_IOS_VERSION=7.0 # 7.0 as this is the minimum for these architectures elif [ "${IOS_ARCH}" == "i386" ]; then - MIN_IOS_VERSION=5.1 # 6.0 to prevent start linking errors - fi - - MIN_TYPE=-miphoneos-version-min= - if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then - MIN_TYPE=-mios-simulator-version-min= + MIN_IOS_VERSION=7.0 fi - export CFLAGS="-arch $IOS_ARCH -pipe -no-cpp-precomp -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$MIN_IOS_VERSION -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/ -DNDEBUG" + if [ "${TYPE}" == "tvos" ]; then + MIN_TYPE=-mtvos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mtvos-simulator-version-min= + fi + elif [ "$TYPE" == "ios" ]; then + MIN_TYPE=-miphoneos-version-min= + if [[ "${IOS_ARCH}" == "i386" || "${IOS_ARCH}" == "x86_64" ]]; then + MIN_TYPE=-mios-simulator-version-min= + fi + fi + + BITCODE="" + if [[ "$TYPE" == "tvos" ]]; then + BITCODE=-fembed-bitcode; + MIN_IOS_VERSION=9.0 + fi + + + export CFLAGS="-arch $IOS_ARCH $BITCODE -DNDEBUG -pipe -no-cpp-precomp -isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} $MIN_TYPE$MIN_IOS_VERSION -I${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/include/" export CPPFLAGS=$CFLAGS - export LINKFLAGS="$CFLAGS $EXTRA_LINK_FLAGS" - export LDFLAGS="-L${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/lib/ $LINKFLAGS" + export LINKFLAGS="$CFLAGS $EXTRA_LINK_FLAGS " + export LDFLAGS="-L${CROSS_TOP}/SDKs/${CROSS_SDK}/usr/lib/ $LINKFLAGS -std=c++11 -stdlib=libc++" export CXXFLAGS="$CFLAGS $EXTRA_FLAGS" mkdir -p "$CURRENTPATH/builddir/$TYPE/$IOS_ARCH" @@ -242,7 +262,7 @@ function build() { echo "-----------------" echo `pwd` echo "Finished for all architectures." - mkdir -p "$CURRENTPATH/builddir/$TYPE/$IOS_ARCH" + mkdir -p "$CURRENTPATH/builddir/$TYPE/" LOG="$CURRENTPATH/builddir/$TYPE/build-tess2-${VER}-lipo.log" mkdir -p "lib/$TYPE" @@ -251,6 +271,12 @@ function build() { echo "Running lipo to create fat lib" echo "Please stand by..." + if [[ "${TYPE}" == "tvos" ]]; then + lipo -create builddir/$TYPE/libtess2-arm64.a \ + builddir/$TYPE/libtess2-x86_64.a \ + -output builddir/$TYPE/libtess2.a \ + >> "${LOG}" 2>&1 + elif [[ "$TYPE" == "ios" ]]; then # builddir/$TYPE/libtess2-armv7s.a \ lipo -create builddir/$TYPE/libtess2-armv7.a \ builddir/$TYPE/libtess2-arm64.a \ @@ -258,6 +284,7 @@ function build() { builddir/$TYPE/libtess2-x86_64.a \ -output builddir/$TYPE/libtess2.a \ >> "${LOG}" 2>&1 + fi if [ $? != 0 ]; then @@ -271,19 +298,21 @@ function build() { mv builddir/$TYPE/libtess2.a lib/$TYPE/libtess2.a lipo -info lib/$TYPE/libtess2.a - echo "--------------------" - echo "Stripping any lingering symbols" + if [[ "$TYPE" == "ios" ]]; then + echo "--------------------" + echo "Stripping any lingering symbols" - SLOG="$CURRENTPATH/lib/$TYPE/tess2-stripping.log" + SLOG="$CURRENTPATH/lib/$TYPE/tess2-stripping.log" - strip -x lib/$TYPE/libtess2.a >> "${SLOG}" 2>&1 - if [ $? != 0 ]; - then - tail -n 100 "${SLOG}" - echo "Problem while stripping lib - Please check ${SLOG}" - exit 1 - else - echo "Strip Successful for ${SLOG}" + strip -x lib/$TYPE/libtess2.a >> "${SLOG}" 2>&1 + if [ $? != 0 ]; + then + tail -n 100 "${SLOG}" + echo "Problem while stripping lib - Please check ${SLOG}" + exit 1 + else + echo "Strip Successful for ${SLOG}" + fi fi echo "--------------------" @@ -298,10 +327,20 @@ function build() { cp -v $FORMULA_DIR/CMakeLists.txt . mkdir -p build cd build - emcmake cmake .. -DCMAKE_C_FLAGS=-DNDEBUG + emcmake cmake .. -DCMAKE_CXX_FLAGS=-DNDEBUG -DCMAKE_C_FLAGS=-DNDEBUG emmake make -j${PARALLEL_MAKE} - else - cmake -G "Unix Makefiles" --build build/$TYPE ../../ + elif [ "$TYPE" == "linux64" ]; then + premake4 gmake + cd Build + make config=release64 tess2 + elif [ "$TYPE" == "linux" ]; then + premake4 gmake + cd Build + make config=release32 tess2 + else + mkdir -p build/$TYPE + cd build/$TYPE + cmake -G "Unix Makefiles" -DCMAKE_CXX_COMPILER=/mingw32/bin/g++.exe -DCMAKE_C_COMPILER=/mingw32/bin/gcc.exe -DCMAKE_CXX_FLAGS=-DNDEBUG -DCMAKE_C_FLAGS=-DNDEBUG ../../ make fi } @@ -310,7 +349,7 @@ function build() { function copy() { # headers - rm -r $1/include + rm -rf $1/include mkdir -p $1/include cp -Rv Include/* $1/include/ @@ -324,17 +363,23 @@ function copy() { mkdir -p $1/lib/$TYPE/x64 cp -v build_vs_64/Release/tess2.lib $1/lib/$TYPE/x64/tess2.lib fi - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then cp -v lib/$TYPE/libtess2.a $1/lib/$TYPE/tess2.a - elif [ "$TYPE" == "android" ] ; then - echoWarning "TODO: copy android lib" + elif [ "$TYPE" == "osx" ]; then + cp -v build/libtess2.a $1/lib/$TYPE/tess2.a - elif [ "$TYPE" == "emscripten" ] ; then + elif [ "$TYPE" == "emscripten" ]; then cp -v build/libtess2.a $1/lib/$TYPE/libtess2.a + elif [ "$TYPE" == "linux64" ]; then + cp -v Build/libtess2.a $1/lib/$TYPE/libtess2.a + + elif [ "$TYPE" == "linux32" ]; then + cp -v Build/libtess2.a $1/lib/$TYPE/libtess2.a + else - cp -v libtess2.a $1/lib/$TYPE/tess2.a + cp -v build/$TYPE/libtess2.a $1/lib/$TYPE/libtess2.a fi # copy license files @@ -351,7 +396,7 @@ function clean() { elif [ "$TYPE" == "android" ] ; then echoWarning "TODO: clean android" - elif [ "$TYPE" == "ios" ] ; then + elif [[ "$TYPE" == "ios" || "$TYPE" == "tvos" ]]; then make clean rm -f CMakeCache.txt *.a *.lib rm -f builddir/$TYPE diff --git a/scripts/apothecary/formulas/uri/uri.sh b/scripts/apothecary/formulas/uri/uri.sh index 0e6c779eb0a..d1f96248abc 100644 --- a/scripts/apothecary/formulas/uri/uri.sh +++ b/scripts/apothecary/formulas/uri/uri.sh @@ -5,7 +5,7 @@ # # uses cmake build system -FORMULA_TYPES=( "osx" "win_cb" "ios" "android" "linux" "linux64" "linuxarmv6l" "linuxarmv7l" "emscripten" "vs" ) +FORMULA_TYPES=( "osx" "msys2" "ios" "android" "linux" "linux64" "linuxarmv6l" "linuxarmv7l" "emscripten" "vs" ) FORMULA_DEPENDS=( "boost" ) VER="master" diff --git a/scripts/apothecary/formulas/videoInput.sh b/scripts/apothecary/formulas/videoInput.sh index 9ef34866327..07f17526369 100644 --- a/scripts/apothecary/formulas/videoInput.sh +++ b/scripts/apothecary/formulas/videoInput.sh @@ -6,18 +6,18 @@ # # Visual Studio & Code Blocks projects are provided -FORMULA_TYPES=( "vs" "win_cb" ) +FORMULA_TYPES=( "vs" "msys2" ) # define the version VER=master # tools for git use -GIT_URL=https://github.com/ofTheo/videoInput.git +GIT_URL=https://github.com/arturoc/videoInput.git GIT_TAG=$VER # download the source code and unpack it into LIB_NAME function download() { - git clone https://github.com/ofTheo/videoInput.git + git clone ${GIT_URL} } # prepare the build environment, executed inside the lib src dir @@ -39,10 +39,9 @@ function build() { vs-build "videoInput.sln" Build "Release|x64" vs-build "videoInput.sln" Build "Debug|x64" fi - elif [ "$TYPE" == "win_cb" ] ; then - cd CodeBlocks-compileAsLib/videoInputLib - # run CodeBlocks on videoInputLib.cpb somehow - echoWarning "TODO: win_cb build" + elif [ "$TYPE" == "msys2" ] ; then + cd msys2 + make fi } @@ -66,7 +65,8 @@ function copy() { else - echoWarning "TODO: $TYPE copy" + mkdir -p $1/lib/$TYPE + cp -v compiledLib/msys2/libvideoinput.a $1/lib/$TYPE/ fi echoWarning "TODO: License Copy" @@ -78,7 +78,8 @@ function clean() { if [ "$TYPE" == "vs" ] ; then cd videoInputSrcAndDemos/VS-videoInputcompileAsLib vs-clean "videoInput.sln" - elif [ "$TYPE" == "win_cb" ] ; then - echoWarning "TODO: clean win_cb" + elif [ "$TYPE" == "msys2" ] ; then + cd videoInputSrcAndDemos/msys2 + make clean fi } diff --git a/scripts/apothecary/ostype.sh b/scripts/apothecary/ostype.sh index ee4b2b88f21..36addefcbab 100755 --- a/scripts/apothecary/ostype.sh +++ b/scripts/apothecary/ostype.sh @@ -9,8 +9,10 @@ OS=`lowercase \`uname\`` if [ "$OS" == "darwin" ]; then OS="osx" -elif [ "$OS" == "windowsnt" -o "${OS:0:5}" == "mingw" ] ; then - OS="windows" +elif [ "$OS" == "windowsnt" ] ; then + OS="vs" +elif [ "${OS:0:5}" == "mingw" -o "$OS" == "msys_nt-6.3" ]; then + OS="msys2" elif [ "$OS" == "linux" ]; then ARCH=`uname -m` if [ "$ARCH" == "i386" -o "$ARCH" == "i686" ] ; then diff --git a/scripts/ci/Readme.md b/scripts/ci/Readme.md new file mode 100644 index 00000000000..2f6f99f3a53 --- /dev/null +++ b/scripts/ci/Readme.md @@ -0,0 +1,35 @@ +# CI testing OF on Travis + +This folder contains the scripts necessary for the Continuous Integration tests running on travis-ci.org. + +The main CI steps are divided into two steps: +* A build step living in `/scripts/ci/*/build.sh`, which builds the openFrameworks library, the emptyExample where appropriate and the allAddonsExample (on Linux), and, in the future, e.g. the Project generator. +* In a second step, tests are run where available, using a script in `/scripts/ci/*/run_tests.sh`. + +This achieves a bit of separation between the different CI tasks, so it is easier to tell which part failed, as the steps in the `script:` section of `.travis.yml` are all checked for exit status independently. + +## Documented preconditions +* Currently, scripts expect the `$TRAVIS_BUILD_DIR` environment variable to exist, but falls back to automatically getting this from the script location with [a nice trick](http://stackoverflow.com/a/16879155/599884) and some help from [SO](http://stackoverflow.com/a/4774063/599884). +* The docs target relies on `$TRAVIS_PR`. +* The Android build downloads a stripped NDK from our server. The list of stripped things is at scripts/ci/android/NDK_excludes.txt for documentation. +* The build cache for Android builds currently has to be manually cleared when changing the NDK/toolchain version, and a new stripped NDK probably has to be uploaded to our server. A more granular cache test in scripts/ci/android/install.sh could make this unnecessary. + +## Future fixes/improvements +* (If on newer Ubuntu) remove the -no-install-recommends from the docs before_install script. +* Within `linux/build.sh`, exporting `$CXX` does not currently make Make see it, so a workaround was implemented by export. +* Android install uses a customized NDK as Travis can't extract the "normal" way due to memory constraints. +* A helper script in /ci would be nice to enable people to easily run a whole build locally. +* The `docs` build does not work for some reason, has been reported [upstream](https://github.com/HalfdanJ/ofDocGenerator/issues/3). +* Currently, a `no-op` build is added to the build matrix to work around [a Travis issue](https://github.com/travis-ci/travis-ci/issues/1228). +* Transitioning the Linux build to the new Docker infrastructure works in principle (see b03d1a323cfc1ed284ff1c275a76e5bd75d62b30 and a7cba47dcd1d89724d3871f5e5ca8841cf4a8340), but a large list of packages we need are not [whitelisted](https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise) for use, so this has been postponed: + * libraw1394-dev + * libassimp-dev + * librtaudio-dev + * libgstreamer-plugins-base1.0-dev + * gstreamer1.0-libav + * gstreamer1.0-pulseaudio + * gstreamer1.0-x + * gstreamer1.0-plugins-bad + * gstreamer1.0-alsa + * gstreamer1.0-plugins-base + * gstreamer1.0-plugins-good diff --git a/scripts/ci/android/NDK_excludes.txt b/scripts/ci/android/NDK_excludes.txt new file mode 100644 index 00000000000..b263d8e8a89 --- /dev/null +++ b/scripts/ci/android/NDK_excludes.txt @@ -0,0 +1,22 @@ +llvm-* +stlport +x86-4.8 +docs +android-3 +android-4 +android-5 +android-8 +android-9 +android-12 +android-13 +android-14 +android-15 +android-16 +android-17 +android-18 +android-21 +*mips* +*4.8* +*4.6* +python2.7 +perl5 diff --git a/scripts/ci/android/build.sh b/scripts/ci/android/build.sh new file mode 100755 index 00000000000..9bc1dc556fc --- /dev/null +++ b/scripts/ci/android/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +cd $ROOT/examples/android/androidEmptyExample +echo "ABIS_TO_COMPILE_DEBUG = $1" >> config.make +make Debug PLATFORM_OS=Android diff --git a/scripts/ci/android/install.sh b/scripts/ci/android/install.sh new file mode 100755 index 00000000000..ea7ec76d423 --- /dev/null +++ b/scripts/ci/android/install.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -ev +# capture failing exits in commands obscured behind a pipe +set -o pipefail +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +cd ~ +# check if cached directory exists +if [ "$(ls -A android-ndk-r10e)" ]; then + echo "Using cached NDK" + ls -A android-ndk-r10e +else + echo "Downloading NDK" + # curl -Lk http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin -o ndk.bin + # get slimmed and recompressed NDK from our server instead + curl -Lk http://ci.openframeworks.cc/android-ndk-r10e.tar.bz2 -o ndk.bin + chmod a+x ndk.bin + # "Normal" way: + # ./ndk.bin -y | grep -v Extracting + # extract with 7zip, -mmt=1 makes it use only 1 thread to reduce memory consumption: + # 7z x -mmt=1 ndk.bin $(sed 's/^/ -xr!/g' $ROOT/scripts/ci/android/NDK_excludes.txt) | grep -v -e "Extracting" -e "Skipping" + # extract customized NDK: + tar -xjf ndk.bin + rm ndk.bin +fi +NDK_ROOT=$(echo ${PWD} | sed "s/\//\\\\\//g") +cat $ROOT/libs/openFrameworksCompiled/project/android/paths.default.make | sed s/path_to/${NDK_ROOT}/ > $ROOT/libs/openFrameworksCompiled/project/android/paths.make diff --git a/scripts/ci/docs/after_success.sh b/scripts/ci/docs/after_success.sh new file mode 100755 index 00000000000..f7f9eb7867e --- /dev/null +++ b/scripts/ci/docs/after_success.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ev +echo "Uploading documentation to FTP server" +if [[ $TRAVIS_PULL_REQUEST == "false" && $FTP_USER ]]; then + ncftpput -R -v -u $FTP_USER -p $FTP_PASSWORD 104.130.212.175 / output/*; +else + echo "On a PR, skipping upload. Only direct commits are uploaded."; +fi diff --git a/scripts/ci/docs/build.sh b/scripts/ci/docs/build.sh new file mode 100755 index 00000000000..e7fd04e5fb8 --- /dev/null +++ b/scripts/ci/docs/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ev +echo "Building OF documentation" +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +cd $ROOT/scripts/ofDocGenerator +npm run start diff --git a/scripts/ci/docs/install.sh b/scripts/ci/docs/install.sh new file mode 100755 index 00000000000..74d7e7ba489 --- /dev/null +++ b/scripts/ci/docs/install.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -ev +echo "Installing documentation dependencies" +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +gem install sass --version "=3.2.12" +gem install compass --version "=0.12.2" +cd $ROOT/scripts +git clone https://github.com/halfdanJ/ofDocGenerator +cd ofDocGenerator +npm install diff --git a/scripts/ci/ios/build.sh b/scripts/ci/ios/build.sh new file mode 100755 index 00000000000..df967cb2ced --- /dev/null +++ b/scripts/ci/ios/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ev +echo "Building openFrameworks - iOS Template Project" +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +xcodebuild -project "$ROOT/scripts/templates/ios/emptyExample.xcodeproj" -target emptyExample -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO + diff --git a/scripts/ci/linux/build.sh b/scripts/ci/linux/build.sh new file mode 100755 index 00000000000..88cf17020fb --- /dev/null +++ b/scripts/ci/linux/build.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +# Add compiler flag to reduce memory usage to enable builds to complete +# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56746#c7 +# the "proper" way does not work currently: +#export CXXFLAGS="$(CXXFLAGS) --param ftrack-macro-expansion=0" +CUSTOMFLAGS="-ftrack-macro-expansion=0" + +echo "**** Building OF core ****" +cd $ROOT +# this carries over to subsequent compilations of examples +echo "PLATFORM_CFLAGS += $CUSTOMFLAGS" >> libs/openFrameworksCompiled/project/linux64/config.linux64.default.mk +sed -i "s/PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = .*/PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -g0/" libs/openFrameworksCompiled/project/makefileCommon/config.linux.common.mk +cd libs/openFrameworksCompiled/project +make Debug + +echo "**** Building emptyExample ****" +cd $ROOT/scripts/templates/linux64 +make Debug + +echo "**** Building allAddonsExample ****" +cd $ROOT +cp scripts/templates/linux64/Makefile examples/addons/allAddonsExample/ +cp scripts/templates/linux64/config.make examples/addons/allAddonsExample/ +cd examples/addons/allAddonsExample/ +make Debug diff --git a/scripts/ci/linux/install.sh b/scripts/ci/linux/install.sh new file mode 100755 index 00000000000..2baed5b2c13 --- /dev/null +++ b/scripts/ci/linux/install.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} + +# Trusty/14.04 builds don't have databases running - disable this +# echo "Memory usage debugging output" +# ps aux --sort -rss | head -n10 +# echo "Stop services started by default to save memory on Travis" +# # use sudo /etc/init.d/foo stop instead of sudo service foo stop because that +# # fails on travis sometimes, see http://stackoverflow.com/a/27410479/599884 +# # maybe works consistently on 14.04 +# sudo service mysql stop +# sudo service postgresql stop + +sudo $ROOT/scripts/linux/ubuntu/install_dependencies.sh -y; diff --git a/scripts/ci/linux/run_tests.sh b/scripts/ci/linux/run_tests.sh new file mode 100755 index 00000000000..13e2fcc4ac6 --- /dev/null +++ b/scripts/ci/linux/run_tests.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} + +echo "**** Running unit tests ****" +cd $ROOT/tests +for group in *; do + if [ -d $group ]; then + for test in $group/*; do + if [ -d $test ]; then + cd $test + cp ../../../scripts/templates/linux/Makefile . + cp ../../../scripts/templates/linux/config.make . + make Debug + cd bin + binname=$(basename ${test}) + gdb -batch -ex "run" -ex "bt" -ex "q \$_exitcode" ./${binname}_debug + errorcode=$? + if [[ $errorcode -ne 0 ]]; then + exit $errorcode + fi + cd $ROOT/tests + fi + done + fi +done diff --git a/scripts/ci/osx/build.sh b/scripts/ci/osx/build.sh new file mode 100755 index 00000000000..2ef5ccd3da2 --- /dev/null +++ b/scripts/ci/osx/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} +echo "**** Building oF + emptyExample - OSX Template Project ****" +xcodebuild -configuration Release -target emptyExample -project "$ROOT/scripts/templates/osx/emptyExample.xcodeproj" + +echo "**** Building allAddonsExample ****" +cd $ROOT +cp scripts/templates/osx/Makefile examples/addons/allAddonsExample/ +cp scripts/templates/osx/config.make examples/addons/allAddonsExample/ +cd examples/addons/allAddonsExample/ +make Debug diff --git a/scripts/ci/osx/install.sh b/scripts/ci/osx/install.sh new file mode 100755 index 00000000000..093ef8757c4 --- /dev/null +++ b/scripts/ci/osx/install.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -ev +brew update +brew install gdb diff --git a/scripts/ci/osx/run_tests.sh b/scripts/ci/osx/run_tests.sh new file mode 100755 index 00000000000..85f73cf070c --- /dev/null +++ b/scripts/ci/osx/run_tests.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -ev +ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../../.." ; pwd -P )"} + +trap 'for f in ~/Library/Logs/DiagnosticReports/*; do cat $f; done' 11 + +echo "**** Running unit tests ****" +cd $ROOT/tests +for group in *; do + if [ -d $group ]; then + for test in $group/*; do + if [ -d $test ]; then + cd $test + cp ../../../scripts/templates/osx/Makefile . + cp ../../../scripts/templates/osx/config.make . + make Debug + binname=$(basename ${test}) + + if [ "${test}" == "networkTcp" ] || [ "${test}" == "networkUdp" ]; then + counter=0 + errorcode=1 + while [ $counter -lt 5 ] && [ $errorcode -ne 0 ] + do + cd bin/${binname}_debug.app/Contents/MacOS/ + sudo gdb -batch -ex "run" -ex "bt" -ex "q \$_exitcode" ./${binname}_debug + errorcode=$? + counter=$[$counter +1] + done + if [[ $errorcode -ne 0 ]]; then + exit $errorcode + fi + else + cd bin/${binname}_debug.app/Contents/MacOS/ + sudo gdb -batch -ex "run" -ex "bt" -ex "q \$_exitcode" ./${binname}_debug + errorcode=$? + if [[ $errorcode -ne 0 ]]; then + exit $errorcode + fi + fi + cd $ROOT/tests + fi + done + fi +done diff --git a/scripts/ci/vs/run_tests.bat b/scripts/ci/vs/run_tests.bat new file mode 100644 index 00000000000..46c36edb20b --- /dev/null +++ b/scripts/ci/vs/run_tests.bat @@ -0,0 +1,24 @@ +cd %APPVEYOR_BUILD_FOLDER%\tests +set TESTS_PLATFORM=%PLATFORM% +set STATUS=0 +if "%PLATFORM%" equ "x86" set TESTS_PLATFORM=Win32 +FOR /D %%G IN (*) DO ( + echo %APPVEYOR_BUILD_FOLDER%\tests\%%G + cd %APPVEYOR_BUILD_FOLDER%\tests\%%G + FOR /D %%E IN (*) DO ( + echo %APPVEYOR_BUILD_FOLDER%\tests\%%G\%%E + cd %APPVEYOR_BUILD_FOLDER%\tests\%%G\%%E + msbuild %%E.sln /p:Configuration=Debug /p:Platform=%TESTS_PLATFORM% + if ERRORLEVEL 1 ( + appveyor AddTest -Name %%E -Framework ofxUnitTests -FileName %%E.sln -Outcome Failed -Duration 0 -StdOut "Error compiling" + SET STATUS=1 + ) else ( + cd bin + %%E_debug.exe + if ERRORLEVEL 1 echo "Finished with error" & SET STATUS=1 + ) + ) +) +cd .. +echo "Tests finished with status %STATUS%" +exit /B %STATUS% diff --git a/scripts/dev/create_package.sh b/scripts/dev/create_package.sh index 60ea73812af..df5748a5b84 100755 --- a/scripts/dev/create_package.sh +++ b/scripts/dev/create_package.sh @@ -1,9 +1,16 @@ #!/bin/bash -# $1 -> platform: win_cb, linux, linux64, vs, osx, ios, all +# $1 -> platform: msys2, linux, linux64, vs, osx, ios, all # $2 -> version number: 006 +# +# This script removes folders clones the openFrameworks repo +# and deletes parts of it to create the final package. +# Do not try to modify it to run over your local install of +# openFrameworks or it'll remove it along with any projects it +# might contain. platform=$1 version=$2 +of_root=$(readlink -f "$(dirname "$(readlink -f "$0")")/../..") if [ $# -eq 3 ]; then branch=$3 @@ -11,21 +18,21 @@ else branch=stable fi -REPO=https://github.com/openframeworks/openFrameworks -REPO_ALIAS=upstreamhttps +REPO=../.. +REPO_ALIAS=originlocal BRANCH=$branch -PG_REPO=https://github.com/ofZach/projectGeneratorSimple.git +PG_REPO=https://github.com/openframeworks/projectGenerator.git PG_REPO_ALIAS=originhttps PG_BRANCH=master hostArch=`uname` -if [ "$platform" != "win_cb" ] && [ "$platform" != "linux" ] && [ "$platform" != "linux64" ] && [ "$platform" != "linuxarmv6l" ] && [ "$platform" != "linuxarmv7l" ] && [ "$platform" != "vs" ] && [ "$platform" != "osx" ] && [ "$platform" != "android" ] && [ "$platform" != "ios" ] && [ "$platform" != "all" ]; then +if [ "$platform" != "msys2" ] && [ "$platform" != "linux" ] && [ "$platform" != "linux64" ] && [ "$platform" != "linuxarmv6l" ] && [ "$platform" != "linuxarmv7l" ] && [ "$platform" != "vs" ] && [ "$platform" != "osx" ] && [ "$platform" != "android" ] && [ "$platform" != "ios" ]; then echo usage: echo ./create_package.sh platform version echo platform: - echo win_cb, linux, linux64, linuxarmv6l, linuxarmv7l, vs, osx, android, ios, all + echo msys2, linux, linux64, linuxarmv6l, linuxarmv7l, vs, osx, android, ios, all exit 1 fi @@ -33,34 +40,57 @@ if [ "$version" == "" ]; then echo usage: echo ./create_package.sh platform version [branch] echo platform: - echo win_cb, linux, linux64, vs, osx, android, ios, all + echo msys2, linux, linux64, vs, osx, android, ios, all echo echo branch: echo master, stable exit 1 fi - -libsnotinmac="unicap gstappsink glu quicktime videoInput kiss portaudio" -libsnotinlinux="quicktime videoInput glut glu cairo" -libsnotinwindows="unicap gstappsink kiss portaudio" -libsnotinandroid="glut unicap gstappsink quicktime videoInput fmodex glee rtAudio kiss portaudio cairo" -libsnotinios="glut unicap gstappsink quicktime videoInput fmodex glee rtAudio kiss portaudio cairo" - -rm -rf openFrameworks -git clone $REPO --depth=1 --branch=$BRANCH +echo +echo +echo +echo -------------------------------------------------------------------------- +echo "Creating package $version for $platform" +echo -------------------------------------------------------------------------- +echo + +libsnotinmac="glu quicktime videoInput kiss" +libsnotinlinux="quicktime videoInput glut glu cairo glew openssl rtAudio" +libsnotinvs="kiss" +libsnotinmingw="kiss glut cairo glew openssl" +libsnotinandroid="glut quicktime videoInput fmodex glee rtAudio kiss cairo" +libsnotinios="glut quicktime videoInput fmodex glee rtAudio kiss cairo" + +# This script removes folders clones the openFrameworks repo +# and deletes parts of it to create the final package. +# Do not try to modify it to run over your local install of +# openFrameworks or it'll remove it along with any projects it +# might contain. +# Instead we download it in a folder with a different name so it's +# safe to delete it completely at the end +pkgfolder=openFrameworks_pkg_creation + +rm -rf ${pkgfolder} +echo "Cloning OF from $REPO $BRANCH" +git clone $REPO --depth=1 --branch=$BRANCH ${pkgfolder} 2> /dev/null gitfinishedok=$? if [ $gitfinishedok -ne 0 ]; then echo "Error connecting to github" - exit + exit 1 fi - - -cd openFrameworks +cd ${pkgfolder} packageroot=$PWD -cd apps/projectGenerator/projectGeneratorSimple -git clone $PG_REPO --depth=1 --branch=$PG_BRANCH + +cd apps +echo "Cloning project generator from $PG_REPO $PG_BRANCH" +git clone $PG_REPO --depth=1 --branch=$PG_BRANCH 2> /dev/null +gitfinishedok=$? +if [ $gitfinishedok -ne 0 ]; then + echo "Error connecting to github" + exit 1 +fi cd $packageroot @@ -68,7 +98,6 @@ cd $packageroot function deleteCodeblocks { #delete codeblock files rm *.cbp - rm *.sh rm *.workspace } @@ -100,25 +129,45 @@ function deleteEclipse { function createProjectFiles { - projectGenerator --allexamples --${pkg_platform} + if [ "$pkg_platform" != "android" ] && [ "$pkg_platform" != "linuxarmv6l" ] && [ "$pkg_platform" != "linuxarmv7l" ]; then + cd ${main_ofroot}/apps/projectGenerator + git pull origin master + cd commandLine + echo "Recompiling command line PG" + PROJECT_OPTIMIZATION_CFLAGS_RELEASE=-O3 make -j2 > /dev/null + cd ${pkg_ofroot} + echo "Creating project files for $pkg_platform" + ${main_ofroot}/apps/projectGenerator/commandLine/bin/projectGenerator --recursive -p${pkg_platform} -o$pkg_ofroot $pkg_ofroot/examples > /dev/null + elif [ "$pkg_platform" == "linuxarmv6l" ] || [ "$pkg_platform" == "linuxarmv7l" ]; then + for example_group in $pkg_ofroot/examples/*; do + for example in $example_group/*; do + if [ -d $example ]; then + cp $pkg_ofroot/scripts/templates/linux/Makefile $example/ + cp $pkg_ofroot/scripts/templates/linux/config.make $example/ + fi + done + done + fi + cd ${pkg_ofroot} } function createPackage { pkg_platform=$1 pkg_version=$2 pkg_ofroot=$3 + main_ofroot=$4 #remove previously created package cd $pkg_ofroot/.. rm -Rf of_v${pkg_version}_${pkg_platform}.* rm -Rf of_v${pkg_version}_${pkg_platform}_* - echo "creating package $pkg_platform $version in $pkg_ofroot" + echo "Creating package $pkg_platform $version in $pkg_ofroot" #remove devApps folder rm -r $pkg_ofroot/apps/devApps #remove projectGenerator folder - if [ "$pkg_platform" != "linux" ] && [ "$pkg_platform" != "linux64" ]; then + if [ "$pkg_platform" = "android" ] || [ "$pkg_platform" = "msys2" ]; then rm -rf $pkg_ofroot/apps/projectGenerator fi @@ -178,7 +227,12 @@ function createPackage { rm -Rf gl/gpuParticleSystemExample rm -Rf gl/vboMeshDrawInstancedExample rm -Rf gl/shaderExample - + rm -Rf gl/computeShaderParticlesExample + rm -Rf gl/computeShaderTextureExample + rm -Rf gl/pixelBufferExample + rm -Rf gl/textureBufferInstancedExample + rm -Rf gl/threadedPixelBufferExample + rm -Rf utils/systemSpeakExample rm -Rf utils/fileBufferLoadingCSVExample @@ -190,7 +244,7 @@ function createPackage { rm -Rf utils/fileOpenSaveDialogExample fi - if [ "$pkg_platform" == "win_cb" ] || [ "$pkg_platform" == "vs" ]; then + if [ "$pkg_platform" == "msys2" ] || [ "$pkg_platform" == "vs" ]; then rm -Rf video/osxHighPerformanceVideoPlayerExample rm -Rf video/osxVideoRecorderExample rm -Rf gles @@ -198,6 +252,8 @@ function createPackage { if [ "$pkg_platform" == "osx" ]; then rm -Rf gles + rm -Rf gl/computeShaderParticlesExample + rm -Rf gl/computeShaderTextureExample fi @@ -213,99 +269,134 @@ function createPackage { #delete other platform libraries if [ "$pkg_platform" = "linux" ]; then - otherplatforms="linux64 linuxarmv6l linuxarmv7l osx win_cb vs ios android" + otherplatforms="linux64 linuxarmv6l linuxarmv7l osx msys2 vs ios android" fi if [ "$pkg_platform" = "linux64" ]; then - otherplatforms="linux linuxarmv6l linuxarmv7l osx win_cb vs ios android" + otherplatforms="linux linuxarmv6l linuxarmv7l osx msys2 vs ios android" fi if [ "$pkg_platform" = "linuxarmv6l" ]; then - otherplatforms="linux64 linux linuxarmv7l osx win_cb vs ios android" + otherplatforms="linux64 linux linuxarmv7l osx msys2 vs ios android" fi if [ "$pkg_platform" = "linuxarmv7l" ]; then - otherplatforms="linux64 linux linuxarmv6l osx win_cb vs ios android" + otherplatforms="linux64 linux linuxarmv6l osx msys2 vs ios android" fi if [ "$pkg_platform" = "osx" ]; then - otherplatforms="linux linux64 linuxarmv6l linuxarmv7l win_cb vs ios android" + otherplatforms="linux linux64 linuxarmv6l linuxarmv7l msys2 vs ios android" fi - if [ "$pkg_platform" = "win_cb" ]; then - otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx vs ios android makefileCommon" + if [ "$pkg_platform" = "msys2" ]; then + otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx vs ios android" fi if [ "$pkg_platform" = "vs" ]; then - otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx win_cb ios android makefileCommon" + otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx msys2 ios android" fi if [ "$pkg_platform" = "ios" ]; then - otherplatforms="linux linux64 linuxarmv6l linuxarmv7l win_cb vs android makefileCommon" + otherplatforms="linux linux64 linuxarmv6l linuxarmv7l msys2 vs android" fi if [ "$pkg_platform" = "android" ]; then - otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx win_cb vs ios" + otherplatforms="linux linux64 linuxarmv6l linuxarmv7l osx msys2 vs ios" fi #download and uncompress PG - cd $pkg_ofroot - rm -rf projectGenerator - if [ "$pkg_platform" = "win_cb" ]; then - rm projectGenerator_wincb.zip - wget http://www.openframeworks.cc/pgSimple/projectGenerator_wincb.zip - unzip projectGenerator_wincb.zip - rm projectGenerator_wincb.zip - rm -Rf __MACOSX - fi + echo "Creating projectGenerator" + mkdir -p $HOME/.tmp + export TMPDIR=$HOME/.tmp if [ "$pkg_platform" = "vs" ]; then - rm projectGenerator_winvs.zip - wget http://www.openframeworks.cc/pgSimple/projectGenerator_winvs.zip - unzip projectGenerator_winvs.zip - rm projectGenerator_winvs.zip - rm -Rf __MACOSX + cd ${pkg_ofroot}/apps/projectGenerator/frontend + npm install > /dev/null + npm run build:vs > /dev/null + mv dist/projectGenerator-win32-ia32 ${pkg_ofroot}/projectGenerator-vs + cd ${pkg_ofroot} + rm -rf apps/projectGenerator + cd ${pkg_ofroot}/projectGenerator-vs/resources/app/app/ + wget http://198.61.170.130/projectGenerator/projectGenerator-vs.zip 2> /dev/null + unzip projectGenerator-vs.zip 2> /dev/null + rm projectGenerator-vs.zip + cd ${pkg_ofroot} + sed -i "s/osx/vs/g" projectGenerator-vs/resources/app/settings.json fi if [ "$pkg_platform" = "osx" ]; then - rm projectGenerator_osx.zip - wget http://www.openframeworks.cc/pgSimple/projectGenerator_osx.zip - unzip projectGenerator_osx.zip - rm projectGenerator_osx.zip - rm -Rf __MACOSX + cd ${pkg_ofroot}/apps/projectGenerator/frontend + npm install > /dev/null + npm run build:osx > /dev/null + mv dist/projectGenerator-darwin-x64 ${pkg_ofroot}/projectGenerator-osx + cd ${pkg_ofroot} + rm -rf apps/projectGenerator + wget http://198.61.170.130/projectGenerator/projectGenerator_osx -O projectGenerator-osx/projectGenerator.app/Contents/Resources/app/app/projectGenerator 2> /dev/null + sed -i "s/osx/osx/g" projectGenerator-osx/projectGenerator.app/Contents/Resources/app/settings.json fi if [ "$pkg_platform" = "ios" ]; then - rm projectGenerator_ios.zip - wget http://www.openframeworks.cc/pgSimple/projectGenerator_ios.zip - unzip projectGenerator_ios.zip - rm projectGenerator_ios.zip - rm -Rf __MACOSX + cd ${pkg_ofroot}/apps/projectGenerator/frontend + npm install > /dev/null + npm run build:osx > /dev/null + mv dist/projectGenerator-darwin-x64 ${pkg_ofroot}/projectGenerator-ios + cd ${pkg_ofroot} + rm -rf apps/projectGenerator + wget http://198.61.170.130/projectGenerator/projectGenerator_osx -O projectGenerator-ios/projectGenerator.app/Contents/Resources/app/app/projectGenerator 2> /dev/null + sed -i "s/osx/ios/g" projectGenerator-ios/projectGenerator.app/Contents/Resources/app/settings.json + fi + + if [ "$pkg_platform" = "linux" ]; then + cd ${pkg_ofroot}/apps/projectGenerator/frontend + npm install > /dev/null + npm run build:linux32 > /dev/null + mv dist/projectGenerator-linux-ia32 ${pkg_ofroot}/projectGenerator-linux + cd ${pkg_ofroot} + sed -i "s/osx/linux/g" projectGenerator-linux/resources/app/settings.json + fi + + if [ "$pkg_platform" = "linux64" ]; then + cd ${pkg_ofroot}/apps/projectGenerator/frontend + npm install > /dev/null + npm run build:linux64 > /dev/null + mv dist/projectGenerator-linux-x64 ${pkg_ofroot}/projectGenerator-linux64 + cd ${pkg_ofroot} + sed -i "s/osx/linux64/g" projectGenerator-linux64/resources/app/settings.json fi # linux remove other platform projects from PG source and copy ofxGui if [ "$pkg_platform" = "linux" ] || [ "$pkg_platform" = "linux64" ] || [ "$pkg_platform" = "linuxarmv6l" ] || [ "$pkg_platform" = "linuxarmv7l" ]; then - cd apps/projectGenerator/projectGeneratorSimple + cd ${pkg_ofroot} + mv apps/projectGenerator/commandLine . + mv apps/projectGenerator/ofxProjectGenerator . + rm -rf apps/projectGenerator + mkdir apps/projectGenerator + mv commandLine apps/projectGenerator/ + mv ofxProjectGenerator apps/projectGenerator/ + cd apps/projectGenerator/commandLine deleteCodeblocks deleteVS deleteXcode - rm -Rf .git* fi #delete libraries for other platforms + echo "Deleting core libraries from other platforms" cd $pkg_ofroot/libs for lib in $( find . -maxdepth 1 -mindepth 1 -type d ) do - echo $PWD - echo deleting $lib/lib - cd $lib/lib - rm -Rf $otherplatforms - cd $pkg_ofroot/libs + if [ -d $lib/lib ]; then + #echo deleting $lib/lib + cd $lib/lib + rm -Rf $lib/lib/$otherplatforms + cd $pkg_ofroot/libs + fi done if [ "$pkg_platform" = "osx" ]; then rm -Rf $libsnotinmac elif [ "$pkg_platform" = "linux" ] || [ "$pkg_platform" = "linux64" ] || [ "$pkg_platform" = "linuxarmv6l" ] || [ "$pkg_platform" = "linuxarmv7l" ]; then rm -Rf $libsnotinlinux - elif [ "$pkg_platform" = "win_cb" ] || [ "$pkg_platform" = "vs" ]; then - rm -Rf $libsnotinwindows + elif [ "$pkg_platform" = "msys2" ]; then + rm -Rf $libsnotinmingw + elif [ "$pkg_platform" = "vs" ]; then + rm -Rf $libsnotinvs elif [ "$pkg_platform" = "android" ]; then rm -Rf $libsnotinandroid elif [ "$pkg_platform" = "ios" ]; then @@ -313,11 +404,11 @@ function createPackage { fi cd ${pkg_ofroot}/addons + echo "Deleting addon libraries from other platforms" for lib in $( ls -d */libs/*/lib/ ) do cd ${lib} - echo $PWD - echo deleting $lib + #echo deleting $lib rm -Rf $otherplatforms cd $pkg_ofroot/addons done @@ -325,29 +416,38 @@ function createPackage { #delete ofxAndroid in non android if [ "$pkg_platform" != "android" ]; then rm -Rf ofxAndroid + rm -Rf ofxUnitTests fi #delete ofxiPhone in non ios if [ "$pkg_platform" != "ios" ]; then rm -Rf ofxiPhone rm -Rf ofxiOS + rm -Rf ofxUnitTests fi #delete ofxMultiTouch & ofxAccelerometer in non mobile if [ "$pkg_platform" != "android" ] && [ "$pkg_platform" != "ios" ]; then rm -Rf ofxMultiTouch rm -Rf ofxAccelerometer + rm -Rf ofxUnitTests fi if [ "$pkg_platform" == "ios" ] || [ "$pkg_platform" == "android" ]; then rm -Rf ofxVectorGraphics rm -Rf ofxKinect + rm -Rf ofxUnitTests fi + + #delete unit tests by now + rm -Rf ${pkg_ofroot}/tests #delete eclipse projects if [ "$pkg_platform" != "android" ] && [ "$pkg_platform" != "linux" ] && [ "$pkg_platform" != "linux64" ] && [ "$pkg_platform" != "linuxarmv6l" ] && [ "$pkg_platform" != "linuxarmv7l" ]; then cd ${pkg_ofroot} deleteEclipse - rm -R libs/openFrameworks/.settings + if [ -f libs/openFrameworks/.settings ]; then + rm -R libs/openFrameworks/.settings + fi fi #android, move paths.default.make to paths.make @@ -371,12 +471,12 @@ function createPackage { cd ${pkg_ofroot}/libs #delete specific include folders non-android - if [ "$pkg_platform" != "android" ]; then + if [ "$pkg_platform" != "android" ] && [ -d */include_android ]; then rm -Rf $( ls -d */include_android ) fi #delete specific include folders for non-ios - if [ "$pkg_platform" != "ios" ]; then + if [ "$pkg_platform" != "ios" ] && [ -d */include_ios ]; then rm -Rf $( ls -d */include_ios ) fi @@ -388,17 +488,13 @@ function createPackage { #delete dynamic libraries for other platforms cd $pkg_ofroot/export rm -Rf $otherplatforms - if [ "$pkg_platform" = "osx" ]; then - cd $pkg_ofroot - rmdir export - fi #delete scripts cd $pkg_ofroot/scripts if [ "$pkg_platform" != "linux64" ] && [ "$pkg_platform" != "linuxarmv6l" ] && [ "$pkg_platform" != "linuxarmv7l" ]; then rm -Rf $otherplatforms else - rm -Rf win_cb vs osx ios + rm -Rf msys2 vs osx ios fi #delete omap4 scripts for non armv7l @@ -406,11 +502,6 @@ function createPackage { rm -Rf linux/ubuntu-omap4 fi - #delete armv6 scripts for non armv6l - if [ "$pkg_platform" = "linux64" ] || [ "$pkg_platform" = "linux" ] || [ "$pkg_platform" = "linuxarmv7l" ]; then - rm -Rf linux/debian_armv6l - fi - if [ "$pkg_platform" == "ios" ]; then rm -Rf osx fi @@ -432,23 +523,9 @@ function createPackage { if [ "$pkg_platform" != "osx" ] && [ "$pkg_platform" != "ios" ]; then rm -Rf "xcode templates" fi - - - #download and copy OF compiled - #cd $pkg_ofroot/libs/openFrameworksCompiled/lib/${pkg_platform} - #if [ "$pkg_platform" = "win_cb" ]; then - # wget http://openframeworks.cc/git_pkgs/OF_compiled/${pkg_platform}/openFrameworks.lib - # wget http://openframeworks.cc/git_pkgs/OF_compiled/${pkg_platform}/openFrameworksDebug.lib - #fi - - - #if snow leopard change 10.4u to 10.5 - #if [ $runOSXSLScript = 1 ]; then - # cd $pkg_ofroot - # echo "replacing 10.4u with 10.5 for snow leopard" - # find . -name '*.pbxproj' | xargs perl -pi -e 's/10\.4u/10\.5/g' - # pkg_platform="osxSL" - #fi + echo ---------------------------------------------------------------------- + echo + echo #choose readme cd $pkg_ofroot @@ -460,8 +537,8 @@ function createPackage { cp docs/visualstudio.md INSTALL.md fi - if [ "$platform" = "win_cb" ]; then - cp docs/codeblocks.md INSTALL.md + if [ "$platform" = "msys2" ]; then + cp docs/msys2.md INSTALL.md fi if [ "$platform" = "osx" ] || [ "$platform" = "ios" ]; then @@ -469,64 +546,66 @@ function createPackage { fi if [ "$platform" = "android" ]; then - cp docs/android.md INSTALL.md + cp docs/android_eclipse.md INSTALL_ECLIPSE.md + cp docs/android_studio.md INSTALL_ANDROID_STUDIO.md fi rm CONTRIBUTING.md #copy empty example - cd $pkg_ofroot/.. - mkdir -p openFrameworks/apps/myApps + cd $pkg_ofroot + mkdir -p apps/myApps if [ "$pkg_platform" = "android" ]; then - cp -r openFrameworks/examples/android/androidEmptyExample openFrameworks/apps/myApps + cp -r examples/android/androidEmptyExample apps/myApps/ elif [ "$pkg_platform" = "ios" ]; then - cp -r openFrameworks/examples/ios/emptyExample openFrameworks/apps/myApps + cp -r examples/ios/emptyExample apps/myApps/ else - cp -r openFrameworks/examples/empty/emptyExample openFrameworks/apps/myApps + cp -r examples/empty/emptyExample apps/myApps/ fi #create compressed package if [ "$pkg_platform" = "linux" ] || [ "$pkg_platform" = "linux64" ] || [ "$pkg_platform" = "android" ] || [ "$pkg_platform" = "linuxarmv6l" ] || [ "$pkg_platform" = "linuxarmv7l" ]; then + echo "compressing package to of_v${pkg_version}_${pkg_platform}_release.tar.gz" + cd $pkg_ofroot/.. mkdir of_v${pkg_version}_${pkg_platform}_release - mv openFrameworks/* of_v${pkg_version}_${pkg_platform}_release + mv ${pkgfolder}/* of_v${pkg_version}_${pkg_platform}_release COPYFILE_DISABLE=true tar czf of_v${pkg_version}_${pkg_platform}_release.tar.gz of_v${pkg_version}_${pkg_platform}_release rm -Rf of_v${pkg_version}_${pkg_platform}_release else + echo "compressing package to of_v${pkg_version}_${pkg_platform}_release.zip" + cd $pkg_ofroot/.. mkdir of_v${pkg_version}_${pkg_platform}_release - mv openFrameworks/* of_v${pkg_version}_${pkg_platform}_release - zip -r of_v${pkg_version}_${pkg_platform}_release.zip of_v${pkg_version}_${pkg_platform}_release > /dev/null - mv of_v${pkg_version}_${pkg_platform}_release of_v${pkg_version}_${pkg_platform}_release + mv ${pkgfolder}/* of_v${pkg_version}_${pkg_platform}_release + zip --symlinks -r of_v${pkg_version}_${pkg_platform}_release.zip of_v${pkg_version}_${pkg_platform}_release > /dev/null rm -Rf of_v${pkg_version}_${pkg_platform}_release fi } +set -o pipefail # trace ERR through pipes +set -o errtrace # trace ERR through 'time command' and other functions +set -o nounset # set -u : exit the script if you try to use an uninitialized variable +set -o errexit # set -e : exit the script if any statement returns a non-true return value -if [ "$platform" = "all" ]; then - for eachplatform in win_cb linux linux64 vs osx - do - cd $packageroot - mkdir of_v${version}_${eachplatform} - cp -R addons apps export libs other scripts of_v${version}_${eachplatform} - cd of_v${version}_${eachplatform} - createPackage $eachplatform $2 $PWD - done - - cd $packageroot - echo dir: $PWD - mkdir of_v${version}_all - mv addons apps export libs other scripts $packageroot/of_v${version}_all - COPYFILE_DISABLE=true tar czf of_v$version_all_FAT.tar.gz of_v${version}_all - rm -Rf of_v${version}_all - mv * $packageroot/.. - #rm -Rf $packageroot -else - of_root=$(cat ~/.ofprojectgenerator/config) - echo $packageroot > ~/.ofprojectgenerator/config - createPackage $platform $version $packageroot - echo $of_root > ~/.ofprojectgenerator/config - -fi +cleanup() { + cd $packageroot/.. + rm -rf ${pkgfolder} +} +trap cleanup 0 + +error() { + local parent_lineno="$1" + if [[ "$#" = "3" ]] ; then + local message="$2" + local code="${3:-1}" + echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}" + else + local code="${2:-1}" + echo "Error on or near line ${parent_lineno}; exiting with status ${code}" + fi + exit "${code}" +} +trap 'error ${LINENO}' ERR +createPackage $platform $version $packageroot $of_root -cd $packageroot/.. -rm -rf openFrameworks + diff --git a/scripts/dev/documentation.sh b/scripts/dev/documentation.sh deleted file mode 100755 index a108abec1dd..00000000000 --- a/scripts/dev/documentation.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -## This script is to build the OpenFrameworks documentation automatically -echo "Current Branch: $TRAVIS_BRANCH" -### Only build documentation on the master branch. -if [ "$TRAVIS_BRANCH" == "master" ]; then - if [ "$1" == "before_install" ]; then - if [[ $TRAVIS_PULL_REQUEST == "false" ]]; then - echo "Documentation Before Install" - brew update - brew install Caskroom/cask/libreoffice; - brew install doxygen; - brew install ncftp; - gem install sass --version "=3.2.12"; - gem install compass --version "=0.12.2"; - fi - elif [ "$1" == "script" ]; then - if [[ $TRAVIS_PULL_REQUEST == "false" ]]; then - echo "Documentation Building" - cd scripts/; - git clone https://github.com/halfdanJ/ofDocGenerator; - cd ofDocGenerator; - npm install; - npm run start; - fi - elif [ "$1" == "after_success" ]; then - echo "Uploading to FTP" - if [[ $TRAVIS_PULL_REQUEST == "false" && $FTP_USER ]]; then - ncftpput -R -v -u $FTP_USER -p $FTP_PASSWORD 104.130.212.175 / output/*; - fi - fi -fi diff --git a/scripts/dev/head.template b/scripts/dev/head.template index 80b156b1408..1f5b9537485 100644 --- a/scripts/dev/head.template +++ b/scripts/dev/head.template @@ -1,22 +1,5 @@ openFrameworks - - - - - - - - - + - - - - - - - - - diff --git a/scripts/dev/nightlybuilds.sh b/scripts/dev/nightlybuilds.sh index 46a75bb8b0b..4596939b075 100755 --- a/scripts/dev/nightlybuilds.sh +++ b/scripts/dev/nightlybuilds.sh @@ -1,4 +1,33 @@ #!/bin/bash + +lastversion=$(date +%Y%m%d) +echo "Building nightly builds $lastversion" + +. $HOME/.profile + +set -o pipefail # trace ERR through pipes +set -o errtrace # trace ERR through 'time command' and other functions +set -o nounset # set -u : exit the script if you try to use an uninitialized variable +set -o errexit # set -e : exit the script if any statement returns a non-true return value + +error() { + local parent_lineno="$1" + if [[ "$#" = "3" ]] ; then + local message="$2" + local code="${3:-1}" + echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}" + else + local code="${2:-1}" + echo "Error on or near line ${parent_lineno}; exiting with status ${code}" + fi + rm -f *.tar.gz + rm -f *.zip + exit "${code}" +} +trap 'error ${LINENO}' ERR + +touch lasthash.txt +export PG_OF_PATH=$(cat ~/.ofprojectgenerator/config) cd $(cat ~/.ofprojectgenerator/config) git fetch upstreamhttps git reset --hard upstreamhttps/master @@ -6,17 +35,14 @@ cd $(cat ~/.ofprojectgenerator/config)/scripts/dev lasthash=$(cat lasthash.txt) currenthash=$(git rev-parse HEAD) if [ "$currenthash" = "$lasthash" ]; then + echo "Exiting, no changes found" exit 0 fi -# delete older packages -rm /var/www/versions/nightly/of_v*_nightly.* - -lastversion=$(date +%Y%m%d) echo $currenthash>lasthash.txt ./create_package.sh linux $lastversion master ./create_package.sh linux64 $lastversion master -./create_package.sh win_cb $lastversion master +./create_package.sh msys2 $lastversion master ./create_package.sh vs $lastversion master ./create_package.sh ios $lastversion master ./create_package.sh osx $lastversion master @@ -24,31 +50,15 @@ echo $currenthash>lasthash.txt ./create_package.sh linuxarmv6l $lastversion master ./create_package.sh linuxarmv7l $lastversion master +# delete older packages +rm -f /var/www/versions/nightly/of_v*_nightly.* + mv *.tar.gz /var/www/versions/nightly mv *.zip /var/www/versions/nightly -rm /var/www/versions/nightly/of_latest_linux_release.tar.gz -rm /var/www/versions/nightly/of_latest_linux64_release.tar.gz -rm /var/www/versions/nightly/of_latest_win_cb_release.zip -rm /var/www/versions/nightly/of_latest_vs_release.zip -rm /var/www/versions/nightly/of_latest_ios_release.zip -rm /var/www/versions/nightly/of_latest_osx_release.zip -rm /var/www/versions/nightly/of_latest_android_release.tar.gz -rm /var/www/versions/nightly/of_latest_linuxarmv6l_release.tar.gz -rm /var/www/versions/nightly/of_latest_linuxarmv7l_release.tar.gz - -rm /var/www/versions/nightly/of_latest_linux_nightly.tar.gz -rm /var/www/versions/nightly/of_latest_linux64_nightly.tar.gz -rm /var/www/versions/nightly/of_latest_win_cb_nightly.zip -rm /var/www/versions/nightly/of_latest_vs_nightly.zip -rm /var/www/versions/nightly/of_latest_ios_nightly.zip -rm /var/www/versions/nightly/of_latest_osx_nightly.zip -rm /var/www/versions/nightly/of_latest_android_nightly.tar.gz -rm /var/www/versions/nightly/of_latest_linuxarmv6l_nightly.tar.gz -rm /var/www/versions/nightly/of_latest_linuxarmv7l_nightly.tar.gz mv /var/www/versions/nightly/of_v${lastversion}_linux_release.tar.gz /var/www/versions/nightly/of_v${lastversion}_linux_nightly.tar.gz mv /var/www/versions/nightly/of_v${lastversion}_linux64_release.tar.gz /var/www/versions/nightly/of_v${lastversion}_linux64_nightly.tar.gz -mv /var/www/versions/nightly/of_v${lastversion}_win_cb_release.zip /var/www/versions/nightly/of_v${lastversion}_win_cb_nightly.zip +mv /var/www/versions/nightly/of_v${lastversion}_msys2_release.zip /var/www/versions/nightly/of_v${lastversion}_msys2_nightly.zip mv /var/www/versions/nightly/of_v${lastversion}_vs_release.zip /var/www/versions/nightly/of_v${lastversion}_vs_nightly.zip mv /var/www/versions/nightly/of_v${lastversion}_ios_release.zip /var/www/versions/nightly/of_v${lastversion}_ios_nightly.zip mv /var/www/versions/nightly/of_v${lastversion}_osx_release.zip /var/www/versions/nightly/of_v${lastversion}_osx_nightly.zip @@ -78,3 +88,8 @@ echo '' >> /var/www/nightlybuilds.html echo '' >> /var/www/nightlybuilds.html #wget http://openframeworks.cc/nightly_hook.php?version=${lastversion} -O /dev/null + +echo +echo +echo "Successfully created nightly builds for ${lastversion}" +echo diff --git a/scripts/dev/nightlybuilds.template b/scripts/dev/nightlybuilds.template index 2fc577f8250..f1043577d0b 100644 --- a/scripts/dev/nightlybuilds.template +++ b/scripts/dev/nightlybuilds.template @@ -1,2 +1,2 @@

    nightly builds

    -

    Here you can find a daily build of the master branch of openFrameworks. This downloads can be unstable.

    +

    Here you can find a daily build of the master branch of openFrameworks. Note: these downloads can be unstable.

    diff --git a/scripts/dev/release.sh b/scripts/dev/release.sh index 3ef07578927..2ce3ecd6332 100755 --- a/scripts/dev/release.sh +++ b/scripts/dev/release.sh @@ -1,17 +1,42 @@ #!/bin/bash + +. $HOME/.profile + +set -o pipefail # trace ERR through pipes +set -o errtrace # trace ERR through 'time command' and other functions +set -o nounset # set -u : exit the script if you try to use an uninitialized variable +set -o errexit # set -e : exit the script if any statement returns a non-true return value + +error() { + local parent_lineno="$1" + if [[ "$#" = "3" ]] ; then + local message="$2" + local code="${3:-1}" + echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}" + else + local code="${2:-1}" + echo "Error on or near line ${parent_lineno}; exiting with status ${code}" + fi + rm -f *.tar.gz + rm -f *.zip + exit "${code}" +} +trap 'error ${LINENO}' ERR + + version=$1 cd $(cat ~/.ofprojectgenerator/config)/scripts/dev -./create_package.sh linux $version -./create_package.sh linux64 $version -./create_package.sh linuxarmv6l $version -./create_package.sh linuxarmv7l $version -./create_package.sh win_cb $version -./create_package.sh vs $version -./create_package.sh ios $version -./create_package.sh osx $version -./create_package.sh android $version -mkdir /var/www/versions/v${version} +./create_package.sh linux $version master +./create_package.sh linux64 $version master +./create_package.sh linuxarmv6l $version master +./create_package.sh linuxarmv7l $version master +./create_package.sh msys2 $version master +./create_package.sh vs $version master +./create_package.sh ios $version master +./create_package.sh osx $version master +./create_package.sh android $version master +mkdir -p /var/www/versions/v${version} mv *.tar.gz /var/www/versions/v${version} mv *.zip /var/www/versions/v${version} diff --git a/scripts/ios/testTemplate.sh b/scripts/ios/testTemplate.sh deleted file mode 100755 index 32fdd6395de..00000000000 --- a/scripts/ios/testTemplate.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -e -if [ "$SCRIPT_PATH" == "" ]; then SCRIPT_PATH="."; fi -echo "Looking for iOS Template Project" -if [ ! -d "$SCRIPT_PATH/template/bin/emptyExample.app" ]; then - echo "---------------------------------" - if [ ! -e "$SCRIPT_PATH/template/emptyExample.xcodeproj" ]; then - echo "No Xcode project found for emptyExample" - exit 1; - fi - echo "Building openFrameworks - iOS Template Project" - xcodebuild -project "$SCRIPT_PATH/template/emptyExample.xcodeproj" -target emptyExample -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO - ret=$? - if [ $ret -ne 0 ]; then - echo "Failed building emptyExample" - exit 1 - fi - echo "---------------------------------" -fi diff --git a/scripts/linux/archlinux/install_codeblocks.sh b/scripts/linux/archlinux/install_codeblocks.sh deleted file mode 100755 index dee7fac137f..00000000000 --- a/scripts/linux/archlinux/install_codeblocks.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -pacman -Sy --needed codeblocks xterm - diff --git a/scripts/linux/archlinux/install_dependencies.sh b/scripts/linux/archlinux/install_dependencies.sh index 1e08d2d6214..d4fc0aa9e08 100755 --- a/scripts/linux/archlinux/install_dependencies.sh +++ b/scripts/linux/archlinux/install_dependencies.sh @@ -10,10 +10,39 @@ if [ $EUID != 0 ]; then exit 1 fi -pacman -Sy --needed make pkg-config gcc openal python-lxml glew freeglut freeimage gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-libav opencv libxcursor rtaudio assimp boost +pacman -Sy --needed make pkg-config gcc openal python-lxml glew freeglut freeimage gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-libav opencv libxcursor assimp boost exit_code=$? if [ $exit_code != 0 ]; then echo "error installing packages, there could be an error with your internet connection" exit $exit_code fi + +echo "" +echo "" +echo "NOTE FOR RTAUDIO" +echo "=====================" +echo "OpenFramworks requires rtaudio. This package is not in the official repositories and has to be installed via aur. https://aur.archlinux.org/packages/rtaudio/ You can do it manually or use an aur helper like yaourt to do it for you." +echo "" +read -p "Press any key to continue... " -n1 -s + +export LC_ALL=C +GCC_MAJOR_GT_4=$(expr `gcc -dumpversion | cut -f1 -d.` \> 4) +if [ $GCC_MAJOR_GT_4 -eq 1 ]; then + echo + echo + echo "It seems you are running gcc 5 or later, due to incomatible ABI with previous versions" + echo "we need to recompile poco. This will take a while" + read -p "Press any key to continue... " -n1 -s + + sys_cores=$(getconf _NPROCESSORS_ONLN) + if [ $sys_cores -gt 1 ]; then + cores=$(($sys_cores-1)) + else + cores=1 + fi + + DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + cd ${DIR}/../../apothecary + ./apothecary -j${cores} update poco +fi diff --git a/scripts/linux/archlinux/remove_codeblocks.sh b/scripts/linux/archlinux/remove_codeblocks.sh deleted file mode 100755 index 8201d744ee1..00000000000 --- a/scripts/linux/archlinux/remove_codeblocks.sh +++ /dev/null @@ -1 +0,0 @@ -pacman -Rs codeblocks diff --git a/scripts/linux/archlinux_armv6/install_dependencies.sh b/scripts/linux/archlinux_armv6/install_dependencies.sh index 1718904bc34..3d5abc27b9b 100644 --- a/scripts/linux/archlinux_armv6/install_dependencies.sh +++ b/scripts/linux/archlinux_armv6/install_dependencies.sh @@ -17,3 +17,24 @@ if [ $exit_code != 0 ]; then echo "error installing packages, there could be an error with your internet connection" exit $exit_code fi + +export LC_ALL=C +GCC_MAJOR_GT_4=$(expr `gcc -dumpversion | cut -f1 -d.` \> 4) +if [ $GCC_MAJOR_GT_4 -eq 1 ]; then + echo + echo + echo "It seems you are running gcc 5 or later, due to incomatible ABI with previous versions" + echo "we need to recompile poco. This will take a while" + read -p "Press any key to continue... " -n1 -s + + sys_cores=$(getconf _NPROCESSORS_ONLN) + if [ $sys_cores -gt 1 ]; then + cores=$(($sys_cores-1)) + else + cores=1 + fi + + DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + cd ${DIR}/../../apothecary + ./apothecary -j${cores} update poco +fi diff --git a/scripts/linux/buildAllExamples.sh b/scripts/linux/buildAllExamples.sh index 1bd48f64548..1e7851a3b62 100755 --- a/scripts/linux/buildAllExamples.sh +++ b/scripts/linux/buildAllExamples.sh @@ -5,34 +5,34 @@ export LC_ALL=C for category in $( find ../../examples/ -maxdepth 1 -type d ) do if [ "$category" = "../../examples/android" -o "$category" = "../../examples/ios" -o "$category" = "../../examples/" ]; then - continue + continue fi - + echo category $category - for example in $( find $category -maxdepth 1 -type d | grep -v osx ) - do - if [ "$example" = "$category" ]; then - continue + for example in $( find "$category" -maxdepth 1 -type d | grep -v osx ) + do + if [ "$example" = "$category" ]; then + continue fi - echo "-----------------------------------------------------------------" - echo "building " + $example - - #projectGenerator . - make Debug -j2 -C $example + echo ----------------------------------------------------------------- + echo building $example + + #projectGenerator . + make Debug -j2 -C "$example" ret=$? if [ $ret -ne 0 ]; then - echo error compiling $example - exit + echo error compiling $example + exit fi - make Release -j2 -C $example + make Release -j2 -C "$example" ret=$? if [ $ret -ne 0 ]; then - echo error compiling $example - exit + echo error compiling $example + exit fi - - echo "-----------------------------------------------------------------" - echo "" + + echo ----------------------------------------------------------------- + echo done done diff --git a/scripts/linux/buildAllRPIExamples.sh b/scripts/linux/buildAllRPIExamples.sh index 06a9699a6f8..5b602c1ad43 100755 --- a/scripts/linux/buildAllRPIExamples.sh +++ b/scripts/linux/buildAllRPIExamples.sh @@ -1,26 +1,29 @@ -cd ../../examples +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PARENT_DIR="$(dirname "$DIR")" +MAKEFILE_PATH=$PARENT_DIR/templates/linuxarmv6l/Makefile +cd ${DIR}/../../examples + for category in $(ls -1d *) do - if [ $category != "addons" ] && [ $category != "ios" ] && [ $category != "android" ]; then + if [ $category != "addons" ] && [ $category != "ios" ] && [ $category != "android" ]; then - echo "CHANGED TO CATEGORY >"+$category - cd $category - for j in $(ls -1d *) - do - echo ">>$j" - cd $j - cp ../../../scripts/linux/template/linuxarmv6l/Makefile . - make clean - make - ret=$? - if [ $ret -ne 0 ]; - then - echo "error compiling: " + $example - else - echo "successfully compiled :" + $example - fi - cd ../ - done - cd ../ - fi + echo "CHANGED TO CATEGORY >"+$category + cd $category + for j in $(ls -1d *) + do + echo ">>$j" + cd $j +# make clean -f $MAKEFILE_PATH + make -f $MAKEFILE_PATH + ret=$? + if [ $ret -ne 0 ]; + then + echo "error compiling: " + $j + else + echo "successfully compiled :" + $j + fi + cd ../ + done + cd ../ + fi done diff --git a/scripts/linux/cleanAllExamples.sh b/scripts/linux/cleanAllExamples.sh index b525d1a6be4..11f1ee922f2 100755 --- a/scripts/linux/cleanAllExamples.sh +++ b/scripts/linux/cleanAllExamples.sh @@ -3,25 +3,54 @@ for category in $( find ../../examples/ -maxdepth 1 -type d ) do if [ "$category" = "../../examples/android" -o "$category" = "../../examples/ios" -o "$category" = "../../examples/" ]; then - continue + continue fi - - for example in $( find $category -maxdepth 1 -type d | grep -v osx ) + + for example in $( find "$category" -maxdepth 1 -type d | grep -v osx ) + do + if [ "$example" = "$category" ]; then + continue + fi + echo ----------------------------------------------------------------- + echo cleaning "$example" + + make clean -C "$example" + rm -rf "${example:?}/obj" 2> /dev/null + rm -rf "${example:?}/"*.layout 2> /dev/null + rm -rf "${example:?}/"*.backup 2> /dev/null + rm -rf "${example:?}/"*.depend 2> /dev/null + rm "${example:?}/"*~ 2> /dev/null + if [ -f ${example}.qbs ]; then + qbs clean + fi + rm "{example:?}/"*.qbs 2> /dev/null + echo ----------------------------------------------------------------- + echo + done +done + +for category in $( find ../../apps/ -maxdepth 1 -type d ) +do + for example in $( find "$category" -maxdepth 1 -type d | grep -v osx ) do - if [ "$example" = "$category" ]; then - continue - fi - echo "-----------------------------------------------------------------" - echo "cleaning " + $example - - make clean -C $example - rm -rf $example/obj 2> /dev/null - rm -rf $example/*.layout 2> /dev/null - rm -rf $example/*.backup 2> /dev/null - rm -rf $example/*.depend 2> /dev/null - rm $example/*~ 2> /dev/null - - echo "-----------------------------------------------------------------" - echo "" + if [ "$example" = "$category" ]; then + continue + fi + echo ----------------------------------------------------------------- + echo cleaning "$example" + + make clean -C "$example" + rm -rf "${example:?}/obj" 2> /dev/null + rm -rf "${example:?}/"*.layout 2> /dev/null + rm -rf "${example:?}/"*.backup 2> /dev/null + rm -rf "${example:?}/"*.depend 2> /dev/null + rm "${example:?}/"*~ 2> /dev/null + if [ -f ${example}.qbs ]; then + qbs clean + fi + rm "{example:?}/"*.qbs 2> /dev/null + + echo ----------------------------------------------------------------- + echo done done diff --git a/scripts/linux/codeblocks_wizard/README.txt b/scripts/linux/codeblocks_wizard/README.txt deleted file mode 100644 index c0c225554c3..00000000000 --- a/scripts/linux/codeblocks_wizard/README.txt +++ /dev/null @@ -1,17 +0,0 @@ - -CODEBLOCKS WIZARD FOR LINUX INSTALLATION INSTRUCTIONS ------------------------------------------------------ -Copy the openframeworks folder in this directory to /usr/share/codeblocks/templates/wizard, or alternatively to /usr/local/share/codeblocks/templates/wizard if you have compiled codeblocks from source. -i.e. if you are in the same directory as this README do the following: - -cp -r ./openframeworks ~/.codeblocks/share/codeblocks/templates/wizard - -then edit the file ~/.codeblocks/share/codeblocks/templates/wizard/config.script and add the following line: -RegisterWizard(wizCustom, _T("openframeworks"), _T("OpenFrameworks"), _T("2D/3D Graphics")); - - -The Wizard is now installed. To use it, select File->New->Custom and select the OpenFrameworks template. -Then fill in your project details (Project name and Project directory). -Note that you must create your project in the same directory where you installed openFrameworks. -The projects should be created in a folder inside the apps directory, such as "myApps". - diff --git a/scripts/linux/codeblocks_wizard/openframeworks/logo.png b/scripts/linux/codeblocks_wizard/openframeworks/logo.png deleted file mode 100644 index a0e09c78dba..00000000000 Binary files a/scripts/linux/codeblocks_wizard/openframeworks/logo.png and /dev/null differ diff --git a/scripts/linux/codeblocks_wizard/openframeworks/wizard.png b/scripts/linux/codeblocks_wizard/openframeworks/wizard.png deleted file mode 100644 index b48f0cf391d..00000000000 Binary files a/scripts/linux/codeblocks_wizard/openframeworks/wizard.png and /dev/null differ diff --git a/scripts/linux/codeblocks_wizard/openframeworks/wizard.script b/scripts/linux/codeblocks_wizard/openframeworks/wizard.script deleted file mode 100644 index 772929f24ef..00000000000 --- a/scripts/linux/codeblocks_wizard/openframeworks/wizard.script +++ /dev/null @@ -1,106 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// openFrameworks wizard for Codeblocks on Linux -// Created By: Pierre Proske (http://www.digitalstar.net) -// Original Windows CB Wizard created by Roxlu (http://www.roxlu.com/) -// -//////////////////////////////////////////////////////////////////////////////// - -g_selected_addons <- ::wxArrayString(); -g_of_project_dir <- _T(""); -g_of_project_name <- _T(""); -g_of_path_default <- _T(""); -g_full_proj_path <- _T(""); -g_addons_string <- _T(""); - -function BeginWizard() -{ - local of_path_descr = _T("Please select the location of your openFrameworks application directory on your computer.\n" + - "This is the folder where your new app will be created.\n"); - - Wizard.AddPage(_T("ofProjectName")); - Wizard.AddGenericSelectPathPage(_T("OpenFrameworksPath"), of_path_descr, _T("Please select your application directory:"), g_of_path_default); - Wizard.AddPage(_T("ofAddons")); - - return true; - -} - -function OnLeave_ofAddons(forward) { - local of_addons_selection = Wizard.GetListboxStringSelections(_T("ofAddonsList")); - g_selected_addons = GetArrayFromString(of_addons_selection, _T(";"), false); - return true; -} - -function OnLeave_OpenFrameworksPath(bForward) -{ - if (bForward) - { - local dir = Wizard.GetTextControlValue(_T("txtFolder")); // txtFolder is the text control in GenericSelectPathPage - local dir_nomacro = VerifyDirectory(dir); - - if (dir_nomacro.IsEmpty()) - return false; - else { - g_of_project_dir = dir_nomacro; - } - - } - return true; -} - - -function OnLeave_ofProjectName(bForward) -{ - if (bForward) { - g_of_project_name = Wizard.GetTextControlValue(_T("ofProjName")); - } - return true; -} - -function SetupCustom() -{ - local proj = g_of_project_dir + _T("/") + g_of_project_name + _T("/") + g_of_project_name + _T(".cbp"); - local projdir = g_of_project_dir + _T("/"); - - // create project - g_full_proj_path = g_of_project_dir + _T("/") + g_of_project_name +_T("/"); - local commands_string = _T("projectGenerator ") + g_full_proj_path; - ShowMessage(commands_string); - - // add Addons - local addon_count = g_selected_addons.GetCount(); - - for(local i = 0; i < addon_count; i++) - { - local addon_name = g_selected_addons.Item(i); - g_addons_string = g_addons_string + addon_name + _T("\n"); - } - - // create addons.make file - if(addon_count > 0) { - IO.CreateDirectory(g_full_proj_path,0755); - IO.WriteFileContents(g_full_proj_path +_T("/addons.make"), g_addons_string); - } - - // create project - IO.Execute(commands_string); - - // load Project - if(GetProjectManager().LoadProject(proj,true) == 0) - { - ShowError(_T("project failed to load")); - } - -return true; -} - - - - - - - - - - diff --git a/scripts/linux/codeblocks_wizard/openframeworks/wizard.xrc b/scripts/linux/codeblocks_wizard/openframeworks/wizard.xrc deleted file mode 100644 index 0228ac7ada4..00000000000 --- a/scripts/linux/codeblocks_wizard/openframeworks/wizard.xrc +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - wxVERTICAL - - - - wxALL - 8 - - - - - - - - - wxALL - 0 - - - - - - - - wxALL|wxEXPAND - 0 - - myTestProject - 20 - - - - - - - - - - - wxVERTICAL - - - wxALL - 8 - - - - - - - - ofxXmlSettings - ofxOpenCv - ofxOsc - ofxThread - ofx3DUtils - ofx3DModelLoader - ofxAccelerometer - ofxAndroid - ofxAssimpModelLoader - ofxDirList - ofxMultiTouch - ofxNetwork - ofxThreadedImageLoader - ofxVectorGraphics - - - - wxALL|wxGROW - 8 - - - - - - - diff --git a/scripts/linux/compileOF.sh b/scripts/linux/compileOF.sh index f6fcd026a11..9af2565e915 100755 --- a/scripts/linux/compileOF.sh +++ b/scripts/linux/compileOF.sh @@ -17,15 +17,18 @@ SCRIPTPATH=`pwd` popd > /dev/null BUILD="install" -while getopts t opt ; do +JOBS=1 +while getopts tj: opt ; do case "$opt" in - t) # testing, only build Debug - BUILD="test" ;; + t) # testing, only build Debug + BUILD="test" ;; + j) # make job count for parallel build + JOBS="$OPTARG" esac done cd ${SCRIPTPATH}/../../libs/openFrameworksCompiled/project -make Debug +make -j$JOBS Debug exit_code=$? if [ $exit_code != 0 ]; then echo "there has been a problem compiling Debug OF library" @@ -35,7 +38,7 @@ if [ $exit_code != 0 ]; then fi if [ "$BUILD" == "install" ]; then - make Release + make -j$JOBS Release exit_code=$? if [ $exit_code != 0 ]; then echo "there has been a problem compiling Release OF library" diff --git a/scripts/linux/compilePG.sh b/scripts/linux/compilePG.sh index 99a4fc69b93..568d8c5e506 100755 --- a/scripts/linux/compilePG.sh +++ b/scripts/linux/compilePG.sh @@ -2,21 +2,63 @@ export LC_ALL=C -WHO=`who am i`;ID=`echo ${WHO%% *}` -GROUP_ID=`id --group -n ${ID}` +OF_ROOT=../.. -cd ../../apps/projectGenerator/projectGeneratorSimple -make Release +make Release -C ${OF_ROOT}/apps/projectGenerator/commandLine ret=$? if [ $ret -ne 0 ]; then - echo "there has been a problem compiling the projectGenerator" - echo "please report this problem in the forums" + echo "There has been a problem compiling the command line projectGenerator." + echo "Please report this problem in the forums." exit $ret fi -mkdir ../../../projectGenerator 2> /dev/null -cp -R bin/* ../../../projectGenerator -mv ../../../projectGenerator/projectGeneratorSimple ../../../projectGenerator/projectGenerator -sed -i "s/..\/..\/..\/..\//..\//g" ../../../projectGenerator/data/settings/projectGeneratorSettings.xml -chown -R $ID:$GROUP_ID obj bin -chown -R $ID:$GROUP_ID ../../../projectGenerator -chown -R $ID:$GROUP_ID ../../../addons/obj + +echo +echo +read -p "Do you want to install the command line project generator? [Y/n] " -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "To copy the command line project generator we need root permission." + sudo cp ${OF_ROOT}/apps/projectGenerator/commandLine/bin/projectGenerator /usr/local/bin/projectGenerator + if [ ! $? -eq 0 ]; then + echo "Failed to copy the projectGenerator file." + exit + fi + cd ${OF_ROOT} + PG_OF_PATH=$PWD + + CORRECT_PATH=0 + grep PG_OF_PATH ~/.profile + if [ $? -eq 0 ]; then + PREV_OF_PATH=$(grep PG_OF_PATH ~/.profile | sed "s/export PG_OF_PATH=\(.*\)/\1/") + if [ "$PG_OF_PATH" == "$PREV_OF_PATH" ]; then + CORRECT_PATH=1 + fi + else + CORRECT_PATH=1 + fi + + echo + echo + if [ $CORRECT_PATH -eq 0 ]; then + echo "Command line project generator was correctly installed but there was a previous OF install in $PREV_OF_PATH" + echo + echo "You can change the OF path by adding the following line to ~/.profile:" + echo " export PG_OF_PATH=\"MY_FULL_PATH_TO_OF\"" + else + if [ "$PREV_OF_PATH" != "" ]; then + echo "Command line project generator was correctly installed" + echo "To get started run: projectGenerator --help" + else + echo "The command line project generator was correctly installed, but the PG_OF_PATH invironment variable has not been set yet." + echo "You can create this variable by adding the following line to ~/.profile." + echo " export PG_OF_PATH=${PG_OF_PATH}" + read -p "Do you want to add this line to ~/.profile now?? [Y/n] " -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "export PG_OF_PATH=${PG_OF_PATH}" >> ~/.profile + echo "PG_OF_PATH was added. Restart the console for the changes to take effect" + fi + echo "To get started run: projectGenerator --help" + fi + fi +fi diff --git a/scripts/linux/debian/install_codeblocks.sh b/scripts/linux/debian/install_codeblocks.sh deleted file mode 100755 index f4c28d23d9f..00000000000 --- a/scripts/linux/debian/install_codeblocks.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -#DISTRIB_CODENAME=`cat /etc/lsb-release | grep DISTRIB_CODENAME | sed 's/DISTRIB_CODENAME\=\(\.*\)/\1/g'` -WX_DEB="deb http://apt.wxwidgets.org/ etch-wx main" -CB_DEB="deb http://apt.jenslody.de/stable stable main" - -echo $WX_DEB > /etc/apt/sources.list.d/wx.list -echo $CB_DEB > /etc/apt/sources.list.d/cb-nightly.list - -wget -q http://apt.wxwidgets.org/key.asc -O- | apt-key add - - -apt-get update -apt-get install jens-lody-debian-keyring -apt-get install libcodeblocks0 codeblocks libwxsmithlib0 codeblocks-contrib libwxgtk2.8-0 - - diff --git a/scripts/linux/debian/install_dependencies.sh b/scripts/linux/debian/install_dependencies.sh index 0e6cc0c87e3..532910ca78a 100755 --- a/scripts/linux/debian/install_dependencies.sh +++ b/scripts/linux/debian/install_dependencies.sh @@ -35,7 +35,7 @@ fi echo "installing OF dependencies" -apt-get install freeglut3-dev libasound2-dev libxmu-dev libxxf86vm-dev g++ libgl1-mesa-dev libglu1-mesa-dev libraw1394-dev libudev-dev libdrm-dev libglew-dev libopenal-dev libsndfile-dev libfreeimage-dev libcairo2-dev python-lxml python-argparse libfreetype6-dev libssl-dev libpulse-dev libusb-1.0-0-dev libgtk${GTK_VERSION}-dev libopencv-dev libegl1-mesa-dev libgles1-mesa-dev libgles2-mesa-dev libassimp-dev librtaudio-dev libboost-filesystem-dev +apt-get install freeglut3-dev libasound2-dev libxmu-dev libxxf86vm-dev g++ libgl1-mesa-dev libglu1-mesa-dev libraw1394-dev libudev-dev libdrm-dev libglew-dev libopenal-dev libsndfile-dev libfreeimage-dev libcairo2-dev libfreetype6-dev libssl-dev libpulse-dev libusb-1.0-0-dev libgtk${GTK_VERSION}-dev libopencv-dev libegl1-mesa-dev libgles1-mesa-dev libgles2-mesa-dev libassimp-dev librtaudio-dev libboost-filesystem-dev exit_code=$? if [ $exit_code != 0 ]; then echo "error installing dependencies, there could be an error with your internet connection" @@ -52,3 +52,40 @@ if [ $exit_code != 0 ]; then exit $exit_code fi +if [ -f /opt/vc/include/bcm_host.h ]; then + echo "detected Raspberry Pi" + echo "installing gstreamer omx" + apt-get install gstreamer${GSTREAMER_VERSION}-omx +fi + +OS_CODENAME=$(cat /etc/os-release | grep VERSION= | sed "s/VERSION\=\"\(.*\)\"/\1/") + +if [ "$OS_CODENAME" = "7 (wheezy)" ]; then + echo "detected wheezy, installing g++4.8 for c++11 compatibility" + apt-get install g++-4.8 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 20 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 20 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50 +fi + +export LC_ALL=C +GCC_MAJOR_GT_4=$(expr `gcc -dumpversion | cut -f1 -d.` \> 4) +if [ $GCC_MAJOR_GT_4 -eq 1 ]; then + echo + echo + echo "It seems you are running gcc 5 or later, due to incomatible ABI with previous versions" + echo "we need to recompile poco. This will take a while" + read -p "Press any key to continue... " -n1 -s + + sys_cores=$(getconf _NPROCESSORS_ONLN) + if [ $sys_cores -gt 1 ]; then + cores=$(($sys_cores-1)) + else + cores=1 + fi + + DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + cd ${DIR}/../../apothecary + ./apothecary -j${cores} update poco +fi diff --git a/scripts/linux/debian/remove_codeblocks.sh b/scripts/linux/debian/remove_codeblocks.sh deleted file mode 100755 index 4ae80a336fc..00000000000 --- a/scripts/linux/debian/remove_codeblocks.sh +++ /dev/null @@ -1,3 +0,0 @@ -rm /var/cache/apt/archives/libwxbase* -rm /var/cache/apt/archives/libwxgtk* -apt-get remove libwxbase2.8-0 libwxgtk2.8-0 codeblocks diff --git a/scripts/linux/debian_armv6l/install_codeblocks.sh b/scripts/linux/debian_armv6l/install_codeblocks.sh deleted file mode 100755 index 72a10d7ff95..00000000000 --- a/scripts/linux/debian_armv6l/install_codeblocks.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -DISTRIB_CODENAME=`cat /etc/lsb-release | grep DISTRIB_CODENAME | sed 's/DISTRIB_CODENAME\=\(\.*\)/\1/g'` - -WX_DEB="" -ARCH=$(uname -m) - -wget "http://openframeworks.cc/wx-dist.php?dist=${DISTRIB_CODENAME}&arch=${ARCH}" -q -O /tmp/oFtemp -ret=$? - -if [ $ret -eq 0 ]; then -WX_DEB=$(cat /tmp/oFtemp) -fi - -CB_DEB="" - -wget "http://openframeworks.cc/cb-dist.php?dist=${DISTRIB_CODENAME}&arch=${ARCH}" -q -O /tmp/oFtemp -ret=$? - -if [ $ret -eq 0 ]; then -CB_DEB=$(cat /tmp/oFtemp) -fi - -echo "installing codeblocks from" -echo $CB_DEB -echo with wxwidgets from -echo $WX_DEB -if [ -f /etc/apt/sources.list.d/wxwidgets.list ]; then - rm /etc/apt/sources.list.d/wxwidgets.list -fi - -if [ -f /etc/apt/sources.list.d/cb-nightly.list ]; then - rm /etc/apt/sources.list.d/cb-nightly.list -fi -if [ ! "$CB_DEB" = "" ]; then - echo $CB_DEB > /etc/apt/sources.list.d/cb-nightly.list -fi - -if [ ! "$WX_DEB" = "" ]; then - echo $WX_DEB > /etc/apt/sources.list.d/wxwidgets.list -fi - - -apt-get update - -apt-get install libcodeblocks0 codeblocks codeblocks-contrib libwxsmithlib0 codeblocks-contrib libwxgtk2.8-0 - -if [ -f /etc/apt/sources.list.d/wxwidgets.list ]; then - rm /etc/apt/sources.list.d/wxwidgets.list -fi - -if [ -f /etc/apt/sources.list.d/cb-nightly.list ]; then - rm /etc/apt/sources.list.d/cb-nightly.list -fi - -## fix pkg-config by installing missing dependencies - -pkg-config --list-all 2>/dev/null 1>/dev/null -ret=$? -while [ $ret -ne 0 ]; do - pkg=$(pkg-config --list-all 2>&1 1>/dev/null | grep "Package '.*'," | sed "s/Package '\(\.*\)/\1/g" | sed "s/\(\.*\)'.*/\1/g") - sudo apt-get install ${pkg}-dev - pkg-config --list-all 2>/dev/null 1>/dev/null - ret=$? -done diff --git a/scripts/linux/debian_armv6l/install_dependencies.sh b/scripts/linux/debian_armv6l/install_dependencies.sh deleted file mode 100755 index 6cf306c4d57..00000000000 --- a/scripts/linux/debian_armv6l/install_dependencies.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -echo "inserting gstreamer 1.0 repository" -rm /etc/apt/sources.list.d/gstreamer.list -touch /etc/apt/sources.list.d/gstreamer.list -echo "updating apt database" -apt-get update - -GSTREAMER_VERSION=1.0 - -GTK_VERSION=2.0 -echo "detecting latest gtk version" -apt-cache show libgtk-3-dev -exit_code=$? -if [ $exit_code = 0 ]; then - echo selecting gtk 3 - GTK_VERSION=-3 -fi - -echo "installing OF dependencies" -apt-get install libmpg123-dev alsa-base alsa-tools alsa-utils libupnp-dev automake cvs libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libasound2-dev libxmu-dev libxxf86vm-dev g++ libgl1-mesa-dev libglu1-mesa-dev libraw1394-dev libudev-dev libdrm-dev libglew-dev libopenal-dev libsndfile-dev libfreeimage-dev libcairo2-dev libgtk2.0-dev python-lxml python-argparse libfreetype6-dev libassimp-dev portaudio19-dev libssl-dev libpulse-dev libgtk${GTK_VERSION}-dev libopencv-dev libassimp-dev librtaudio-dev libboost-filesystem-dev -exit_code=$? -if [ $exit_code != 0 ]; then - echo "error installing dependencies, there could be an error with your internet connection" - echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" - exit $exit_code -fi - - -echo "installing gstreamer" -apt-get install libgstreamer${GSTREAMER_VERSION}-dev libgstreamer-plugins-base${GSTREAMER_VERSION}-dev gstreamer${GSTREAMER_VERSION}-pulseaudio gstreamer${GSTREAMER_VERSION}-x gstreamer${GSTREAMER_VERSION}-plugins-bad gstreamer${GSTREAMER_VERSION}-alsa gstreamer${GSTREAMER_VERSION}-plugins-base gstreamer${GSTREAMER_VERSION}-plugins-good gstreamer${GSTREAMER_VERSION}-omx -exit_code=$? -if [ $exit_code != 0 ]; then - echo "error installing gstreamer, there could be an error with your internet connection" - echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" - exit $exit_code -fi diff --git a/scripts/linux/debian_armv6l/remove_codeblocks.sh b/scripts/linux/debian_armv6l/remove_codeblocks.sh deleted file mode 100755 index 4ae80a336fc..00000000000 --- a/scripts/linux/debian_armv6l/remove_codeblocks.sh +++ /dev/null @@ -1,3 +0,0 @@ -rm /var/cache/apt/archives/libwxbase* -rm /var/cache/apt/archives/libwxgtk* -apt-get remove libwxbase2.8-0 libwxgtk2.8-0 codeblocks diff --git a/scripts/linux/fedora/install_codeblocks.sh b/scripts/linux/fedora/install_codeblocks.sh deleted file mode 100755 index b6df49d2847..00000000000 --- a/scripts/linux/fedora/install_codeblocks.sh +++ /dev/null @@ -1,2 +0,0 @@ -yum install codeblocks xterm - diff --git a/scripts/linux/fedora/install_dependencies.sh b/scripts/linux/fedora/install_dependencies.sh index 01fe394bf9f..fd245f7eb7c 100755 --- a/scripts/linux/fedora/install_dependencies.sh +++ b/scripts/linux/fedora/install_dependencies.sh @@ -10,7 +10,7 @@ if [ $EUID != 0 ]; then exit 1 fi -yum install freeglut-devel alsa-lib-devel libXmu-devel libXxf86vm-devel gcc-c++ libraw1394-devel gstreamer1-devel gstreamer1-plugins-base-devel libudev-devel libtheora-devel libvorbis-devel openal-soft-devel libsndfile-devel python-lxml glew-devel flac-devel freeimage-devel cairo-devel pulseaudio-libs-devel openssl-devel libusbx-devel gtk2-devel libXrandr-devel libXi-devel opencv-devel libX11-devel assimp-devel rtaudio-devel boost +yum install freeglut-devel alsa-lib-devel libXmu-devel libXxf86vm-devel gcc-c++ libraw1394-devel gstreamer1-devel gstreamer1-plugins-base-devel libudev-devel libtheora-devel libvorbis-devel openal-soft-devel libsndfile-devel python-lxml glew-devel flac-devel freeimage-devel cairo-devel pulseaudio-libs-devel openssl-devel libusbx-devel gtk2-devel libXrandr-devel libXi-devel opencv-devel libX11-devel assimp-devel rtaudio-devel boost-devel gtk3-devel exit_code=$? if [ $exit_code != 0 ]; then @@ -18,3 +18,23 @@ if [ $exit_code != 0 ]; then exit $exit_code fi +export LC_ALL=C +GCC_MAJOR_GT_4=$(expr `gcc -dumpversion | cut -f1 -d.` \> 4) +if [ $GCC_MAJOR_GT_4 -eq 1 ]; then + echo + echo + echo "It seems you are running gcc 5 or later, due to incomatible ABI with previous versions" + echo "we need to recompile poco. This will take a while" + read -p "Press any key to continue... " -n1 -s + + sys_cores=$(getconf _NPROCESSORS_ONLN) + if [ $sys_cores -gt 1 ]; then + cores=$(($sys_cores-1)) + else + cores=1 + fi + + DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + cd ${DIR}/../../apothecary + ./apothecary -j${cores} update poco +fi diff --git a/scripts/linux/fedora/remove_codeblocks.sh b/scripts/linux/fedora/remove_codeblocks.sh deleted file mode 100755 index 3967e965010..00000000000 --- a/scripts/linux/fedora/remove_codeblocks.sh +++ /dev/null @@ -1 +0,0 @@ -yum erase codeblocks diff --git a/scripts/linux/testTemplate.sh b/scripts/linux/testTemplate.sh deleted file mode 100755 index cc4e91a971a..00000000000 --- a/scripts/linux/testTemplate.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -e -cd $OF_ROOT -cp scripts/linux/template/linux/Makefile examples/empty/emptyExample/ -cp scripts/linux/template/linux/config.make examples/empty/emptyExample/ -cd examples/empty/emptyExample -make Debug diff --git a/scripts/linux/ubuntu/install_codeblocks.sh b/scripts/linux/ubuntu/install_codeblocks.sh deleted file mode 100755 index 72a10d7ff95..00000000000 --- a/scripts/linux/ubuntu/install_codeblocks.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -DISTRIB_CODENAME=`cat /etc/lsb-release | grep DISTRIB_CODENAME | sed 's/DISTRIB_CODENAME\=\(\.*\)/\1/g'` - -WX_DEB="" -ARCH=$(uname -m) - -wget "http://openframeworks.cc/wx-dist.php?dist=${DISTRIB_CODENAME}&arch=${ARCH}" -q -O /tmp/oFtemp -ret=$? - -if [ $ret -eq 0 ]; then -WX_DEB=$(cat /tmp/oFtemp) -fi - -CB_DEB="" - -wget "http://openframeworks.cc/cb-dist.php?dist=${DISTRIB_CODENAME}&arch=${ARCH}" -q -O /tmp/oFtemp -ret=$? - -if [ $ret -eq 0 ]; then -CB_DEB=$(cat /tmp/oFtemp) -fi - -echo "installing codeblocks from" -echo $CB_DEB -echo with wxwidgets from -echo $WX_DEB -if [ -f /etc/apt/sources.list.d/wxwidgets.list ]; then - rm /etc/apt/sources.list.d/wxwidgets.list -fi - -if [ -f /etc/apt/sources.list.d/cb-nightly.list ]; then - rm /etc/apt/sources.list.d/cb-nightly.list -fi -if [ ! "$CB_DEB" = "" ]; then - echo $CB_DEB > /etc/apt/sources.list.d/cb-nightly.list -fi - -if [ ! "$WX_DEB" = "" ]; then - echo $WX_DEB > /etc/apt/sources.list.d/wxwidgets.list -fi - - -apt-get update - -apt-get install libcodeblocks0 codeblocks codeblocks-contrib libwxsmithlib0 codeblocks-contrib libwxgtk2.8-0 - -if [ -f /etc/apt/sources.list.d/wxwidgets.list ]; then - rm /etc/apt/sources.list.d/wxwidgets.list -fi - -if [ -f /etc/apt/sources.list.d/cb-nightly.list ]; then - rm /etc/apt/sources.list.d/cb-nightly.list -fi - -## fix pkg-config by installing missing dependencies - -pkg-config --list-all 2>/dev/null 1>/dev/null -ret=$? -while [ $ret -ne 0 ]; do - pkg=$(pkg-config --list-all 2>&1 1>/dev/null | grep "Package '.*'," | sed "s/Package '\(\.*\)/\1/g" | sed "s/\(\.*\)'.*/\1/g") - sudo apt-get install ${pkg}-dev - pkg-config --list-all 2>/dev/null 1>/dev/null - ret=$? -done diff --git a/scripts/linux/ubuntu/install_dependencies.sh b/scripts/linux/ubuntu/install_dependencies.sh index 690148e296f..46943c38a65 100755 --- a/scripts/linux/ubuntu/install_dependencies.sh +++ b/scripts/linux/ubuntu/install_dependencies.sh @@ -6,9 +6,53 @@ if [ $EUID != 0 ]; then echo "usage:" echo "sudo "$0 exit $exit_code - exit 1 + exit 1 +fi + +if [ "$1" == "-y" ]; then + FORCE_YES=-y fi +function installPackages { + for pkg in $@; do + echo "Installing ${pkg}" + dpkg-query -W -f=' ' ${pkg} 2> /dev/null + if [ $? -eq 0 ]; then + echo "Already installed" + else + error="$(apt-get install --dry-run ${pkg})" + exit_code=$? + echo "$error" | grep Remv > /dev/null + if [ $? -eq 0 ]; then + apt-get install ${pkg} + exit_code=$? + if [ $exit_code != 0 ]; then + echo "error installing ${pkg}, there could be an error with your internet connection" + echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" + exit $exit_code + fi + elif [ $exit_code -eq 0 ]; then + apt-get -y install ${pkg} > /dev/null + exit_code=$? + if [ $exit_code != 0 ]; then + echo "error installing ${pkg}, there could be an error with your internet connection" + echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" + exit $exit_code + fi + else + echo "error installing ${pkg}" + echo $error + echo "this seems an error with your distribution repositories but you can also" + echo "report an issue in the openFrameworks github: http://github.com/openframeworks/openFrameworks/issues" + exit $exit_code + fi + fi + done + echo + echo "All packages were installed correctly" + echo +} + MAJOR_VERSION=$(lsb_release -r | cut -f2 -d: | cut -f1 -d. | sed "s/\t//g") MINOR_VERSION=$(lsb_release -r | cut -f2 -d: | cut -f2 -d.) @@ -61,8 +105,7 @@ XTAG=$(dpkg -l |grep xserver-xorg-core|grep ii|awk '{print $2}'|sed "s/xserver-x if [ ! -z $XTAG ] then read -p " installing OF dependencies with "${XTAG}" packages, confirm Y/N ? " -n 1 -r - if [[ $REPLY =~ ^[Yy]$ ]] - then + if [[ $REPLY =~ ^[Yy]$ ]]; then echo echo "installation of OF dependencies with "${XTAG}" packages confirmed" else @@ -70,23 +113,54 @@ then fi fi +PACKAGES="curl libjack-jackd2-0 libjack-jackd2-dev freeglut3-dev libasound2-dev libxmu-dev libxxf86vm-dev g++${CXX_VER} libgl1-mesa-dev${XTAG} libglu1-mesa-dev libraw1394-dev libudev-dev libdrm-dev libglew-dev libopenal-dev libsndfile-dev libfreeimage-dev libcairo2-dev libfreetype6-dev libssl-dev libpulse-dev libusb-1.0-0-dev libgtk${GTK_VERSION}-dev libopencv-dev libassimp-dev librtaudio-dev libboost-filesystem${BOOST_VER}-dev libgstreamer${GSTREAMER_VERSION}-dev libgstreamer-plugins-base${GSTREAMER_VERSION}-dev ${GSTREAMER_FFMPEG} gstreamer${GSTREAMER_VERSION}-pulseaudio gstreamer${GSTREAMER_VERSION}-x gstreamer${GSTREAMER_VERSION}-plugins-bad gstreamer${GSTREAMER_VERSION}-alsa gstreamer${GSTREAMER_VERSION}-plugins-base gstreamer${GSTREAMER_VERSION}-plugins-good gdb" + echo "installing OF dependencies" -apt-get install freeglut3-dev libasound2-dev libxmu-dev libxxf86vm-dev g++${CXX_VER} libgl1-mesa-dev${XTAG} libglu1-mesa-dev libraw1394-dev libudev-dev libdrm-dev libglew-dev libopenal-dev libsndfile-dev libfreeimage-dev libcairo2-dev python-lxml python-argparse libfreetype6-dev libssl-dev libpulse-dev libusb-1.0-0-dev libgtk${GTK_VERSION}-dev libopencv-dev libassimp-dev librtaudio-dev libboost-filesystem${BOOST_VER}-dev -exit_code=$? -if [ $exit_code != 0 ]; then - echo "error installing dependencies, there could be an error with your internet connection" - echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" - exit $exit_code +echo "OF needs to install the following packages using apt-get:" +echo ${PACKAGES} +if [ "$1" != "-y" ]; then + read -p "Do you want to continue? [Y/n] " + if [[ $REPLY =~ ^[Nn]$ ]]; then + exit 0 + fi + + echo + echo "Installing..." + echo + installPackages ${PACKAGES} +else + installPackages ${PACKAGES} fi - -echo "installing gstreamer" -apt-get install libgstreamer${GSTREAMER_VERSION}-dev libgstreamer-plugins-base${GSTREAMER_VERSION}-dev ${GSTREAMER_FFMPEG} gstreamer${GSTREAMER_VERSION}-pulseaudio gstreamer${GSTREAMER_VERSION}-x gstreamer${GSTREAMER_VERSION}-plugins-bad gstreamer${GSTREAMER_VERSION}-alsa gstreamer${GSTREAMER_VERSION}-plugins-base gstreamer${GSTREAMER_VERSION}-plugins-good -exit_code=$? -if [ $exit_code != 0 ]; then - echo "error installing gstreamer, there could be an error with your internet connection" - echo "if the error persists, please report an issue in github: http://github.com/openframeworks/openFrameworks/issues" - exit $exit_code +if [ $(expr $MAJOR_VERSION \< 13 ) -eq 1 ]; then + echo "detected ubuntu 12.xx setting gcc-${CXX_VER} as default compiler" + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 20 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc${CXX_VER} 50 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 20 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++${CXX_VER} 50 fi - +export LC_ALL=C +GCC_MAJOR_GT_4=$(expr `gcc -dumpversion | cut -f1 -d.` \> 4) +if [ $GCC_MAJOR_GT_4 -eq 1 ]; then + echo + echo + echo "It seems you are running gcc 5 or later, due to incomatible ABI with previous versions" + echo "we need to recompile poco. This will take a while" + read -p "Press any key to continue... " -n1 -s + + sys_cores=$(getconf _NPROCESSORS_ONLN) + if [ $sys_cores -gt 1 ]; then + cores=$(($sys_cores-1)) + else + cores=1 + fi + + DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + cd ${DIR}/../../apothecary + ./apothecary -j${cores} update poco + WHO=`who am i`;ID=`echo ${WHO%% *}` + GROUP_ID=`id --group -n ${ID}` + chown -R $ID:$GROUP_ID build/poco + chown -R $ID:$GROUP_ID ../../libs/poco +fi diff --git a/scripts/linux/ubuntu/remove_codeblocks.sh b/scripts/linux/ubuntu/remove_codeblocks.sh deleted file mode 100755 index 4ae80a336fc..00000000000 --- a/scripts/linux/ubuntu/remove_codeblocks.sh +++ /dev/null @@ -1,3 +0,0 @@ -rm /var/cache/apt/archives/libwxbase* -rm /var/cache/apt/archives/libwxgtk* -apt-get remove libwxbase2.8-0 libwxgtk2.8-0 codeblocks diff --git a/scripts/msys2/buildAllExamples.sh b/scripts/msys2/buildAllExamples.sh new file mode 100644 index 00000000000..389f58eb68a --- /dev/null +++ b/scripts/msys2/buildAllExamples.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +export LC_ALL=C + +examples_dir=../../examples +examples_prefix="$examples_dir/" + +system=msys2 +copy_makefiles () { + cp ../templates/$system/Makefile $1/ + cp ../templates/$system/config.make $1/ +} + +delete_makefiles () { + rm $1/Makefile + rm $1/config.make +} + +echo_and_log () { + local str="$*" + echo $str + echo $str $'\r' >> $logfile +} + +echo_category() { + local cat=$1 + local category_short=${cat#$examples_prefix} + echo $'\r'$'\r' >> $logfile + echo_and_log "=================================================================" + echo -e "\e[1mcategory $category_short\e[0m" + echo "category $category_short" $'\r' >> $logfile + echo_and_log "=================================================================" + +} + +echo_success() { + #echo_and_log "[Success]" + echo -e "\e[32m[Success]\e[0m" + echo " " $'\r'>> $logfile + echo "[Success]" $'\r'>> $logfile + (( example_success++ )) +} + +echo_failed() { + echo -e "\e[31;7m[Failed]\e[0m" + echo " " $'\r'>> $logfile + echo "[Failed]" $'\r'>> $logfile + (( example_fail++ )) +} + + +MAKEFLAGS=-j$NUMBER_OF_PROCESSORS + +#initialize logfile +logfile=$examples_dir/ExamplesBuilder.log +echo "" > $logfile + +example_total=0 +example_success=0 +example_fail=0 +example_fail_list="" +example_skipped=0 + +echo_and_log "Building All Examples" + +for category in $( find $examples_dir/ -mindepth 1 -maxdepth 1 -type d ) +do + if [ "$category" = "$examples_dir" -o "$category" = "$examples_dir/android" -o "$category" = "$examples_dir/ios" -o "$category" = "$examples_dir/examples/" ]; then + continue + fi + + echo_category $category + + for example in $( find $category -mindepth 1 -maxdepth 1 -type d | grep -v osx ) + do + + echo_and_log "Building ${example#$examples_prefix}" + (( example_total++ )) + #if [ "$example" = "$examples_dir/3d/cameraLensOffsetExample" ]; then + # echo " [Skipped]" >> $logfile + # (( example_skipped++ )) + # continue + #fi + + + + + #projectGenerator . + + copy_makefiles $example + #ERROR=$(>$logfile 2>>$logfile + ret=$? + if [ $ret -ne 0 ]; then + echo_failed + example_fail_list="$example_fail_list ${example#$examples_prefix}" + else + echo_success + fi + #delete_makefiles $example + + echo_and_log "-----------------------------------------------------------------" + echo "" + done +done + + +echo +echo_and_log +echo_and_log "=================================================================" +echo_and_log "Success:$example_success - Skipped:$example_skipped - Failed:$example_fail - total:$example_total" +echo_and_log "=================================================================" + +if [ $example_fail -gt 0 ]; then + echo_and_log "Failed examples :" + echo_and_log "$example_fail_list" + echo_and_log "=================================================================" +fi diff --git a/scripts/msys2/cleanAllExamples.sh b/scripts/msys2/cleanAllExamples.sh new file mode 100644 index 00000000000..8d30127caf6 --- /dev/null +++ b/scripts/msys2/cleanAllExamples.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +examples_dir=../../examples + +for category in $( find $examples_dir/ -maxdepth 1 -type d ) +do + if [ "$category" = "$examples_dir/android" -o "$category" = "$examples_dir/ios" -o "$category" = "$examples_dir/" ]; then + continue + fi + + for example in $( find $category -maxdepth 1 -type d | grep -v osx ) + do + if [ "$example" = "$category" ]; then + continue + fi + echo "-----------------------------------------------------------------" + echo "cleaning " + $example + + make clean -C $example + rm -rf $example/obj 2> /dev/null + rm -rf $example/*.layout 2> /dev/null + rm -rf $example/*.backup 2> /dev/null + rm -rf $example/*.depend 2> /dev/null + rm $example/*~ 2> /dev/null + + echo "-----------------------------------------------------------------" + echo "" + done +done + diff --git a/scripts/msys2/compileOF.sh b/scripts/msys2/compileOF.sh new file mode 100644 index 00000000000..69e2b4ae212 --- /dev/null +++ b/scripts/msys2/compileOF.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +export LC_ALL=C + +pushd `dirname $0` > /dev/null +SCRIPTPATH=`pwd` +popd > /dev/null + +BUILD="install" +JOBS=1 +while getopts tj: opt ; do + case "$opt" in + t) # testing, only build Debug + BUILD="test" ;; + j) # make job count for parallel build + JOBS="$OPTARG" + esac +done + +if [ "$MSYSTEM" != "MINGW32" ] +then + echo "This is not a MINGW32 shell!" + echo "Please launch compileOF.sh from a MINGW32 shell." + exit 1 +fi + +cd ${SCRIPTPATH}/../../libs/openFrameworksCompiled/project +make -j$JOBS Debug +exit_code=$? +if [ $exit_code != 0 ]; then + echo "there has been a problem compiling Debug OF library" + echo "please report this problem in the forums" + exit $exit_code +fi + +if [ "$BUILD" == "install" ]; then + make -j$JOBS Release + exit_code=$? + if [ $exit_code != 0 ]; then + echo "there has been a problem compiling Release OF library" + echo "please report this problem in the forums" + exit $exit_code + fi +fi diff --git a/scripts/msys2/install_dependencies.sh b/scripts/msys2/install_dependencies.sh new file mode 100644 index 00000000000..61a7c930ab9 --- /dev/null +++ b/scripts/msys2/install_dependencies.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +function usage { + echo usage: + echo ./install_dependencies.sh [--help] [--noconfirm] + echo --help: + echo display this message + echo + echo --noconfirm: + echo install packages without user confirmation +} + +#Analyse script arguments +while [[ $# > 0 ]] ; do + arg=$1 + shift + if [ "$arg" == "--noconfirm" ]; then + confirm=--noconfirm + continue + fi + if [ "$arg" == "--help" ]; then + usage + exit 1 + fi + echo Invalid argument : $arg + usage + exit 1 +done + +NOT_HAS_PATH=$(echo $PATH | grep /mingw32/bin > /dev/null; echo $?) +if [ "$NOT_HAS_PATH" -ne "0" ]; then + cd / + MSYS2_ROOT=$(pwd -W) + setx PATH "$MSYS2_ROOT/mingw32/bin;$MSYS2_ROOT/usr/bin/;%PATH%;" +fi + +arch=i686 + +pacman -Sy +pacman -Su +pacman -S $confirm ca-certificates +pacman -Sy $confirm --needed make mingw-w64-$arch-gcc mingw-w64-$arch-glew mingw-w64-$arch-freeglut mingw-w64-$arch-FreeImage mingw-w64-$arch-opencv mingw-w64-$arch-assimp mingw-w64-$arch-boost mingw-w64-$arch-cairo mingw-w64-$arch-clang mingw-w64-$arch-gdb mingw-w64-$arch-zlib mingw-w64-$arch-tools mingw-w64-$arch-pkg-config mingw-w64-$arch-poco mingw-w64-$arch-glfw + +# this would install gstreamer which can be used in mingw too +#pacman -Sy mingw-w64-$arch-gst-libav mingw-w64-$arch-gst-plugins-bad mingw-w64-$arch-gst-plugins-base mingw-w64-$arch-gst-plugins-good mingw-w64-$arch-gst-plugins-ugly mingw-w64-$arch-gstreamer + +exit_code=$? +if [ $exit_code != 0 ]; then + echo "error installing packages, there could be an error with your internet connection" + exit $exit_code +fi diff --git a/scripts/osx/testTemplate.sh b/scripts/osx/testTemplate.sh deleted file mode 100755 index 179e58c297e..00000000000 --- a/scripts/osx/testTemplate.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -e -if [ "$SCRIPT_PATH" == "" ]; then SCRIPT_PATH="."; fi -echo "Looking for OSX Template Project" -if [ ! -d $SCRIPT_PATH/template/bin/emptyExample.app ]; then - echo "---------------------------------" - if [ ! -e $SCRIPT_PATH/template/emptyExample.xcodeproj ]; then - echo "-----------------------------" - echo "No Xcode project found for emptyExample" - fi - echo "Building openFrameworks - OSX Template Project" - xcodebuild -configuration Release -target emptyExample -project $SCRIPT_PATH/template/emptyExample.xcodeproj - ret=$? - if [ $ret -ne 0 ]; then - echo "Failed building emptyExample" - exit 1 - fi - echo "---------------------------------" -fi diff --git a/scripts/qtcreator/install_template.sh b/scripts/qtcreator/install_template.sh new file mode 100755 index 00000000000..9041bac0abc --- /dev/null +++ b/scripts/qtcreator/install_template.sh @@ -0,0 +1,4 @@ +mkdir -p ${HOME}/.config/QtProject/qtcreator/templates/wizards/ +cp -r templates/wizards/openFrameworks ${HOME}/.config/QtProject/qtcreator/templates/wizards/ +cp -r templates/wizards/openFrameworksUpdate ${HOME}/.config/QtProject/qtcreator/templates/wizards/ + diff --git a/examples/android/android3DModelLoaderExample/Makefile b/scripts/qtcreator/templates/wizards/openFrameworks/Makefile similarity index 100% rename from examples/android/android3DModelLoaderExample/Makefile rename to scripts/qtcreator/templates/wizards/openFrameworks/Makefile diff --git a/scripts/vs/template/bin/data/.gitkeep b/scripts/qtcreator/templates/wizards/openFrameworks/bin/data/.gitkeep similarity index 100% rename from scripts/vs/template/bin/data/.gitkeep rename to scripts/qtcreator/templates/wizards/openFrameworks/bin/data/.gitkeep diff --git a/examples/android/android3DModelLoaderExample/config.make b/scripts/qtcreator/templates/wizards/openFrameworks/config.make similarity index 100% rename from examples/android/android3DModelLoaderExample/config.make rename to scripts/qtcreator/templates/wizards/openFrameworks/config.make diff --git a/scripts/qtcreator/templates/wizards/openFrameworks/of.png b/scripts/qtcreator/templates/wizards/openFrameworks/of.png new file mode 100644 index 00000000000..3f81822ddac Binary files /dev/null and b/scripts/qtcreator/templates/wizards/openFrameworks/of.png differ diff --git a/scripts/qtcreator/templates/wizards/openFrameworks/qtcreator.qbs b/scripts/qtcreator/templates/wizards/openFrameworks/qtcreator.qbs new file mode 100644 index 00000000000..107163a770f --- /dev/null +++ b/scripts/qtcreator/templates/wizards/openFrameworks/qtcreator.qbs @@ -0,0 +1,69 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "%{JS: %{CorrectInitialOFPath}?'../../..':'%{OFPath}'}/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: %{JS: %{CorrectInitialOFPath}?'\'../../..\'':'\'%{OFPath}\''} + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + of.addons: [ + %{JS: + [].concat(%{ofx3DModelLoader} ? ['\'ofx3DModelLoader\''] : []) + .concat(%{ofxAssimpModelLoader} ? ['\'ofxAssimpModelLoader\''] : []) + .concat(%{ofxGui} ? ['\'ofxGui\''] : []) + .concat(%{ofxKinect} ? ['\'ofxKinect\''] : []) + .concat(%{ofxNetwork} ? ['\'ofxNetwork\''] : []) + .concat(%{ofxOpenCv} ? ['\'ofxOpenCv\''] : []) + .concat(%{ofxOsc} ? ['\'ofxOsc\''] : []) + .concat(%{ofxSvg} ? ['\'ofxSvg\''] : []) + .concat(%{ofxTween} ? ['\'ofxTween\''] : []) + .concat(%{ofxVectorGraphics} ? ['\'ofxVectorGraphics\''] : []) + .concat(%{ofxXmlSettings} ? ['\'ofxXmlSettings\''] : []).toString() + } + ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + of.frameworks: [] // osx only, additional frameworks to link with the project + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/linux/template/linux/src/main.cpp b/scripts/qtcreator/templates/wizards/openFrameworks/src/main.cpp similarity index 100% rename from scripts/linux/template/linux/src/main.cpp rename to scripts/qtcreator/templates/wizards/openFrameworks/src/main.cpp diff --git a/scripts/linux/template/linux/src/ofApp.cpp b/scripts/qtcreator/templates/wizards/openFrameworks/src/ofApp.cpp similarity index 100% rename from scripts/linux/template/linux/src/ofApp.cpp rename to scripts/qtcreator/templates/wizards/openFrameworks/src/ofApp.cpp diff --git a/scripts/linux/template/linux/src/ofApp.h b/scripts/qtcreator/templates/wizards/openFrameworks/src/ofApp.h similarity index 100% rename from scripts/linux/template/linux/src/ofApp.h rename to scripts/qtcreator/templates/wizards/openFrameworks/src/ofApp.h diff --git a/scripts/qtcreator/templates/wizards/openFrameworks/wizard.json b/scripts/qtcreator/templates/wizards/openFrameworks/wizard.json new file mode 100644 index 00000000000..2c9c5f68c37 --- /dev/null +++ b/scripts/qtcreator/templates/wizards/openFrameworks/wizard.json @@ -0,0 +1,303 @@ +{ + "version": 1, + "kind": "project", + "id": "R.OF Application", + "category": "I.openFrameworks", + "trDescription": "Creates an empty openFrameworks application using Qbs to build.", + "trDisplayName": "openFrameworks Application", + "trDisplayCategory": "openFrameworks", + "icon": "of.png", + "enabled": "%{JS: [ %{Plugins} ].indexOf('QbsProjectManager') >= 0 }", + + "options": + [ + { "key": "ProjectFile", "value": "%{QbsFile}" }, + { "key": "QbsFile", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qbs')}" }, + { "key": "IsTopLevelProject", "value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}'}" }, + { "key": "InitialOFPath", "value": "%{JS: Util.absoluteFilePath('%{ProjectDirectory}/../../..')}" }, + { "key": "CorrectInitialOFPath", "value": "%{JS: Util.isDirectory('%{InitialOFPath}') && Util.isDirectory('%{InitialOFPath}/libs/openFrameworks') && Util.isDirectory('%{InitialOFPath}/addons') && Util.isDirectory('%{InitialOFPath}/scripts')}" }, + { "key": "CorrectOFPath", "value": "%{JS: Util.isDirectory('%{OFPath}') && Util.isDirectory('%{OFPath}/libs/openFrameworks') && Util.isDirectory('%{OFPath}/addons') && Util.isDirectory('%{OFPath}/scripts')}" }, + { "key": "UtilsInspect", "value": "%{JS: Object.getOwnPropertyNames(Util).toString()}" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project" + }, + { + "trDisplayName": "openFrameworks config", + "trShortTitle": "OF config", + "typeId": "Fields", + "data" : + [ + { + "name": "ErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: !%{CorrectInitialOFPath} && !%{CorrectOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Couldn't find openFrameworks, please check that the project path in the previous page is 2 levels below the OF root.\n\nEg: /home/myname/Code/openFrameworks/apps/myapps\n\nOr select a correct OF path in the following field" + } + }, + { + "name": "NoErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: !%{CorrectInitialOFPath} && %{CorrectOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Correct openFrameworks install found." + } + }, + { + "name": "Sp0", + "type": "Spacer", + "visible": "%{JS: !%{CorrectInitialOFPath}}", + "data": + { + "factor": 1 + } + }, + { + "name": "OFPath", + "type": "PathChooser", + "trDisplayName": "OF path:", + "mandatory": "%{JS: !%{CorrectInitialOFPath}}", + "visible": "%{JS: !%{CorrectInitialOFPath}}", + "isComplete": "%{JS: %{CorrectOFPath}}", + "data": + { + "kind": "existingDirectory", + "basePath": "%{InitialOFPath}", + "path": "%{InitialOFPath}" + } + }, + { + "name": "ErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: %{CorrectInitialOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Correct openFrameworks install detected in:" + } + }, + { + "name": "OFPathLabel", + "type": "LineEdit", + "span": "true", + "visible": "%{JS: %{CorrectInitialOFPath}}", + "enabled": false, + "data": + { + "trText": "%{InitialOFPath}", + "trDisabledText": "%{InitialOFPath}" + } + } + ] + }, + { + "trDisplayName": "Addons", + "trShortTitle": "Addons", + "typeId": "Fields", + "data" : + [ + { + "name": "AddonsLabel", + "type": "Label", + "span": true, + "visible": "true", + "data": + { + "wordWrap": true, + "trText": "Select the addons to include in the project Only official addons supported by now. You can easily add other addons later in the project file" + } + }, + { + "name": "Sp2", + "type": "Spacer", + "data": + { + "factor": 1 + } + }, + { + "name": "ofx3DModelLoader", + "trDisplayName": "ofx3DModelLoader", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxAssimpModelLoader", + "trDisplayName": "ofxAssimpModelLoader", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxGui", + "trDisplayName": "ofxGui", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxKinect", + "trDisplayName": "ofxKinect", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxNetwork", + "trDisplayName": "ofxNetwork", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxOpenCv", + "trDisplayName": "ofxOpenCv", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxOsc", + "trDisplayName": "ofxOsc", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxSvg", + "trDisplayName": "ofxSvg", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxThreadedImageLoader", + "trDisplayName": "ofxThreadedImageLoader", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxTween", + "trDisplayName": "ofxTween", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxVectorGraphics", + "trDisplayName": "ofxVectorGraphics", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + }, + { + "name": "ofxXmlSettings", + "trDisplayName": "ofxXmlSettings", + "type": "CheckBox", + "data": { + "checkedValue": "1", + "uncheckedValue": "0", + "checked": "false" + } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "qtcreator.qbs", + "target": "%{QbsFile}", + "openAsProject": true + }, + { + "source": "src/main.cpp", + "target": "src/main.cpp", + "openInEditor": false + }, + { + "source": "src/ofApp.cpp", + "target": "src/ofApp.cpp", + "openInEditor": true + }, + { + "source": "src/ofApp.h", + "target": "src/ofApp.h", + "openInEditor": true + }, + { + "source": "bin/data/.gitkeep", + "target": "bin/data/.gitkeep", + "openInEditor": false + }, + { + "source": "Makefile", + "target": "Makefile", + "openInEditor": false + }, + { + "source": "config.make", + "target": "config.make", + "openInEditor": false + } + ] + } + ] +} diff --git a/scripts/linux/template/linux/Makefile b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/Makefile similarity index 100% rename from scripts/linux/template/linux/Makefile rename to scripts/qtcreator/templates/wizards/openFrameworksUpdate/Makefile diff --git a/scripts/linux/template/linux/config.make b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/config.make similarity index 100% rename from scripts/linux/template/linux/config.make rename to scripts/qtcreator/templates/wizards/openFrameworksUpdate/config.make diff --git a/scripts/qtcreator/templates/wizards/openFrameworksUpdate/of.png b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/of.png new file mode 100644 index 00000000000..9db6b0783be Binary files /dev/null and b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/of.png differ diff --git a/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update.qbs b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update.qbs new file mode 100644 index 00000000000..460b884b7aa --- /dev/null +++ b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update.qbs @@ -0,0 +1,63 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "%{JS: %{CorrectInitialOFPath}?'../../..':'%{OFPath}'}/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: %{JS: %{CorrectInitialOFPath}?'\'../../..\'':'\'%{OFPath}\''} + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + // This project is using addons.make to include the addons + // since it was imported from old code. To change it to include + // the addons from the qbs file change the following lines to + // the list of used addons in array format. eg: + // + // of.addons: [ + // 'ofxGui', + // 'ofxOpenCv', + // ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + of.frameworks: [] // osx only, additional frameworks to link with the project + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update_no_addons.qbs b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update_no_addons.qbs new file mode 100644 index 00000000000..a6a481422e0 --- /dev/null +++ b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/qtcreator_update_no_addons.qbs @@ -0,0 +1,57 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "%{JS: %{CorrectInitialOFPath}?'../../..':'%{OFPath}'}/libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: %{JS: %{CorrectInitialOFPath}?'\'../../..\'':'\'%{OFPath}\''} + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + of.addons: [ + + ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + of.frameworks: [] // osx only, additional frameworks to link with the project + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/qtcreator/templates/wizards/openFrameworksUpdate/wizard.json b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/wizard.json new file mode 100644 index 00000000000..151bbe0172a --- /dev/null +++ b/scripts/qtcreator/templates/wizards/openFrameworksUpdate/wizard.json @@ -0,0 +1,162 @@ +{ + "version": 1, + "kind": "project", + "id": "R.OF ImportApplication", + "category": "I.openFrameworks", + "trDescription": "Updates an existing openFrameworks application using Qbs to build.\nAlso adds any addon from addons.make. Use this to open existing examples, old code...", + "trDisplayName": "Import an existing Application", + "trDisplayCategory": "openFrameworks", + "icon": "of.png", + "enabled": "%{JS: [ %{Plugins} ].indexOf('QbsProjectManager') >= 0 }", + + "options": + [ + { "key": "ProjectFile", "value": "%{QbsFile}" }, + { "key": "QbsFile", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qbs')}" }, + { "key": "IsTopLevelProject", "value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}'}" }, + { "key": "InitialOFPath", "value": "%{JS: Util.absoluteFilePath('%{ProjectDirectory}/../../..')}" }, + { "key": "CorrectInitialOFPath", "value": "%{JS: Util.isDirectory('%{InitialOFPath}') && Util.isDirectory('%{InitialOFPath}/libs/openFrameworks') && Util.isDirectory('%{InitialOFPath}/addons') && Util.isDirectory('%{InitialOFPath}/scripts')}" }, + { "key": "CorrectOFPath", "value": "%{JS: Util.isDirectory('%{OFPath}') && Util.isDirectory('%{OFPath}/libs/openFrameworks') && Util.isDirectory('%{OFPath}/addons') && Util.isDirectory('%{OFPath}/scripts')}" }, + { "key": "ProjectDirectory", "value": "%{ProjectPath}"}, + { "key": "TargetPath", "value": "%{ProjectPath}"}, + { "key": "ProjectName", "value": "%{JS: Util.baseName('%{ProjectPath}') }"} + ], + "pages": + [ + { + "trDisplayName": "Path to the project to import", + "trShortTitle": "Project path", + "typeId": "Fields", + "data": [ + { + "name": "ProjectPath", + "type": "PathChooser", + "trDisplayName": "Project path:", + "mandatory": "true", + "visible": "true", + "isComplete": "%{JS: Util.isDirectory('%{ProjectPath}') && Util.isDirectory('%{ProjectPath}/src') }", + "data": + { + "kind": "existingDirectory", + "basePath": "", + "path": "" + } + } + ] + }, + { + "trDisplayName": "openFrameworks config", + "trShortTitle": "OF config", + "typeId": "Fields", + "data" : + [ + { + "name": "ErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: !%{CorrectInitialOFPath} && !%{CorrectOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Couldn't find openFrameworks, please check that the project path in the previous page is 2 levels below the OF root.\n\nEg: /home/myname/Code/openFrameworks/apps/myapps\n\nOr select a correct OF path in the following field" + } + }, + { + "name": "NoErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: !%{CorrectInitialOFPath} && %{CorrectOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Correct openFrameworks install found." + } + }, + { + "name": "Sp0", + "type": "Spacer", + "visible": "%{JS: !%{CorrectInitialOFPath}}", + "data": + { + "factor": 1 + } + }, + { + "name": "OFPath", + "type": "PathChooser", + "trDisplayName": "OF path:", + "mandatory": "%{JS: !%{CorrectInitialOFPath}}", + "visible": "%{JS: !%{CorrectInitialOFPath}}", + "isComplete": "%{JS: %{CorrectOFPath}}", + "data": + { + "kind": "existingDirectory", + "basePath": "%{InitialOFPath}", + "path": "%{InitialOFPath}" + } + }, + { + "name": "ErrorOFPath", + "type": "Label", + "span": true, + "visible": "%{JS: %{CorrectInitialOFPath}}", + "data": + { + "wordWrap": true, + "trText": "Correct openFrameworks install detected in:" + } + }, + { + "name": "OFPathLabel", + "type": "LineEdit", + "span": "true", + "visible": "%{JS: %{CorrectInitialOFPath}}", + "enabled": false, + "data": + { + "trText": "%{InitialOFPath}", + "trDisabledText": "%{InitialOFPath}" + } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "qtcreator_update.qbs", + "target": "%{QbsFile}", + "openAsProject": true, + "condition": "%{JS: Util.exists('%{ProjectDirectory}/addons.make') }" + }, + { + "source": "qtcreator_update_no_addons.qbs", + "target": "%{QbsFile}", + "openAsProject": true, + "condition": "%{JS: !Util.exists('%{ProjectDirectory}/addons.make') }" + }, + { + "source": "Makefile", + "target": "Makefile", + "openInEditor": false, + "condition": "%{JS: !Util.exists('%{ProjectDirectory}/Makefile') }" + }, + { + "source": "config.make", + "target": "config.make", + "openInEditor": false, + "condition": "%{JS: !Util.exists('%{ProjectDirectory}/config.make') }" + } + ] + } + ] +} diff --git a/scripts/templates/android/.gitignore b/scripts/templates/android/.gitignore new file mode 100644 index 00000000000..06f74e3313a --- /dev/null +++ b/scripts/templates/android/.gitignore @@ -0,0 +1,36 @@ +### Android ### +# Built application files +*.apk +*.ap_ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +### Android Patch ### +gen-external-apklibs +reports +obj +assets diff --git a/examples/android/android3DModelLoaderExample/AndroidManifest.xml b/scripts/templates/android/AndroidManifest.xml similarity index 80% rename from examples/android/android3DModelLoaderExample/AndroidManifest.xml rename to scripts/templates/android/AndroidManifest.xml index f2becd420d7..59ac603b3a7 100644 --- a/examples/android/android3DModelLoaderExample/AndroidManifest.xml +++ b/scripts/templates/android/AndroidManifest.xml @@ -1,16 +1,16 @@ + android:targetSdkVersion="22" /> + + - - + + TEMPLATE_APP_NAME + Settings + \ No newline at end of file diff --git a/examples/android/android3DModelLoaderExample/res/values/styles.xml b/scripts/templates/android/res/values/styles.xml similarity index 100% rename from examples/android/android3DModelLoaderExample/res/values/styles.xml rename to scripts/templates/android/res/values/styles.xml diff --git a/scripts/templates/android/settings.gradle b/scripts/templates/android/settings.gradle new file mode 100644 index 00000000000..784ddb9fa44 --- /dev/null +++ b/scripts/templates/android/settings.gradle @@ -0,0 +1,12 @@ +// openFrameworks-relative root directories (don't touch) +def ofRoot = '../../../' + +include ':ofAndroidLib' +project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib') + +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(ofRoot + 'libs/openFrameworksCompiled/project/android') + +include ':openFrameworks' +project(':openFrameworks').projectDir = new File(ofRoot + 'libs/openFrameworks') + diff --git a/examples/android/android3DModelLoaderExample/src/main.cpp b/scripts/templates/android/src/main.cpp similarity index 99% rename from examples/android/android3DModelLoaderExample/src/main.cpp rename to scripts/templates/android/src/main.cpp index 7b91b3e61c2..bc252b88fd1 100644 --- a/examples/android/android3DModelLoaderExample/src/main.cpp +++ b/scripts/templates/android/src/main.cpp @@ -4,7 +4,6 @@ int main(){ ofSetupOpenGL(1024,768, 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: diff --git a/scripts/templates/android/src/ofApp.cpp b/scripts/templates/android/src/ofApp.cpp new file mode 100644 index 00000000000..189c4aebe88 --- /dev/null +++ b/scripts/templates/android/src/ofApp.cpp @@ -0,0 +1,96 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup(){ + +} + +//-------------------------------------------------------------- +void ofApp::update(){ + +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + +} + +//-------------------------------------------------------------- +void ofApp::keyPressed (int key){ + +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::touchDown(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::touchMoved(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::touchUp(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::touchDoubleTap(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::touchCancelled(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::swipe(ofxAndroidSwipeDir swipeDir, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::pause(){ + +} + +//-------------------------------------------------------------- +void ofApp::stop(){ + +} + +//-------------------------------------------------------------- +void ofApp::resume(){ + +} + +//-------------------------------------------------------------- +void ofApp::reloadTextures(){ + +} + +//-------------------------------------------------------------- +bool ofApp::backPressed(){ + return false; +} + +//-------------------------------------------------------------- +void ofApp::okPressed(){ + +} + +//-------------------------------------------------------------- +void ofApp::cancelPressed(){ + +} diff --git a/examples/android/android3DModelLoaderExample/src/ofApp.h b/scripts/templates/android/src/ofApp.h similarity index 88% rename from examples/android/android3DModelLoaderExample/src/ofApp.h rename to scripts/templates/android/src/ofApp.h index 6c4a3a80424..2fe90435ddb 100644 --- a/examples/android/android3DModelLoaderExample/src/ofApp.h +++ b/scripts/templates/android/src/ofApp.h @@ -2,9 +2,6 @@ #include "ofMain.h" #include "ofxAndroid.h" -#include "ofx3DModelLoader.h" - -#include class ofApp : public ofxAndroidApp{ @@ -33,6 +30,4 @@ class ofApp : public ofxAndroidApp{ bool backPressed(); void okPressed(); void cancelPressed(); - - ofx3DModelLoader squirrelModel; }; diff --git a/examples/android/android3DModelLoaderExample/srcJava/cc/openframeworks/android3DModelLoaderExample/OFActivity.java b/scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java similarity index 97% rename from examples/android/android3DModelLoaderExample/srcJava/cc/openframeworks/android3DModelLoaderExample/OFActivity.java rename to scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java index 3c9433da547..eb37dacf2ab 100644 --- a/examples/android/android3DModelLoaderExample/srcJava/cc/openframeworks/android3DModelLoaderExample/OFActivity.java +++ b/scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java @@ -1,4 +1,4 @@ -package cc.openframeworks.android3DModelLoaderExample; +package cc.openframeworks.TEMPLATE_APP_NAME; import android.os.Bundle; import android.view.KeyEvent; diff --git a/scripts/templates/gitignore/.gitignore b/scripts/templates/gitignore/.gitignore new file mode 100644 index 00000000000..3d355299837 --- /dev/null +++ b/scripts/templates/gitignore/.gitignore @@ -0,0 +1,89 @@ +#.gitignore is a file which makes git ignore files which should +# not go into version control in the first place +# Questions? See +# http://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files +# http://git-scm.com/docs/gitignore + +########################### +# ignore generated binaries +# but not the data folder +########################### + +/bin/* +!/bin/data/ + +######### +# general +######### + +[Bb]uild/ +[Oo]bj/ +*.o +[Dd]ebug*/ +[Rr]elease*/ +*.mode* +*.app/ +*.pyc +.svn/ +*.log + +######################## +# IDE files which should +# be ignored +######################## + +# XCode +*.pbxuser +*.perspective +*.perspectivev3 +*.mode1v3 +*.mode2v3 +# XCode 4 +*.xccheckout +xcuserdata/ + +# Visual Studio +*.sdf +*.opensdf +*.suo +*.pdb +*.ilk +*.aps +ipch/ + +# Eclipse +.metadata +local.properties +.externalToolBuilders + +# Android Studio +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries + +################## +# operating system +################## + +# Linux +*~ +# KDE +.directory +.AppleDouble + +# OSX +.DS_Store +*.swp +*~.nib +# Thumbnails +._* + +# Windows +# Image file caches +Thumbs.db +# Folder config file +Desktop.ini + +# Android +.csettings diff --git a/scripts/templates/gitignore/template.config b/scripts/templates/gitignore/template.config new file mode 100644 index 00000000000..ed7d2d75ee4 --- /dev/null +++ b/scripts/templates/gitignore/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs linuxarmv6l linuxarmv7l +DESCRIPTION=Gitignore template for new projects diff --git a/scripts/templates/gl3.1/src/main.cpp b/scripts/templates/gl3.1/src/main.cpp new file mode 100644 index 00000000000..e35a4e3888b --- /dev/null +++ b/scripts/templates/gl3.1/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(3,1); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl3.1/template.config b/scripts/templates/gl3.1/template.config new file mode 100644 index 00000000000..f158459807f --- /dev/null +++ b/scripts/templates/gl3.1/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=OpenGL 3.1 application with programmable renderer diff --git a/scripts/templates/gl3.2/src/main.cpp b/scripts/templates/gl3.2/src/main.cpp new file mode 100644 index 00000000000..051baa939c6 --- /dev/null +++ b/scripts/templates/gl3.2/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(3,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl3.2/template.config b/scripts/templates/gl3.2/template.config new file mode 100644 index 00000000000..0ce30261fd2 --- /dev/null +++ b/scripts/templates/gl3.2/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=OpenGL 3.2 application with programmable renderer diff --git a/scripts/templates/gl3.3/src/main.cpp b/scripts/templates/gl3.3/src/main.cpp new file mode 100644 index 00000000000..44e78addc92 --- /dev/null +++ b/scripts/templates/gl3.3/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(3,3); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl3.3/template.config b/scripts/templates/gl3.3/template.config new file mode 100644 index 00000000000..c1d0e6f5433 --- /dev/null +++ b/scripts/templates/gl3.3/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=OpenGL 3.3 application with programmable renderer diff --git a/scripts/templates/gl4.0/src/main.cpp b/scripts/templates/gl4.0/src/main.cpp new file mode 100644 index 00000000000..f9530381c28 --- /dev/null +++ b/scripts/templates/gl4.0/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,0); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.0/template.config b/scripts/templates/gl4.0/template.config new file mode 100644 index 00000000000..cbcb09d5a30 --- /dev/null +++ b/scripts/templates/gl4.0/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=OpenGL 4.0 application with programmable renderer diff --git a/scripts/templates/gl4.1/src/main.cpp b/scripts/templates/gl4.1/src/main.cpp new file mode 100644 index 00000000000..4d33dde096b --- /dev/null +++ b/scripts/templates/gl4.1/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,1); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.1/template.config b/scripts/templates/gl4.1/template.config new file mode 100644 index 00000000000..c5406d4b163 --- /dev/null +++ b/scripts/templates/gl4.1/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=OpenGL 4.1 application with programmable renderer diff --git a/scripts/templates/gl4.2/src/main.cpp b/scripts/templates/gl4.2/src/main.cpp new file mode 100644 index 00000000000..9433f0ca8eb --- /dev/null +++ b/scripts/templates/gl4.2/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.2/template.config b/scripts/templates/gl4.2/template.config new file mode 100644 index 00000000000..7afe53a405e --- /dev/null +++ b/scripts/templates/gl4.2/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 msys2 vs +DESCRIPTION=OpenGL 4.2 application with programmable renderer diff --git a/scripts/templates/gl4.3/src/main.cpp b/scripts/templates/gl4.3/src/main.cpp new file mode 100644 index 00000000000..18f0d727c8d --- /dev/null +++ b/scripts/templates/gl4.3/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,3); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.3/template.config b/scripts/templates/gl4.3/template.config new file mode 100644 index 00000000000..b4b2ab05c13 --- /dev/null +++ b/scripts/templates/gl4.3/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 msys2 vs +DESCRIPTION=OpenGL 4.3 application with programmable renderer diff --git a/scripts/templates/gl4.4/src/main.cpp b/scripts/templates/gl4.4/src/main.cpp new file mode 100644 index 00000000000..fe295c22f71 --- /dev/null +++ b/scripts/templates/gl4.4/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,4); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.4/template.config b/scripts/templates/gl4.4/template.config new file mode 100644 index 00000000000..60296e8b6b3 --- /dev/null +++ b/scripts/templates/gl4.4/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 msys2 vs +DESCRIPTION=OpenGL 4.4 application with programmable renderer diff --git a/scripts/templates/gl4.5/src/main.cpp b/scripts/templates/gl4.5/src/main.cpp new file mode 100644 index 00000000000..b176dfb7746 --- /dev/null +++ b/scripts/templates/gl4.5/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLWindowSettings settings; + settings.setGLVersion(4,5); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gl4.5/template.config b/scripts/templates/gl4.5/template.config new file mode 100644 index 00000000000..e31b42675ff --- /dev/null +++ b/scripts/templates/gl4.5/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 msys2 vs +DESCRIPTION=OpenGL 4.5 application with programmable renderer diff --git a/scripts/templates/gles2/src/main.cpp b/scripts/templates/gles2/src/main.cpp new file mode 100644 index 00000000000..fe62360b34c --- /dev/null +++ b/scripts/templates/gles2/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofGLESWindowSettings settings; + settings.setGLESVersion(2); + ofCreateWindow(settings); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/scripts/templates/gles2/template.config b/scripts/templates/gles2/template.config new file mode 100644 index 00000000000..fe285e5f8a8 --- /dev/null +++ b/scripts/templates/gles2/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linuxarmv6l linuxarmv7l +DESCRIPTION=OpenGL ES 2 application with programmable renderer diff --git a/scripts/ios/template/Project.xcconfig b/scripts/templates/ios/Project.xcconfig similarity index 100% rename from scripts/ios/template/Project.xcconfig rename to scripts/templates/ios/Project.xcconfig diff --git a/scripts/ios/template/bin/data/Default-568h@2x~iphone.png b/scripts/templates/ios/bin/data/Default-568h@2x~iphone.png similarity index 100% rename from scripts/ios/template/bin/data/Default-568h@2x~iphone.png rename to scripts/templates/ios/bin/data/Default-568h@2x~iphone.png diff --git a/scripts/ios/template/bin/data/Default.png b/scripts/templates/ios/bin/data/Default.png similarity index 100% rename from scripts/ios/template/bin/data/Default.png rename to scripts/templates/ios/bin/data/Default.png diff --git a/scripts/ios/template/bin/data/Default@2x.png b/scripts/templates/ios/bin/data/Default@2x.png similarity index 100% rename from scripts/ios/template/bin/data/Default@2x.png rename to scripts/templates/ios/bin/data/Default@2x.png diff --git a/scripts/ios/template/bin/data/Default@2x~ipad.png b/scripts/templates/ios/bin/data/Default@2x~ipad.png similarity index 100% rename from scripts/ios/template/bin/data/Default@2x~ipad.png rename to scripts/templates/ios/bin/data/Default@2x~ipad.png diff --git a/scripts/ios/template/bin/data/Default@2x~iphone.png b/scripts/templates/ios/bin/data/Default@2x~iphone.png similarity index 100% rename from scripts/ios/template/bin/data/Default@2x~iphone.png rename to scripts/templates/ios/bin/data/Default@2x~iphone.png diff --git a/scripts/ios/template/bin/data/Default~ipad.png b/scripts/templates/ios/bin/data/Default~ipad.png similarity index 100% rename from scripts/ios/template/bin/data/Default~ipad.png rename to scripts/templates/ios/bin/data/Default~ipad.png diff --git a/scripts/ios/template/bin/data/Default~iphone.png b/scripts/templates/ios/bin/data/Default~iphone.png similarity index 100% rename from scripts/ios/template/bin/data/Default~iphone.png rename to scripts/templates/ios/bin/data/Default~iphone.png diff --git a/scripts/ios/template/bin/data/Icon-72.png b/scripts/templates/ios/bin/data/Icon-72.png similarity index 100% rename from scripts/ios/template/bin/data/Icon-72.png rename to scripts/templates/ios/bin/data/Icon-72.png diff --git a/scripts/ios/template/bin/data/Icon-72@2x.png b/scripts/templates/ios/bin/data/Icon-72@2x.png similarity index 100% rename from scripts/ios/template/bin/data/Icon-72@2x.png rename to scripts/templates/ios/bin/data/Icon-72@2x.png diff --git a/scripts/ios/template/bin/data/Icon.png b/scripts/templates/ios/bin/data/Icon.png similarity index 100% rename from scripts/ios/template/bin/data/Icon.png rename to scripts/templates/ios/bin/data/Icon.png diff --git a/scripts/ios/template/bin/data/Icon@2x.png b/scripts/templates/ios/bin/data/Icon@2x.png similarity index 100% rename from scripts/ios/template/bin/data/Icon@2x.png rename to scripts/templates/ios/bin/data/Icon@2x.png diff --git a/scripts/ios/template/emptyExample.xcodeproj/project.pbxproj b/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj similarity index 97% rename from scripts/ios/template/emptyExample.xcodeproj/project.pbxproj rename to scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj index ccc1e42629b..953aaf31f6a 100644 --- a/scripts/ios/template/emptyExample.xcodeproj/project.pbxproj +++ b/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj @@ -144,6 +144,8 @@ YES GCC_PREFIX_HEADER ofxiOS_Prefix.pch + GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64] + NO INFOPLIST_FILE ofxiOS-Info.plist IPHONEOS_DEPLOYMENT_TARGET @@ -166,6 +168,8 @@ YES GCC_PREFIX_HEADER ofxiOS_Prefix.pch + GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64] + NO INFOPLIST_FILE ofxiOS-Info.plist IPHONEOS_DEPLOYMENT_TARGET @@ -523,11 +527,7 @@ shellPath /bin/sh shellScript - rsync -avz --exclude='.DS_Store' "${SRCROOT}/bin/data/" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" - - - - + rsync -avz --exclude='.DS_Store' "${SRCROOT}/bin/data/" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" BB16E9930F2B1E5900518274 @@ -593,6 +593,17 @@ sourceTree <group> + 6948EE371B920CB800B5AC1A + + children + + isa + PBXGroup + name + local_addons + sourceTree + <group> + BB24DDC910DA781C00E9C588 fileEncoding @@ -614,6 +625,7 @@ 32CA4F630368D1EE00C91783 BB24DDC910DA781C00E9C588 E41D3EE513B3906D00A75A5D + 6948EE371B920CB800B5AC1A E41D3ED613B38FB500A75A5D
    isa @@ -682,10 +694,10 @@ libc++ CODE_SIGN_IDENTITY - CODE_SIGN_IDENTITY[sdk=iphonesimulator*] - CODE_SIGN_IDENTITY[sdk=iphoneos*] iPhone Developer + CODE_SIGN_IDENTITY[sdk=iphonesimulator*] + COMPRESS_PNG_FILES NO GCC_C_LANGUAGE_STANDARD @@ -694,6 +706,8 @@ 0 GCC_SYMBOLS_PRIVATE_EXTERN NO + GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64] + NO GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO NO GCC_WARN_ABOUT_POINTER_SIGNEDNESS @@ -738,10 +752,10 @@ libc++ CODE_SIGN_IDENTITY - CODE_SIGN_IDENTITY[sdk=iphonesimulator*] - CODE_SIGN_IDENTITY[sdk=iphoneos*] iPhone Developer + CODE_SIGN_IDENTITY[sdk=iphonesimulator*] + COMPRESS_PNG_FILES NO GCC_C_LANGUAGE_STANDARD @@ -756,6 +770,8 @@ NO GCC_THUMB_SUPPORT NO + GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64] + NO GCC_WARN_ABOUT_RETURN_TYPE YES GCC_WARN_UNUSED_VARIABLE diff --git a/scripts/ios/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample.xcscheme b/scripts/templates/ios/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample.xcscheme similarity index 100% rename from scripts/ios/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample.xcscheme rename to scripts/templates/ios/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample.xcscheme diff --git a/scripts/ios/template/ofxiOS-Info.plist b/scripts/templates/ios/ofxiOS-Info.plist similarity index 100% rename from scripts/ios/template/ofxiOS-Info.plist rename to scripts/templates/ios/ofxiOS-Info.plist diff --git a/scripts/ios/template/ofxiOS_Prefix.pch b/scripts/templates/ios/ofxiOS_Prefix.pch similarity index 62% rename from scripts/ios/template/ofxiOS_Prefix.pch rename to scripts/templates/ios/ofxiOS_Prefix.pch index 0a09c090df8..fd3401c1759 100644 --- a/scripts/ios/template/ofxiOS_Prefix.pch +++ b/scripts/templates/ios/ofxiOS_Prefix.pch @@ -2,10 +2,6 @@ // Prefix header for all source files of the 'iPhone' target in the 'iPhone' project // -#ifndef __IPHONE_5_0 -#warning "This project uses features only available in iOS SDK 5.0 and later." -#endif - #ifdef __OBJC__ #import #import diff --git a/scripts/ios/template/src/main.mm b/scripts/templates/ios/src/main.mm similarity index 95% rename from scripts/ios/template/src/main.mm rename to scripts/templates/ios/src/main.mm index 3942f4d3b53..afdac8d814e 100644 --- a/scripts/ios/template/src/main.mm +++ b/scripts/templates/ios/src/main.mm @@ -1,5 +1,3 @@ -#include "ofMain.h" -#include "ofAppiOSWindow.h" #include "ofApp.h" int main() { diff --git a/scripts/ios/template/src/ofApp.h b/scripts/templates/ios/src/ofApp.h similarity index 92% rename from scripts/ios/template/src/ofApp.h rename to scripts/templates/ios/src/ofApp.h index 2ee3d8b5e55..51660ad9224 100644 --- a/scripts/ios/template/src/ofApp.h +++ b/scripts/templates/ios/src/ofApp.h @@ -1,8 +1,6 @@ #pragma once -#include "ofMain.h" #include "ofxiOS.h" -#include "ofxiOSExtras.h" class ofApp : public ofxiOSApp { diff --git a/scripts/ios/template/src/ofApp.mm b/scripts/templates/ios/src/ofApp.mm similarity index 100% rename from scripts/ios/template/src/ofApp.mm rename to scripts/templates/ios/src/ofApp.mm diff --git a/scripts/linux/template/linuxarmv6l/Makefile b/scripts/templates/linux/Makefile similarity index 100% rename from scripts/linux/template/linuxarmv6l/Makefile rename to scripts/templates/linux/Makefile diff --git a/scripts/win_cb/template/bin/data/.gitkeep b/scripts/templates/linux/bin/data/.gitkeep similarity index 100% rename from scripts/win_cb/template/bin/data/.gitkeep rename to scripts/templates/linux/bin/data/.gitkeep diff --git a/scripts/templates/linux/config.make b/scripts/templates/linux/config.make new file mode 100644 index 00000000000..836fce7854f --- /dev/null +++ b/scripts/templates/linux/config.make @@ -0,0 +1,141 @@ +################################################################################ +# CONFIGURE PROJECT MAKEFILE (optional) +# This file is where we make project specific configurations. +################################################################################ + +################################################################################ +# OF ROOT +# The location of your root openFrameworks installation +# (default) OF_ROOT = ../../.. +################################################################################ +# OF_ROOT = ../../.. + +################################################################################ +# PROJECT ROOT +# The location of the project - a starting place for searching for files +# (default) PROJECT_ROOT = . (this directory) +# +################################################################################ +# PROJECT_ROOT = . + +################################################################################ +# PROJECT SPECIFIC CHECKS +# This is a project defined section to create internal makefile flags to +# conditionally enable or disable the addition of various features within +# this makefile. For instance, if you want to make changes based on whether +# GTK is installed, one might test that here and create a variable to check. +################################################################################ +# None + +################################################################################ +# PROJECT EXTERNAL SOURCE PATHS +# These are fully qualified paths that are not within the PROJECT_ROOT folder. +# Like source folders in the PROJECT_ROOT, these paths are subject to +# exlclusion via the PROJECT_EXLCUSIONS list. +# +# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXTERNAL_SOURCE_PATHS = + +################################################################################ +# PROJECT EXCLUSIONS +# These makefiles assume that all folders in your current project directory +# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations +# to look for source code. The any folders or files that match any of the +# items in the PROJECT_EXCLUSIONS list below will be ignored. +# +# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete +# string unless teh user adds a wildcard (%) operator to match subdirectories. +# GNU make only allows one wildcard for matching. The second wildcard (%) is +# treated literally. +# +# (default) PROJECT_EXCLUSIONS = (blank) +# +# Will automatically exclude the following: +# +# $(PROJECT_ROOT)/bin% +# $(PROJECT_ROOT)/obj% +# $(PROJECT_ROOT)/%.xcodeproj +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXCLUSIONS = + +################################################################################ +# PROJECT LINKER FLAGS +# These flags will be sent to the linker when compiling the executable. +# +# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs +# +# Note: Leave a leading space when adding list items with the += operator +# +# Currently, shared libraries that are needed are copied to the +# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to +# add a runtime path to search for those shared libraries, since they aren't +# incorporated directly into the final executable application binary. +################################################################################ +# PROJECT_LDFLAGS=-Wl,-rpath=./libs + +################################################################################ +# PROJECT DEFINES +# Create a space-delimited list of DEFINES. The list will be converted into +# CFLAGS with the "-D" flag later in the makefile. +# +# (default) PROJECT_DEFINES = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_DEFINES = + +################################################################################ +# PROJECT CFLAGS +# This is a list of fully qualified CFLAGS required when compiling for this +# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS +# defined in your platform specific core configuration files. These flags are +# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. +# +# (default) PROJECT_CFLAGS = (blank) +# +# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in +# your platform specific configuration file will be applied by default and +# further flags here may not be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CFLAGS = + +################################################################################ +# PROJECT OPTIMIZATION CFLAGS +# These are lists of CFLAGS that are target-specific. While any flags could +# be conditionally added, they are usually limited to optimization flags. +# These flags are added BEFORE the PROJECT_CFLAGS. +# +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) +# +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) +# +# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the +# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration +# file will be applied by default and further optimization flags here may not +# be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = + +################################################################################ +# PROJECT COMPILERS +# Custom compilers can be set for CC and CXX +# (default) PROJECT_CXX = (blank) +# (default) PROJECT_CC = (blank) +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CXX = +# PROJECT_CC = diff --git a/scripts/linux/template/linux/emptyExample_linux.cbp b/scripts/templates/linux/emptyExample_linux.cbp similarity index 100% rename from scripts/linux/template/linux/emptyExample_linux.cbp rename to scripts/templates/linux/emptyExample_linux.cbp diff --git a/scripts/linux/template/linux/emptyExample_linux.workspace b/scripts/templates/linux/emptyExample_linux.workspace similarity index 100% rename from scripts/linux/template/linux/emptyExample_linux.workspace rename to scripts/templates/linux/emptyExample_linux.workspace diff --git a/scripts/templates/linux/qtcreator.qbs b/scripts/templates/linux/qtcreator.qbs new file mode 100644 index 00000000000..34371765d14 --- /dev/null +++ b/scripts/templates/linux/qtcreator.qbs @@ -0,0 +1,55 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: "../../.." + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + of.addons: [ + ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/linux/template/linux64/src/main.cpp b/scripts/templates/linux/src/main.cpp similarity index 100% rename from scripts/linux/template/linux64/src/main.cpp rename to scripts/templates/linux/src/main.cpp diff --git a/scripts/linux/template/linux64/src/ofApp.cpp b/scripts/templates/linux/src/ofApp.cpp similarity index 100% rename from scripts/linux/template/linux64/src/ofApp.cpp rename to scripts/templates/linux/src/ofApp.cpp diff --git a/scripts/linux/template/linux64/src/ofApp.h b/scripts/templates/linux/src/ofApp.h similarity index 100% rename from scripts/linux/template/linux64/src/ofApp.h rename to scripts/templates/linux/src/ofApp.h diff --git a/scripts/linux/template/linuxarmv7l/Makefile b/scripts/templates/linux64/Makefile similarity index 100% rename from scripts/linux/template/linuxarmv7l/Makefile rename to scripts/templates/linux64/Makefile diff --git a/tutorials/shader/05_alphaMasking/bin/data/.gitkeep b/scripts/templates/linux64/bin/data/.gitkeep similarity index 100% rename from tutorials/shader/05_alphaMasking/bin/data/.gitkeep rename to scripts/templates/linux64/bin/data/.gitkeep diff --git a/scripts/templates/linux64/config.make b/scripts/templates/linux64/config.make new file mode 100644 index 00000000000..836fce7854f --- /dev/null +++ b/scripts/templates/linux64/config.make @@ -0,0 +1,141 @@ +################################################################################ +# CONFIGURE PROJECT MAKEFILE (optional) +# This file is where we make project specific configurations. +################################################################################ + +################################################################################ +# OF ROOT +# The location of your root openFrameworks installation +# (default) OF_ROOT = ../../.. +################################################################################ +# OF_ROOT = ../../.. + +################################################################################ +# PROJECT ROOT +# The location of the project - a starting place for searching for files +# (default) PROJECT_ROOT = . (this directory) +# +################################################################################ +# PROJECT_ROOT = . + +################################################################################ +# PROJECT SPECIFIC CHECKS +# This is a project defined section to create internal makefile flags to +# conditionally enable or disable the addition of various features within +# this makefile. For instance, if you want to make changes based on whether +# GTK is installed, one might test that here and create a variable to check. +################################################################################ +# None + +################################################################################ +# PROJECT EXTERNAL SOURCE PATHS +# These are fully qualified paths that are not within the PROJECT_ROOT folder. +# Like source folders in the PROJECT_ROOT, these paths are subject to +# exlclusion via the PROJECT_EXLCUSIONS list. +# +# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXTERNAL_SOURCE_PATHS = + +################################################################################ +# PROJECT EXCLUSIONS +# These makefiles assume that all folders in your current project directory +# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations +# to look for source code. The any folders or files that match any of the +# items in the PROJECT_EXCLUSIONS list below will be ignored. +# +# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete +# string unless teh user adds a wildcard (%) operator to match subdirectories. +# GNU make only allows one wildcard for matching. The second wildcard (%) is +# treated literally. +# +# (default) PROJECT_EXCLUSIONS = (blank) +# +# Will automatically exclude the following: +# +# $(PROJECT_ROOT)/bin% +# $(PROJECT_ROOT)/obj% +# $(PROJECT_ROOT)/%.xcodeproj +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXCLUSIONS = + +################################################################################ +# PROJECT LINKER FLAGS +# These flags will be sent to the linker when compiling the executable. +# +# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs +# +# Note: Leave a leading space when adding list items with the += operator +# +# Currently, shared libraries that are needed are copied to the +# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to +# add a runtime path to search for those shared libraries, since they aren't +# incorporated directly into the final executable application binary. +################################################################################ +# PROJECT_LDFLAGS=-Wl,-rpath=./libs + +################################################################################ +# PROJECT DEFINES +# Create a space-delimited list of DEFINES. The list will be converted into +# CFLAGS with the "-D" flag later in the makefile. +# +# (default) PROJECT_DEFINES = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_DEFINES = + +################################################################################ +# PROJECT CFLAGS +# This is a list of fully qualified CFLAGS required when compiling for this +# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS +# defined in your platform specific core configuration files. These flags are +# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. +# +# (default) PROJECT_CFLAGS = (blank) +# +# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in +# your platform specific configuration file will be applied by default and +# further flags here may not be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CFLAGS = + +################################################################################ +# PROJECT OPTIMIZATION CFLAGS +# These are lists of CFLAGS that are target-specific. While any flags could +# be conditionally added, they are usually limited to optimization flags. +# These flags are added BEFORE the PROJECT_CFLAGS. +# +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) +# +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) +# +# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the +# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration +# file will be applied by default and further optimization flags here may not +# be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = + +################################################################################ +# PROJECT COMPILERS +# Custom compilers can be set for CC and CXX +# (default) PROJECT_CXX = (blank) +# (default) PROJECT_CC = (blank) +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CXX = +# PROJECT_CC = diff --git a/scripts/linux/template/linux64/emptyExample_linux64.cbp b/scripts/templates/linux64/emptyExample_linux64.cbp similarity index 100% rename from scripts/linux/template/linux64/emptyExample_linux64.cbp rename to scripts/templates/linux64/emptyExample_linux64.cbp diff --git a/scripts/linux/template/linux64/emptyExample_linux64.workspace b/scripts/templates/linux64/emptyExample_linux64.workspace similarity index 100% rename from scripts/linux/template/linux64/emptyExample_linux64.workspace rename to scripts/templates/linux64/emptyExample_linux64.workspace diff --git a/scripts/templates/linux64/qtcreator.qbs b/scripts/templates/linux64/qtcreator.qbs new file mode 100644 index 00000000000..34371765d14 --- /dev/null +++ b/scripts/templates/linux64/qtcreator.qbs @@ -0,0 +1,55 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: "../../.." + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + of.addons: [ + ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/linux/template/linuxarmv6l/src/main.cpp b/scripts/templates/linux64/src/main.cpp similarity index 100% rename from scripts/linux/template/linuxarmv6l/src/main.cpp rename to scripts/templates/linux64/src/main.cpp diff --git a/scripts/linux/template/linuxarmv6l/src/ofApp.cpp b/scripts/templates/linux64/src/ofApp.cpp similarity index 100% rename from scripts/linux/template/linuxarmv6l/src/ofApp.cpp rename to scripts/templates/linux64/src/ofApp.cpp diff --git a/scripts/linux/template/linuxarmv6l/src/ofApp.h b/scripts/templates/linux64/src/ofApp.h similarity index 100% rename from scripts/linux/template/linuxarmv6l/src/ofApp.h rename to scripts/templates/linux64/src/ofApp.h diff --git a/scripts/osx/template/Makefile b/scripts/templates/linuxarmv6l/Makefile similarity index 100% rename from scripts/osx/template/Makefile rename to scripts/templates/linuxarmv6l/Makefile diff --git a/tutorials/shader/06_multiTexture/bin/data/.gitkeep b/scripts/templates/linuxarmv6l/bin/data/.gitkeep similarity index 100% rename from tutorials/shader/06_multiTexture/bin/data/.gitkeep rename to scripts/templates/linuxarmv6l/bin/data/.gitkeep diff --git a/scripts/linux/template/linuxarmv6l/config.make b/scripts/templates/linuxarmv6l/config.make similarity index 100% rename from scripts/linux/template/linuxarmv6l/config.make rename to scripts/templates/linuxarmv6l/config.make diff --git a/scripts/linux/template/linuxarmv6l/emptyExample_linuxarmv6l.cbp b/scripts/templates/linuxarmv6l/emptyExample_linuxarmv6l.cbp similarity index 100% rename from scripts/linux/template/linuxarmv6l/emptyExample_linuxarmv6l.cbp rename to scripts/templates/linuxarmv6l/emptyExample_linuxarmv6l.cbp diff --git a/scripts/linux/template/linuxarmv6l/emptyExample_linuxarmv6l.workspace b/scripts/templates/linuxarmv6l/emptyExample_linuxarmv6l.workspace similarity index 100% rename from scripts/linux/template/linuxarmv6l/emptyExample_linuxarmv6l.workspace rename to scripts/templates/linuxarmv6l/emptyExample_linuxarmv6l.workspace diff --git a/scripts/linux/template/linuxarmv7l/src/main.cpp b/scripts/templates/linuxarmv6l/src/main.cpp similarity index 100% rename from scripts/linux/template/linuxarmv7l/src/main.cpp rename to scripts/templates/linuxarmv6l/src/main.cpp diff --git a/scripts/linux/template/linuxarmv7l/src/ofApp.cpp b/scripts/templates/linuxarmv6l/src/ofApp.cpp similarity index 100% rename from scripts/linux/template/linuxarmv7l/src/ofApp.cpp rename to scripts/templates/linuxarmv6l/src/ofApp.cpp diff --git a/scripts/linux/template/linuxarmv7l/src/ofApp.h b/scripts/templates/linuxarmv6l/src/ofApp.h similarity index 100% rename from scripts/linux/template/linuxarmv7l/src/ofApp.h rename to scripts/templates/linuxarmv6l/src/ofApp.h diff --git a/scripts/templates/linuxarmv7l/Makefile b/scripts/templates/linuxarmv7l/Makefile new file mode 100644 index 00000000000..8d8e4c0943a --- /dev/null +++ b/scripts/templates/linuxarmv7l/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../..) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/tutorials/shader/07_fboAlphaMask/bin/data/.gitkeep b/scripts/templates/linuxarmv7l/bin/data/.gitkeep similarity index 100% rename from tutorials/shader/07_fboAlphaMask/bin/data/.gitkeep rename to scripts/templates/linuxarmv7l/bin/data/.gitkeep diff --git a/scripts/linux/template/linuxarmv7l/config.make b/scripts/templates/linuxarmv7l/config.make similarity index 100% rename from scripts/linux/template/linuxarmv7l/config.make rename to scripts/templates/linuxarmv7l/config.make diff --git a/scripts/linux/template/linuxarmv7l/emptyExample_linuxarmv7l.cbp b/scripts/templates/linuxarmv7l/emptyExample_linuxarmv7l.cbp similarity index 100% rename from scripts/linux/template/linuxarmv7l/emptyExample_linuxarmv7l.cbp rename to scripts/templates/linuxarmv7l/emptyExample_linuxarmv7l.cbp diff --git a/scripts/linux/template/linuxarmv7l/emptyExample_linuxarmv7l.workspace b/scripts/templates/linuxarmv7l/emptyExample_linuxarmv7l.workspace similarity index 100% rename from scripts/linux/template/linuxarmv7l/emptyExample_linuxarmv7l.workspace rename to scripts/templates/linuxarmv7l/emptyExample_linuxarmv7l.workspace diff --git a/scripts/osx/template/src/main.cpp b/scripts/templates/linuxarmv7l/src/main.cpp similarity index 100% rename from scripts/osx/template/src/main.cpp rename to scripts/templates/linuxarmv7l/src/main.cpp diff --git a/scripts/osx/template/src/ofApp.cpp b/scripts/templates/linuxarmv7l/src/ofApp.cpp similarity index 100% rename from scripts/osx/template/src/ofApp.cpp rename to scripts/templates/linuxarmv7l/src/ofApp.cpp diff --git a/scripts/osx/template/src/ofApp.h b/scripts/templates/linuxarmv7l/src/ofApp.h similarity index 100% rename from scripts/osx/template/src/ofApp.h rename to scripts/templates/linuxarmv7l/src/ofApp.h diff --git a/scripts/templates/msys2/Makefile b/scripts/templates/msys2/Makefile new file mode 100644 index 00000000000..8d8e4c0943a --- /dev/null +++ b/scripts/templates/msys2/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../..) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/tutorials/shader/09_gaussianBlurFilter/bin/data/.gitkeep b/scripts/templates/msys2/bin/data/.gitkeep similarity index 100% rename from tutorials/shader/09_gaussianBlurFilter/bin/data/.gitkeep rename to scripts/templates/msys2/bin/data/.gitkeep diff --git a/scripts/templates/msys2/config.make b/scripts/templates/msys2/config.make new file mode 100644 index 00000000000..836fce7854f --- /dev/null +++ b/scripts/templates/msys2/config.make @@ -0,0 +1,141 @@ +################################################################################ +# CONFIGURE PROJECT MAKEFILE (optional) +# This file is where we make project specific configurations. +################################################################################ + +################################################################################ +# OF ROOT +# The location of your root openFrameworks installation +# (default) OF_ROOT = ../../.. +################################################################################ +# OF_ROOT = ../../.. + +################################################################################ +# PROJECT ROOT +# The location of the project - a starting place for searching for files +# (default) PROJECT_ROOT = . (this directory) +# +################################################################################ +# PROJECT_ROOT = . + +################################################################################ +# PROJECT SPECIFIC CHECKS +# This is a project defined section to create internal makefile flags to +# conditionally enable or disable the addition of various features within +# this makefile. For instance, if you want to make changes based on whether +# GTK is installed, one might test that here and create a variable to check. +################################################################################ +# None + +################################################################################ +# PROJECT EXTERNAL SOURCE PATHS +# These are fully qualified paths that are not within the PROJECT_ROOT folder. +# Like source folders in the PROJECT_ROOT, these paths are subject to +# exlclusion via the PROJECT_EXLCUSIONS list. +# +# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXTERNAL_SOURCE_PATHS = + +################################################################################ +# PROJECT EXCLUSIONS +# These makefiles assume that all folders in your current project directory +# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations +# to look for source code. The any folders or files that match any of the +# items in the PROJECT_EXCLUSIONS list below will be ignored. +# +# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete +# string unless teh user adds a wildcard (%) operator to match subdirectories. +# GNU make only allows one wildcard for matching. The second wildcard (%) is +# treated literally. +# +# (default) PROJECT_EXCLUSIONS = (blank) +# +# Will automatically exclude the following: +# +# $(PROJECT_ROOT)/bin% +# $(PROJECT_ROOT)/obj% +# $(PROJECT_ROOT)/%.xcodeproj +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXCLUSIONS = + +################################################################################ +# PROJECT LINKER FLAGS +# These flags will be sent to the linker when compiling the executable. +# +# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs +# +# Note: Leave a leading space when adding list items with the += operator +# +# Currently, shared libraries that are needed are copied to the +# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to +# add a runtime path to search for those shared libraries, since they aren't +# incorporated directly into the final executable application binary. +################################################################################ +# PROJECT_LDFLAGS=-Wl,-rpath=./libs + +################################################################################ +# PROJECT DEFINES +# Create a space-delimited list of DEFINES. The list will be converted into +# CFLAGS with the "-D" flag later in the makefile. +# +# (default) PROJECT_DEFINES = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_DEFINES = + +################################################################################ +# PROJECT CFLAGS +# This is a list of fully qualified CFLAGS required when compiling for this +# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS +# defined in your platform specific core configuration files. These flags are +# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. +# +# (default) PROJECT_CFLAGS = (blank) +# +# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in +# your platform specific configuration file will be applied by default and +# further flags here may not be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CFLAGS = + +################################################################################ +# PROJECT OPTIMIZATION CFLAGS +# These are lists of CFLAGS that are target-specific. While any flags could +# be conditionally added, they are usually limited to optimization flags. +# These flags are added BEFORE the PROJECT_CFLAGS. +# +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) +# +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) +# +# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the +# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration +# file will be applied by default and further optimization flags here may not +# be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = + +################################################################################ +# PROJECT COMPILERS +# Custom compilers can be set for CC and CXX +# (default) PROJECT_CXX = (blank) +# (default) PROJECT_CC = (blank) +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CXX = +# PROJECT_CC = diff --git a/scripts/templates/msys2/icon.rc b/scripts/templates/msys2/icon.rc new file mode 100644 index 00000000000..7cef03b1552 --- /dev/null +++ b/scripts/templates/msys2/icon.rc @@ -0,0 +1,7 @@ +//TODO: figure out how to do debug and release icons +#ifdef _DEBUG + MAINICON ICON "../../../libs/openFrameworksCompiled/project/msys2/icon-debug.ico" +#else + MAINICON ICON "../../../libs/openFrameworksCompiled/project/msys2/icon.ico" +#endif + diff --git a/scripts/templates/msys2/qtcreator.qbs b/scripts/templates/msys2/qtcreator.qbs new file mode 100644 index 00000000000..34371765d14 --- /dev/null +++ b/scripts/templates/msys2/qtcreator.qbs @@ -0,0 +1,55 @@ +import qbs +import qbs.Process +import qbs.File +import qbs.FileInfo +import qbs.TextFile +import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp + +Project{ + property string of_root: "../../.." + + ofApp { + name: { return FileInfo.baseName(path) } + + files: [ + 'src/main.cpp', + 'src/ofApp.cpp', + 'src/ofApp.h', + ] + + of.addons: [ + ] + + // additional flags for the project. the of module sets some + // flags by default to add the core libraries, search paths... + // this flags can be augmented through the following properties: + of.pkgConfigs: [] // list of additional system pkgs to include + of.includePaths: [] // include search paths + of.cFlags: [] // flags passed to the c compiler + of.cxxFlags: [] // flags passed to the c++ compiler + of.linkerFlags: [] // flags passed to the linker + of.defines: [] // defines are passed as -D to the compiler + // and can be checked with #ifdef or #if in the code + + // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html + // eg: this will enable ccache when compiling + // + // cpp.compilerWrapper: 'ccache' + + Depends{ + name: "cpp" + } + + // common rules that parse the include search paths, core libraries... + Depends{ + name: "of" + } + + // dependency with the OF library + Depends{ + name: "openFrameworks" + } + } + + references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")] +} diff --git a/scripts/vs/template/src/main.cpp b/scripts/templates/msys2/src/main.cpp similarity index 100% rename from scripts/vs/template/src/main.cpp rename to scripts/templates/msys2/src/main.cpp diff --git a/scripts/vs/template/src/ofApp.cpp b/scripts/templates/msys2/src/ofApp.cpp similarity index 100% rename from scripts/vs/template/src/ofApp.cpp rename to scripts/templates/msys2/src/ofApp.cpp diff --git a/scripts/vs/template/src/ofApp.h b/scripts/templates/msys2/src/ofApp.h similarity index 100% rename from scripts/vs/template/src/ofApp.h rename to scripts/templates/msys2/src/ofApp.h diff --git a/scripts/templates/nofmod/Project.xcconfig b/scripts/templates/nofmod/Project.xcconfig new file mode 100644 index 00000000000..ff311cdc768 --- /dev/null +++ b/scripts/templates/nofmod/Project.xcconfig @@ -0,0 +1,26 @@ +//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. +//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED +OF_PATH = ../../.. + +//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE +#include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" + +//ICONS - NEW IN 0072 +ICON_NAME_DEBUG = icon-debug.icns +ICON_NAME_RELEASE = icon.icns +ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/ + +//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to: +//ICON_FILE_PATH = bin/data/ + +//Libs without Poco +OF_CORE_LIBS_REDUCED = $(LIB_POCO) $(LIB_TESS) $(LIB_GLEW) $(LIB_CAIRO1) $(LIB_CAIRO2) $(LIB_CAIRO3) $(LIB_RTAUDIO) $(LIB_OPENSSL1) $(LIB_OPENSSL2) $(LIB_GLFW) $(LIB_FREEIMAGE) $(LIB_FREETYPE) $(LIB_BOOST_FS) $(LIB_BOOST_SYSTEM) + +OF_CORE_HEADERS_REDUCED = $(HEADER_OF) $(HEADER_POCO) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_CAIRO) $(HEADER_RTAUDIO) $(HEADER_GLFW) $(HEADER_BOOST) $(HEADER_UTF8) $(HEADER_SSL) + +OF_CORE_FRAMEWORKS_REDUCED = -framework Accelerate -framework AGL -framework AppKit -framework ApplicationServices -framework AudioToolbox -framework AVFoundation -framework Cocoa -framework CoreAudio -framework CoreFoundation -framework CoreMedia -framework CoreServices -framework CoreVideo -framework IOKit -framework OpenGL -framework QuartzCore -framework QuickTime -framework QTKit -framework GLUT + + + +OTHER_LDFLAGS = $(OF_CORE_LIBS_REDUCED) $(OF_CORE_FRAMEWORKS_REDUCED) +HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS_REDUCED) diff --git a/scripts/templates/nofmod/template.config b/scripts/templates/nofmod/template.config new file mode 100644 index 00000000000..017296bb59c --- /dev/null +++ b/scripts/templates/nofmod/template.config @@ -0,0 +1,2 @@ +PLATFORMS=osx +DESCRIPTION=OSX application with no FMOD linking diff --git a/scripts/templates/nowindow/src/main.cpp b/scripts/templates/nowindow/src/main.cpp new file mode 100644 index 00000000000..59d251f2755 --- /dev/null +++ b/scripts/templates/nowindow/src/main.cpp @@ -0,0 +1,15 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + ofRunMainLoop(); + +} diff --git a/scripts/templates/nowindow/template.config b/scripts/templates/nowindow/template.config new file mode 100644 index 00000000000..4b24253a579 --- /dev/null +++ b/scripts/templates/nowindow/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=No window application diff --git a/scripts/templates/osx/Makefile b/scripts/templates/osx/Makefile new file mode 100644 index 00000000000..8d8e4c0943a --- /dev/null +++ b/scripts/templates/osx/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../..) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/scripts/osx/template/Project.xcconfig b/scripts/templates/osx/Project.xcconfig similarity index 100% rename from scripts/osx/template/Project.xcconfig rename to scripts/templates/osx/Project.xcconfig diff --git a/scripts/templates/osx/bin/data/.gitkeep b/scripts/templates/osx/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/scripts/osx/template/config.make b/scripts/templates/osx/config.make similarity index 100% rename from scripts/osx/template/config.make rename to scripts/templates/osx/config.make diff --git a/scripts/osx/template/emptyExample.xcodeproj/project.pbxproj b/scripts/templates/osx/emptyExample.xcodeproj/project.pbxproj similarity index 83% rename from scripts/osx/template/emptyExample.xcodeproj/project.pbxproj rename to scripts/templates/osx/emptyExample.xcodeproj/project.pbxproj index 761343420c7..9bd949ef299 100644 --- a/scripts/osx/template/emptyExample.xcodeproj/project.pbxproj +++ b/scripts/templates/osx/emptyExample.xcodeproj/project.pbxproj @@ -10,6 +10,117 @@ 46 objects + 6948EE371B920CB800B5AC1A + + children + + isa + PBXGroup + name + local_addons + sourceTree + <group> + + 8466F1851C04CA0E00918B1C + + buildActionMask + 12 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + # ---- Code Sign App Package ---- + +# WARNING: You may have to run Clean in Xcode after changing CODE_SIGN_IDENTITY! + +# Verify that $CODE_SIGN_IDENTITY is set +if [ -z "${CODE_SIGN_IDENTITY}" ] ; then +echo "CODE_SIGN_IDENTITY needs to be set for framework code-signing" +exit 0 +fi + +if [ -z "${CODE_SIGN_ENTITLEMENTS}" ] ; then +echo "CODE_SIGN_ENTITLEMENTS needs to be set for framework code-signing!" + +if [ "${CONFIGURATION}" = "Release" ] ; then +exit 1 +else +# Code-signing is optional for non-release builds. +exit 0 +fi +fi + +ITEMS="" + +FRAMEWORKS_DIR="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +echo "$FRAMEWORKS_DIR" +if [ -d "$FRAMEWORKS_DIR" ] ; then +FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -name "*.dylib" -or -name "*.bundle" | sed -e "s/\(.*framework\)/\1\/Versions\/A\//") +RESULT=$? +if [[ $RESULT != 0 ]] ; then +exit 1 +fi + +ITEMS="${FRAMEWORKS}" +fi + +LOGINITEMS_DIR="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/" +if [ -d "$LOGINITEMS_DIR" ] ; then +LOGINITEMS=$(find "${LOGINITEMS_DIR}" -depth -type d -name "*.app") +RESULT=$? +if [[ $RESULT != 0 ]] ; then +exit 1 +fi + +ITEMS="${ITEMS}"$'\n'"${LOGINITEMS}" +fi + +# Prefer the expanded name, if available. +CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}" +if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then +# Fall back to old behavior. +CODE_SIGN_IDENTITY_FOR_ITEMS="${CODE_SIGN_IDENTITY}" +fi + +echo "Identity:" +echo "${CODE_SIGN_IDENTITY_FOR_ITEMS}" + +echo "Entitlements:" +echo "${CODE_SIGN_ENTITLEMENTS}" + +echo "Found:" +echo "${ITEMS}" + +# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below. +SAVED_IFS=$IFS +IFS=$(echo -en "\n\b") + +# Loop through all items. +for ITEM in $ITEMS; +do +echo "Signing '${ITEM}'" +codesign --force --verbose --sign "${CODE_SIGN_IDENTITY_FOR_ITEMS}" --entitlements "${CODE_SIGN_ENTITLEMENTS}" "${ITEM}" +RESULT=$? +if [[ $RESULT != 0 ]] ; then +echo "Failed to sign '${ITEM}'." +IFS=$SAVED_IFS +exit 1 +fi +done + +# Restore $IFS. +IFS=$SAVED_IFS + + BB4B014C10F69532006C3DED children @@ -89,6 +200,7 @@ E4B69E1C0A3A1BDC003C02F2 E4EEC9E9138DF44700A80321 BB4B014C10F69532006C3DED + 6948EE371B920CB800B5AC1A E4B69B5B0A3A1756003C02F2
    isa @@ -299,6 +411,7 @@ E4B69B590A3A1756003C02F2 E4B6FFFD0C3F9AB9008CF71C E4C2427710CC5ABF004149E2 + 8466F1851C04CA0E00918B1C
    buildRules @@ -374,7 +487,7 @@ INFOPLIST_FILE openFrameworks-Info.plist INSTALL_PATH - $(HOME)/Applications + /Applications LIBRARY_SEARCH_PATHS $(inherited) PRODUCT_NAME @@ -415,7 +528,7 @@ INFOPLIST_FILE openFrameworks-Info.plist INSTALL_PATH - $(HOME)/Applications + /Applications LIBRARY_SEARCH_PATHS $(inherited) PRODUCT_NAME @@ -534,9 +647,15 @@ shellPath /bin/sh shellScript - rsync -aved ../../../libs/fmodex/lib/osx/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/"; install_name_tool -change ./libfmodex.dylib @executable_path/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME"; -mkdir -p "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/" + mkdir -p "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/" +# Copy default icon file into App/Resources rsync -aved "$ICON_FILE" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/" +# Copy bin/data into App/Resources +rsync -avz --exclude='.DS_Store' "${SRCROOT}/bin/data/" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/data/" +# Copy libfmod and change install directory for fmod to run +rsync -aved ../../../libs/fmodex/lib/osx/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/"; +install_name_tool -change @executable_path/libfmodex.dylib @executable_path/../Frameworks/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME"; +# Copy GLUT framework (must remove for AppStore submissions) rsync -aved ../../../libs/glut/lib/osx/GLUT.framework "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/" diff --git a/scripts/osx/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Debug.xcscheme b/scripts/templates/osx/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Debug.xcscheme similarity index 100% rename from scripts/osx/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Debug.xcscheme rename to scripts/templates/osx/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Debug.xcscheme diff --git a/scripts/osx/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Release.xcscheme b/scripts/templates/osx/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Release.xcscheme similarity index 100% rename from scripts/osx/template/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Release.xcscheme rename to scripts/templates/osx/emptyExample.xcodeproj/xcshareddata/xcschemes/emptyExample Release.xcscheme diff --git a/scripts/osx/template/openFrameworks-Info.plist b/scripts/templates/osx/openFrameworks-Info.plist similarity index 100% rename from scripts/osx/template/openFrameworks-Info.plist rename to scripts/templates/osx/openFrameworks-Info.plist diff --git a/scripts/win_cb/template/src/main.cpp b/scripts/templates/osx/src/main.cpp similarity index 100% rename from scripts/win_cb/template/src/main.cpp rename to scripts/templates/osx/src/main.cpp diff --git a/scripts/win_cb/template/src/ofApp.cpp b/scripts/templates/osx/src/ofApp.cpp similarity index 100% rename from scripts/win_cb/template/src/ofApp.cpp rename to scripts/templates/osx/src/ofApp.cpp diff --git a/scripts/win_cb/template/src/ofApp.h b/scripts/templates/osx/src/ofApp.h similarity index 100% rename from scripts/win_cb/template/src/ofApp.h rename to scripts/templates/osx/src/ofApp.h diff --git a/scripts/templates/unittest/src/main.cpp b/scripts/templates/unittest/src/main.cpp new file mode 100644 index 00000000000..6f96ce2ad8b --- /dev/null +++ b/scripts/templates/unittest/src/main.cpp @@ -0,0 +1,22 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" + +class ofApp: public ofxUnitTestsApp{ + void run(){ + + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + +} diff --git a/scripts/templates/unittest/template.config b/scripts/templates/unittest/template.config new file mode 100644 index 00000000000..c1f670808fe --- /dev/null +++ b/scripts/templates/unittest/template.config @@ -0,0 +1,2 @@ +PLATFORMS=linux linux64 osx msys2 vs +DESCRIPTION=Unit test no window application diff --git a/scripts/templates/vs/bin/data/.gitkeep b/scripts/templates/vs/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/scripts/vs/template/emptyExample.sln b/scripts/templates/vs/emptyExample.sln similarity index 98% rename from scripts/vs/template/emptyExample.sln rename to scripts/templates/vs/emptyExample.sln index 9461302dc34..db100687fe7 100644 --- a/scripts/vs/template/emptyExample.sln +++ b/scripts/templates/vs/emptyExample.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 +# Visual Studio 14 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emptyExample", "emptyExample.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" diff --git a/scripts/vs/template/emptyExample.vcxproj b/scripts/templates/vs/emptyExample.vcxproj similarity index 100% rename from scripts/vs/template/emptyExample.vcxproj rename to scripts/templates/vs/emptyExample.vcxproj diff --git a/scripts/vs/template/emptyExample.vcxproj.filters b/scripts/templates/vs/emptyExample.vcxproj.filters similarity index 100% rename from scripts/vs/template/emptyExample.vcxproj.filters rename to scripts/templates/vs/emptyExample.vcxproj.filters diff --git a/scripts/vs/template/emptyExample.vcxproj.user b/scripts/templates/vs/emptyExample.vcxproj.user similarity index 100% rename from scripts/vs/template/emptyExample.vcxproj.user rename to scripts/templates/vs/emptyExample.vcxproj.user diff --git a/scripts/vs/template/icon.rc b/scripts/templates/vs/icon.rc similarity index 100% rename from scripts/vs/template/icon.rc rename to scripts/templates/vs/icon.rc diff --git a/scripts/templates/vs/src/main.cpp b/scripts/templates/vs/src/main.cpp new file mode 100644 index 00000000000..e57370b26ee --- /dev/null +++ b/scripts/templates/vs/src/main.cpp @@ -0,0 +1,13 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofSetupOpenGL(1024,768,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 ofApp()); + +} diff --git a/scripts/templates/vs/src/ofApp.cpp b/scripts/templates/vs/src/ofApp.cpp new file mode 100644 index 00000000000..0d3236e7cf9 --- /dev/null +++ b/scripts/templates/vs/src/ofApp.cpp @@ -0,0 +1,71 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup(){ + +} + +//-------------------------------------------------------------- +void ofApp::update(){ + +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseEntered(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseExited(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/scripts/templates/vs/src/ofApp.h b/scripts/templates/vs/src/ofApp.h new file mode 100644 index 00000000000..a9a1eea2ad6 --- /dev/null +++ b/scripts/templates/vs/src/ofApp.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ofMain.h" + +class ofApp : public ofBaseApp{ + + 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 mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + +}; diff --git a/scripts/vs/compileAllExamples.cmd b/scripts/vs/compileAllExamples.cmd index df70037050a..b9ce8f413b6 100644 --- a/scripts/vs/compileAllExamples.cmd +++ b/scripts/vs/compileAllExamples.cmd @@ -1,2 +1,2 @@ @echo off -setupCommandLine 120 build both devenv +setupCommandLine 140 build both Win32 devenv diff --git a/scripts/vs/setupCommandLine.cmd b/scripts/vs/setupCommandLine.cmd index 2f368db4c7f..ab3e2c24e55 100644 --- a/scripts/vs/setupCommandLine.cmd +++ b/scripts/vs/setupCommandLine.cmd @@ -1,82 +1,134 @@ @echo off +setlocal enabledelayedexpansion rem setupCommandLine.cmd rem rem openFrameworks C++ Libraries command-line build script -rem for MS Visual Studio 2012 +rem for Microsoft Visual Studio rem rem Usage rem ----- -rem setupCommandLine VS_VERSION [ACTION] [CONFIGURATION] [TOOL] -rem VS_VERSION: 80|90|100|110|120 +rem setupCommandLine VS_VERSION [ACTION] [CONFIGURATION] [PLATFORM] [TOOL] +rem VS_VERSION: 100|110|120|140 rem ACTION: build|rebuild|clean rem CONFIGURATION: release|debug|both +rem PLATFORM: Win32|x64 rem TOOL: devenv|vcexpress|wdexpress|msbuild - - echo /////////////////////////////// echo / openFrameworks build script / echo /////////////////////////////// echo. -rem /////////////////////////////// -rem / Load Visual C++ Environment / -rem /////////////////////////////// -:loader +echo Loading variables -echo ++++ Loading variables -if "%1"=="" (set VS_VERSION=110) else (set VS_VERSION=%1) -if not defined VCINSTALLDIR ( - if "%VS_VERSION%"=="80" (call "%VS80COMNTOOLS%vsvars32.bat") else ( - if "%VS_VERSION%"=="90" (call "%VS90COMNTOOLS%vsvars32.bat") else ( - if "%VS_VERSION%"=="100" (call "%VS100COMNTOOLS%vsvars32.bat") else ( - if "%VS_VERSION%"=="110" (call "%VS110COMNTOOLS%vsvars32.bat") else ( - if "%VS_VERSION%"=="120" (call "%VS120COMNTOOLS%vsvars32.bat") - )))) +rem VS_VERSION {100 | 110 | 120 | 140} +if "%1"=="" ( + echo VS_VERSION is required argument. +) +set VS_VERSION=vs%1 +set VS_64_BIT_ENV=VC\bin\x86_amd64\vcvarsx86_amd64.bat - if not defined VSINSTALLDIR ( - echo Error: No Visual C++ environment found. - echo Please run this script from a Visual Studio Command Prompt - echo or run "%%VSnnCOMNTOOLS%%\vsvars32.bat" first. - ) else (echo ++++ Variables loaded)) +rem PLATFORM [Win32|x64|WinCE|WEC2013] +set PLATFORM=%4 +if "%PLATFORM%"=="" ( + set PLATFORM=Win32 +) +if not %PLATFORM%==Win32 ( + if not %PLATFORM%==x64 ( + echo Invalid plateform. + goto :EOF + ) +) -rem //////////////////////////// -rem / Init variables - options / -rem //////////////////////////// -:options +rem Load Visual C++ Environment +if not defined VCINSTALLDIR ( + if %VS_VERSION%==vs100 ( + if %PLATFORM%==x64 ( + call "%VS100COMNTOOLS%..\..\%VS_64_BIT_ENV%" + ) else ( + call "%VS100COMNTOOLS%vsvars32.bat" + ) + ) else ( + if %VS_VERSION%==vs110 ( + if %PLATFORM%==x64 ( + call "%VS110COMNTOOLS%..\..\%VS_64_BIT_ENV%" + ) else ( + call "%VS110COMNTOOLS%vsvars32.bat" + ) + ) else ( + if %VS_VERSION%==vs120 ( + if %PLATFORM%==x64 ( + call "%VS120COMNTOOLS%..\..\%VS_64_BIT_ENV%" + ) else ( + call "%VS120COMNTOOLS%vsvars32.bat + ) + ) else ( + if %VS_VERSION%==vs140 ( + if %PLATFORM%==x64 ( + call "%VS140COMNTOOLS%..\..\%VS_64_BIT_ENV%" + ) else ( + call "%VS140COMNTOOLS%vsvars32.bat + ) + ) + ) + ) + ) +) +if not defined VSINSTALLDIR ( + echo Error: No Visual C++ environment found. + echo Please run this script from a Visual Studio Command Prompt + echo or run "%%VSnnCOMNTOOLS%%\vsvars32.bat" first. + goto :EOF +) else (echo Variables loaded) rem TOOL [devenv|vcexpress|wdexpress|msbuild] -if "%4"=="" ( - set BUILD_TOOL=devenv - if "%VS_VERSION%"=="100" (set BUILD_TOOL=msbuild) - if "%VS_VERSION%"=="110" (set BUILD_TOOL=msbuild) - if "%VS_VERSION%"=="120" (set BUILD_TOOL=msbuild) -) else (set BUILD_TOOL=%4) -if "%VS_VERSION%"==100 (goto action) -if "%VS_VERSION%"==110 (goto action) -if "%VS_VERSION%"==120 (goto action) -if "%BUILD_TOOL%"=="msbuild" ( - if not "%VS_VERSION%"=="120" ( - if not "%VS_VERSION%"=="110" ( - if not "%VS_VERSION%"=="100" ( - echo "Cannot use msbuild with Visual Studio 2008 or earlier." - exit))) +if "%5"=="" ( + set BUILD_TOOL=msbuild +) else ( + set BUILD_TOOL=%5 +) +if %BUILD_TOOL%==msbuild ( + if not %VS_VERSION%==vs140 ( + if not %VS_VERSION%==vs120 ( + if not %VS_VERSION%==vs110 ( + if not %VS_VERSION%==vs100 ( + echo "Cannot use msbuild with Visual Studio 2008 or earlier." + goto :EOF + ) + ) + ) + ) +) rem ACTION [build|rebuild|clean] set ACTION=%2 -if not "%ACTION%"=="build" ( - if not "%ACTION%"=="rebuild" ( +if not %ACTION%==build ( + if not %ACTION%==rebuild ( if not "%ACTION%"=="" ( - if not "%ACTION%"=="clean" exit))) + if not %ACTION%==clean ( + echo Invalid action. + goto :EOF + ) + ) + ) +) if "%ACTION%"=="" (set ACTION="build") rem CONFIGURATION [release|debug|both] set CONFIGURATION=%3 -if not "%CONFIGURATION%"=="release" ( - if not "%CONFIGURATION%"=="debug" ( +if not %CONFIGURATION%==release ( + if not %CONFIGURATION%==debug ( if not "%CONFIGURATION%"=="" ( - if not "%CONFIGURATION%"=="both" exit))) + if not %CONFIGURATION%==both ( + echo Invalid configuration. + goto :EOF + ) + ) + ) +) + +echo Environment ready rem /////////////// rem / Builder C++ / @@ -89,11 +141,9 @@ for /d %%X in (..\..\examples\*) do ( cd %%Y for %%Z in (*.sln) do ( echo. - echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - echo ++++ Building [%%Z] - echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo ++++++++++++++++++++++++++++++++++++ + echo ++ Building [%%Z] + echo ++++++++++++++++++++++++++++++++++++ echo. if "%BUILD_TOOL%"=="msbuild" ( @@ -104,4 +154,5 @@ for /d %%X in (..\..\examples\*) do ( if not "%CONFIGURATION%"=="debug" (%BUILD_TOOL% "%CD%\%%X\%%Y\%%Z" /%ACTION% Release /nologo)) ) cd ../ - )) + ) +) diff --git a/scripts/win_cb/codeblocks_wizard/README.txt b/scripts/win_cb/codeblocks_wizard/README.txt deleted file mode 100644 index 5e9e3773491..00000000000 --- a/scripts/win_cb/codeblocks_wizard/README.txt +++ /dev/null @@ -1,31 +0,0 @@ - -CODEBLOCKS WIZARD FOR WINDOWS INSTALLATION INSTRUCTIONS ------------------------------------------------------ -Python is required to run the createProjects.py python script that is used by this wizard. - -Install python: -http://www.python.org/getit/ -Do not change the default installation location (i.e. c:\Python26) -This version was tested with Python 2.6.6 - -Install lxml (the MS Windows installer version) -http://pypi.python.org/pypi/lxml/2.3 - -Install argparse (Windows installer): -http://pypi.python.org/pypi/argparse/1.1 - -Copy the "openframeworks" folder in the same directory as this README to the following location: -"C:\Program Files\CodeBlocks\share\CodeBlocks\templates\wizard" - -Then do the following: - 1. Open the global registration script for editing at C:\Program Files\CodeBlocks\share\CodeBlocks\templates\wizard\config.script - 2. Add the following line to the main RegisterWizards() function: - RegisterWizard(wizCustom, _T("openframeworks"), _T("OpenFrameworks"), _T("2D/3D Graphics")); - 3. Press CTRL+S (save the file) - 4. Close and restart CodeBlocks - - The Wizard is now installed. To use it, select File->New->Custom and select the OpenFrameworks template. - Then fill in your project details (Project name and Project directory). - Note that you must create your project in the same directory where you installed openFrameworks. - The projects should be created in a folder inside the apps directory, such as "myApps". - diff --git a/scripts/win_cb/codeblocks_wizard/openframeworks/logo.png b/scripts/win_cb/codeblocks_wizard/openframeworks/logo.png deleted file mode 100644 index a0e09c78dba..00000000000 Binary files a/scripts/win_cb/codeblocks_wizard/openframeworks/logo.png and /dev/null differ diff --git a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.png b/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.png deleted file mode 100644 index b48f0cf391d..00000000000 Binary files a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.png and /dev/null differ diff --git a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.script b/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.script deleted file mode 100644 index 456f88a3792..00000000000 --- a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.script +++ /dev/null @@ -1,112 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// openFrameworks wizard for Codeblocks on Linux -// Created By: Pierre Proske pierre@digitalstar.net -// www.digitalstar.net -// -//////////////////////////////////////////////////////////////////////////////// - -g_selected_addons <- ::wxArrayString(); -g_of_project_dir <- _T(""); -g_of_project_name <- _T(""); -g_of_path_default <- _T(""); -g_full_proj_path <- _T(""); -g_addons_string <- _T(""); - -function BeginWizard() -{ - local of_path_descr = _T("Please select the location of your openFrameworks application directory on your computer.\n" + - "This is the folder where your new app will be created.\n"); - - Wizard.AddPage(_T("ofProjectName")); - Wizard.AddGenericSelectPathPage(_T("OpenFrameworksPath"), of_path_descr, _T("Please select your application directory:"), g_of_path_default); - Wizard.AddPage(_T("ofAddons")); - - return true; - -} - -function OnLeave_ofAddons(forward) { - local of_addons_selection = Wizard.GetListboxStringSelections(_T("ofAddonsList")); - g_selected_addons = GetArrayFromString(of_addons_selection, _T(";"), false); - return true; -} - -function OnLeave_OpenFrameworksPath(bForward) -{ - if (bForward) - { - local dir = Wizard.GetTextControlValue(_T("txtFolder")); // txtFolder is the text control in GenericSelectPathPage - local dir_nomacro = VerifyDirectory(dir); - - if (dir_nomacro.IsEmpty()) - return false; - else { - g_of_project_dir = dir_nomacro; - } - - } - return true; -} - - -function OnLeave_ofProjectName(bForward) -{ - if (bForward) { - g_of_project_name = Wizard.GetTextControlValue(_T("ofProjName")); - } - return true; -} - -function SetupCustom() -{ - local proj = g_of_project_dir + _T("\\") + g_of_project_name + _T("\\") + g_of_project_name + _T(".cbp"); - local projdir = g_of_project_dir + _T("\\"); - - // create project - g_full_proj_path = g_of_project_dir + _T("\\") + g_of_project_name + _T("\\"); - local batch_proj_path = g_of_project_dir + _T("\\") + g_of_project_name; - local commands_string = g_of_project_dir + _T("\\..\\..\\scripts\\win_cb\\createProjects.py ") + batch_proj_path; - - // add Addons - local addon_count = g_selected_addons.GetCount(); - - for(local i = 0; i < addon_count; i++) - { - local addon_name = g_selected_addons.Item(i); - g_addons_string = g_addons_string + addon_name + _T("\n"); - } - - // create addons.make file - IO.CreateDirectory(g_full_proj_path,0755); - if(addon_count > 0) { - IO.WriteFileContents(g_full_proj_path +_T("\\addons.make"), g_addons_string); - } - - local batch_string = g_of_project_dir + _T("\\..\\..\\scripts\\win_cb"); - IO.WriteFileContents(g_full_proj_path +_T("\\mylaunch.bat"), _T("cd \"") + batch_string + _T("\\") + _T("\"") + _T("\n") + _T("createProjects.py ") + _T("\"")+batch_proj_path+_T("\"") ); - - // create project - local outnum = IO.Execute(g_full_proj_path +_T("\\mylaunch.bat")); - - IO.RemoveFile(g_full_proj_path +_T("\\mylaunch.bat")); - - // load Project - if(GetProjectManager().LoadProject(proj,true) == 0) - { - ShowMessage(_T("project failed to load")); - } - -return true; -} - - - - - - - - - - - diff --git a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.xrc b/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.xrc deleted file mode 100644 index 0228ac7ada4..00000000000 --- a/scripts/win_cb/codeblocks_wizard/openframeworks/wizard.xrc +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - wxVERTICAL - - - - wxALL - 8 - - - - - - - - - wxALL - 0 - - - - - - - - wxALL|wxEXPAND - 0 - - myTestProject - 20 - - - - - - - - - - - wxVERTICAL - - - wxALL - 8 - - - - - - - - ofxXmlSettings - ofxOpenCv - ofxOsc - ofxThread - ofx3DUtils - ofx3DModelLoader - ofxAccelerometer - ofxAndroid - ofxAssimpModelLoader - ofxDirList - ofxMultiTouch - ofxNetwork - ofxThreadedImageLoader - ofxVectorGraphics - - - - wxALL|wxGROW - 8 - - - - - - - diff --git a/scripts/win_cb/compileAllExamples.bat b/scripts/win_cb/compileAllExamples.bat deleted file mode 100644 index 7f5f5958548..00000000000 --- a/scripts/win_cb/compileAllExamples.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off - - -set OLDDIR=%CD% - -cd ..\..\libs\openFrameworksCompiled\project\win_cb\ -"C:\Program Files\CodeBlocks\codeblocks.exe" /na /nd --target="release" --build "openFrameworksLib.cbp" -cd ../../../../scripts/win_cb - - -for /d %%X in (..\..\examples\*) do ( -cd %%X -echo compiling all folders in: %%X - for /d %%Y in (*) do ( - cd %%Y - - for %%Z in (*.cbp) do ( - - "C:\Program Files\CodeBlocks\codeblocks.exe" /na /nd --target= "release" --build %%Z - - ) - cd ../ - ) - - -) - -chdir /d %OLDDIR% \ No newline at end of file diff --git a/scripts/win_cb/createProjects.py b/scripts/win_cb/createProjects.py deleted file mode 100755 index 793d0bf1879..00000000000 --- a/scripts/win_cb/createProjects.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/python -import os -from lxml import etree -from lxml import objectify -import argparse -import shutil -import glob - - -of_root = os.path.realpath(__file__)[0:-(len(os.path.join('scripts','linux','createProject.py'))+2)] -platform = 'win_cb' -arch = 'win_cb' -templates_path = os.path.join(of_root,'scripts',platform,'template') -template = {'cbp': os.path.join(templates_path , 'emptyExample.cbp'), 'full_cbp': os.path.join(templates_path , 'emptyExample.cbp'), 'workspace': os.path.join(templates_path , 'emptyExample.workspace'), 'makefile': templates_path + 'Makefile', 'config.make': templates_path + 'config.make'} -fullCBP = True - -def addCBPIncludePath(project,dirpath): - found=False - if project.find('Compiler') == None: - etree.SubElement(project,"Compiler") - if project.Compiler.find('Add') != None: - for include in project.Compiler.Add: - if str(include.get("directory"))==str(dirpath): - found=True - break - if not found: - include = etree.SubElement(project.Compiler,"Add") - include.set("directory",dirpath) - -def addCBPLibrary(project,libpath): - found=False - if project.find('Linker') == None: - etree.SubElement(project,"Linker") - if project.Linker.find('Add') != None: - for lib in project.Linker.Add: - if str(lib.get("option"))==str(libpath): - found=True - break - if not found: - include = etree.SubElement(project.Linker,"Add") - include.set("option",libpath) - -def addCBPUnit(project,filepath,basefolder): - found=False - for unit in project.Unit: - if str(unit.get("filename"))==str(filepath): - found=True - break - if not found: - unit = etree.SubElement(project,"Unit") - unit.set("filename",filepath) - virtual_folder = etree.SubElement(unit,"Option") - virtual_folder.set("virtualFolder",basefolder) - -def addAddon(project,addon): - if addon == '': - return - if not os.path.exists(os.path.join(of_root,'addons',addon)): - print 'error', addon, 'in addons.make not found' - return - if not os.path.exists(os.path.join(of_root,'addons',addon,'src')): - print 'error', addon, 'has no src folder' - return - if fullCBP: - addon_src = os.path.join('..','..','..','addons',addon,'src') - addCBPIncludePath(project,addon_src) - for root, dirs, files in os.walk(os.path.join(of_root,'addons',addon,'src')): - for name in files: - basefolder = root[len(of_root):] - filepath = str(os.path.join('..','..','..',basefolder,name)) - addCBPUnit(project,filepath,basefolder) - if fullCBP: - for dir in dirs: - basefolder = root[len(of_root):] - dirpath = os.path.join('..','..','..',basefolder,dir) - addCBPIncludePath(project,dirpath) - - if fullCBP: - if not os.path.exists(os.path.join(of_root,'addons',addon,'libs')): - return - - # add search path for libs in case theres source in it - basefolder = os.path.join('addons',addon,'libs'); - dirpath = os.path.join(of_root,basefolder) - addCBPIncludePath(project,os.path.join('..','..','..',basefolder)) - for root, dirs, files in os.walk(dirpath): - for dir in dirs: - basefolder_addon = root[len(of_root):] - dirpath_addon = os.path.join('..','..','..',basefolder_addon,dir) - addCBPIncludePath(project,dirpath_addon) - - # add source in libs - for root, dirs, files in os.walk(dirpath): - for name in files: - basename, extension = os.path.splitext(name) - if extension=='.c' or extension=='.cc' or extension=='.cpp' or extension=='.h': - basefolder = root[len(of_root):] - filepath = str(os.path.join('..','..','..',basefolder,name)) - addCBPUnit(project,filepath,basefolder) - - for libdir in os.listdir(os.path.join(of_root,'addons',addon,'libs')): - if not os.path.isdir(os.path.join(of_root,'addons',addon,'libs',libdir)): - continue - basefolder = os.path.join('addons',addon,'libs',libdir); - if os.path.exists(os.path.join(of_root,basefolder,'include')): - dirpath = os.path.join(of_root,basefolder,'include') - addCBPIncludePath(project,os.path.join('..','..','..',basefolder,'include')) - for root, dirs, files in os.walk(dirpath): - for dir in dirs: - basefolder_addon = root[len(of_root):] - dirpath_addon = os.path.join('..','..','..',basefolder_addon,dir) - addCBPIncludePath(project,dirpath_addon) - - basefolder = os.path.join('addons',addon,'libs',libdir); - if os.path.exists(os.path.join(of_root,basefolder,'lib',arch)): - dirpath = os.path.join('..','..','..',basefolder,'lib',arch) - if os.path.exists(os.path.join(of_root,basefolder,'lib',arch,'libsorder.make')): - libsorder = open(os.path.join(of_root,basefolder,'lib',arch,'libsorder.make')) - for lib in libsorder: - if lib[-1]=='\n': - lib = lib[:-1] - addCBPLibrary(project,os.path.join(dirpath,'lib'+lib.strip()+'.a')) - libsorder.close() - else: - for lib in glob.glob(os.path.join(of_root,basefolder,'lib',arch,'*.a')): - baselib = lib[len(of_root):] - addCBPLibrary(project,os.path.join('..','..','..',baselib)) - for lib in glob.glob(os.path.join(of_root,basefolder,'lib',arch,'*.dll')): - baselib = lib[len(of_root):] - addCBPLibrary(project,os.path.join('..','..','..',baselib)) - - -def addAddons(project,project_path): - if not os.path.exists(os.path.join(project_path,'addons.make')): - return - addons_make = open(os.path.join(project_path,'addons.make'),'r') - for addon in addons_make: - if addon[-1]=='\n': - addon = addon[:-1] - addAddon(project, addon) - -def createCBP(project_path): - if os.path.abspath(project_path) == os.path.abspath(templates_path): - return - project_name = os.path.basename(project_path) - cbp = objectify.parse(os.path.join(project_path,project_name+'.cbp')) - root = cbp.getroot() - project = root.Project - - for option in project.Option: - if option.get("title")!=None: - option.set("title",project_name) - - # add existing files in src/ to the codeblocks project - for root, dirs, files in os.walk(os.path.join(project_path,'src')): - for name in files: - basefolder = root[len(project_path)+1:] - filepath = str(os.path.join(basefolder,name)) - addCBPUnit(project,filepath,basefolder) - - # add addons from addons.make to the cbp - addAddons(project,project_path) - - cbp_file = open(os.path.join(project_path,project_name+'.cbp'),mode='w') - cbp_file.write(etree.tostring(cbp, xml_declaration=True, encoding='UTF-8', pretty_print=True)) - cbp_file.close() - -def createWorkspace(project_path): - if os.path.abspath(project_path) == os.path.abspath(templates_path): - return - project_name = os.path.basename(project_path) - ws = objectify.parse(os.path.join(project_path,project_name+'.workspace')) - root = ws.getroot() - workspace = root.Workspace - - if workspace.get("title")=="emptyExample": - workspace.set("title",project_name) - - for project in workspace.Project: - if project.get("filename")=="emptyExample.cbp": - project.set("filename",project_name+".cbp") - - ws_file = open(os.path.join(project_path,project_name+'.workspace'),mode='w') - ws_file.write(etree.tostring(ws, xml_declaration=True, encoding='UTF-8', pretty_print=True)) - ws_file.close() - -def createProject(project_path): - print 'generating',project_path - if os.path.abspath(project_path) == os.path.abspath(templates_path): - return - if project_path[-1]==os.sep: - project_path=project_path[:-1] - if not os.path.exists(project_path): - os.mkdir(project_path) - - project_name = os.path.basename(project_path) - if fullCBP: - shutil.copyfile(template['full_cbp'],os.path.join(project_path,project_name+'.cbp')) - else: - shutil.copyfile(template['cbp'],os.path.join(project_path,project_name+'.cbp')) - - shutil.copyfile(template['workspace'],os.path.join(project_path,project_name+'.workspace')) - - if platform == "linux": - shutil.copyfile(template['makefile'],os.path.join(project_path,'Makefile')) - - if platform == "linux" and not os.path.exists(os.path.join(project_path, 'config.make')): - shutil.copyfile(template['config.make'],os.path.join(project_path,'config.make')) - - if not os.path.exists(os.path.join(project_path,'src')): - os.mkdir(os.path.join(project_path , 'src')) - for file in os.listdir(os.path.join(templates_path , 'src')): - shutil.copyfile(os.path.join(templates_path , 'src' , file), os.path.join(project_path , 'src' , file)) - - if not os.path.exists(os.path.join(project_path , 'bin')): - os.mkdir(os.path.join(project_path , 'bin')) - - if not os.path.exists(os.path.join(project_path , 'bin', 'data')): - os.mkdir(os.path.join(project_path , 'bin','data')) - - createCBP(project_path) - createWorkspace(project_path) - - - -parser = argparse.ArgumentParser(description='OF linux project generator') -parser.add_argument('project_path', metavar='project_path', nargs='?') -#parser.add_argument('-n', '--not_mk', dest='not_mk', action='store_const', -# default=False, const=True, help='create cbp not dependent on Makefile') - -project_path = parser.parse_args().project_path -fullCBP = True #parser.parse_args().not_mk - -if project_path==None: #parse all directories in ofroot/examples - for directory in os.listdir(os.path.join(of_root,'examples')): - if directory != '.gitignore': #parse all examples in ofroot/examples/directory - for example in os.listdir(os.path.join(of_root,'examples',directory)): - if example != '.gitkeep': createProject(os.path.join(of_root,'examples',directory,example)) -else: - createProject(project_path) - diff --git a/scripts/win_cb/template/emptyExample.cbp b/scripts/win_cb/template/emptyExample.cbp deleted file mode 100644 index def17e762e3..00000000000 --- a/scripts/win_cb/template/emptyExample.cbp +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - diff --git a/scripts/win_cb/template/emptyExample.workspace b/scripts/win_cb/template/emptyExample.workspace deleted file mode 100644 index 50ff33a738b..00000000000 --- a/scripts/win_cb/template/emptyExample.workspace +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/scripts/win_cb/template/icon.rc b/scripts/win_cb/template/icon.rc deleted file mode 100644 index d2c6a1adfea..00000000000 --- a/scripts/win_cb/template/icon.rc +++ /dev/null @@ -1,2 +0,0 @@ -//TODO: figure out how to do debug and release icons -MAINICON ICON "../../../libs/openFrameworksCompiled/project/win_cb/icon.ico" diff --git a/tutorials/.gitignore b/tests/.gitignore similarity index 84% rename from tutorials/.gitignore rename to tests/.gitignore index 0962fb939a5..053c0adb7dd 100644 --- a/tutorials/.gitignore +++ b/tests/.gitignore @@ -23,17 +23,23 @@ /*/*/*.workspace # Visual Studio -/*/*/*.sln -/*/*/*.vcxproj -/*/*/*.vcxproj.user -/*/*/*.vcxproj.filters -/*/*/icon.rc +#/*/*/*.sln +#/*/*/*.vcxproj +#/*/*/*.vcxproj.user +#/*/*/*.vcxproj.filters +#/*/*/icon.rc # Eclipse /*/*/.cproject /*/*/.project /*/*/.settings/ +# QtCreator +/*/*/*.qbs +/*/*/*.qbs.user +/*/*/*.pro +/*/*/*.pro.user + ######################### # operating system ######################### diff --git a/tests/addons/networkTcp/addons.make b/tests/addons/networkTcp/addons.make new file mode 100644 index 00000000000..1b470413a32 --- /dev/null +++ b/tests/addons/networkTcp/addons.make @@ -0,0 +1,2 @@ +ofxUnitTests +ofxNetwork diff --git a/tests/addons/networkTcp/bin/data/.gitkeep b/tests/addons/networkTcp/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/addons/networkTcp/icon.rc b/tests/addons/networkTcp/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/addons/networkTcp/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/addons/networkTcp/networkTcp.sln b/tests/addons/networkTcp/networkTcp.sln new file mode 100644 index 00000000000..043777f1bb4 --- /dev/null +++ b/tests/addons/networkTcp/networkTcp.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "networkTcp", "networkTcp.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/addons/networkTcp/networkTcp.vcxproj b/tests/addons/networkTcp/networkTcp.vcxproj new file mode 100644 index 00000000000..3ce6c5e4f86 --- /dev/null +++ b/tests/addons/networkTcp/networkTcp.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + networkTcp + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src;..\..\..\addons\ofxNetwork\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src;..\..\..\addons\ofxNetwork\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src;..\..\..\addons\ofxNetwork\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src;..\..\..\addons\ofxNetwork\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/addons/networkTcp/networkTcp.vcxproj.filters b/tests/addons/networkTcp/networkTcp.vcxproj.filters new file mode 100644 index 00000000000..03a9d4b1fd4 --- /dev/null +++ b/tests/addons/networkTcp/networkTcp.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + {01A15744-29A6-108D-08E9-83A7} + + + {3D1C10C7-8F35-E796-9C70-F5F3} + + + + + src + + + addons\ofxUnitTests\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + + + + diff --git a/tests/addons/networkTcp/networkTcp.vcxproj.user b/tests/addons/networkTcp/networkTcp.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/addons/networkTcp/networkTcp.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/addons/networkTcp/src/main.cpp b/tests/addons/networkTcp/src/main.cpp new file mode 100644 index 00000000000..646919aa89e --- /dev/null +++ b/tests/addons/networkTcp/src/main.cpp @@ -0,0 +1,283 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" +#include "ofxNetwork.h" + +class ofApp: public ofxUnitTestsApp{ +public: + void testNonBlocking(int timeout = 0){ + ofLogNotice() << "---------------------------------------"; + ofLogNotice() << "testNonBlocking"; + + int port = ofRandom(15000, 65535); + + ofxTCPServer server; + test(server.setup(port,false), "non blocking server"); + + ofxTCPClient client; + test(client.setup("127.0.0.1",port,false), "non blocking client"); + + server.waitConnectedClient(500); + + bool received = false; + std::string messageSent = "message"; + std::string messageReceived; + + test(client.send(messageSent), "send non blocking from client"); + for(int i=0;i messageReceived(messageSent.size()+1, 0); + int received = 0; + do{ + auto ret = server.receiveRawBytes(0, messageReceived.data() + received, messageSent.size()); + test(ret>0, "received blocking from server"); + if(ret>0){ + received += ret; + }else{ + break; + } + }while(received messageReceived(messageSent.size()+1, 0); + int received = 0; + do{ + auto ret = server.receiveRawBytes(0, messageReceived.data() + received, messageSent.size()); + test(ret>0, "received blocking from server"); + if(ret>0){ + received += ret; + }else{ + break; + } + }while(received lck(mtx); + done.wait(lck); + }); + + ofxTCPManager client; + test(client.Create(), "client socket create"); + test(client.Connect("127.0.0.1", port), "client socket connect"); + + ofSleepMillis(100); + client.SetTimeoutReceive(5); + auto then = ofGetElapsedTimeMillis(); + char buffer; + test_eq(client.Receive(&buffer,1), SOCKET_TIMEOUT, "socket timeouts on no receive"); + auto now = ofGetElapsedTimeMillis(); + // seems timers in the test servers are not very accurate so + // we test this with a margin of 500ms + test_gt(now-then, 4500, "Connect waits 5s to timeout, waited: " + ofToString(now - then)); + done.notify_all(); + serverThread.join(); + } + + void testSendMaxSize(){ + ofLogNotice() << ""; + ofLogNotice() << "---------------------------------------"; + ofLogNotice() << "testSendMaxSize tests #3478"; + + int port = ofRandom(15000, 65535); + + ofxTCPServer server; + test(server.setup(port,true), "blocking server"); + + ofxTCPClient client; + test(client.setup("127.0.0.1", port, true), "blocking client"); + + // wait for connection to be made + server.waitConnectedClient(500); + + string str; + string received; + for(int i=0;i(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); +} + diff --git a/tests/addons/networkUdp/addons.make b/tests/addons/networkUdp/addons.make new file mode 100644 index 00000000000..dd62b677fe0 --- /dev/null +++ b/tests/addons/networkUdp/addons.make @@ -0,0 +1,2 @@ +ofxNetwork +ofxUnitTests diff --git a/tests/addons/networkUdp/bin/data/.gitkeep b/tests/addons/networkUdp/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/addons/networkUdp/icon.rc b/tests/addons/networkUdp/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/addons/networkUdp/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/addons/networkUdp/networkUdp.sln b/tests/addons/networkUdp/networkUdp.sln new file mode 100644 index 00000000000..7ec62477762 --- /dev/null +++ b/tests/addons/networkUdp/networkUdp.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "networkUdp", "networkUdp.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/addons/networkUdp/networkUdp.vcxproj b/tests/addons/networkUdp/networkUdp.vcxproj new file mode 100644 index 00000000000..021072724d7 --- /dev/null +++ b/tests/addons/networkUdp/networkUdp.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + networkUdp + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxNetwork\src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxNetwork\src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxNetwork\src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxNetwork\src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/addons/networkUdp/networkUdp.vcxproj.filters b/tests/addons/networkUdp/networkUdp.vcxproj.filters new file mode 100644 index 00000000000..091ceee72ec --- /dev/null +++ b/tests/addons/networkUdp/networkUdp.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {01A15744-29A6-108D-08E9-83A7} + + + {3D1C10C7-8F35-E796-9C70-F5F3} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxNetwork\src + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/addons/networkUdp/networkUdp.vcxproj.user b/tests/addons/networkUdp/networkUdp.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/addons/networkUdp/networkUdp.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/addons/networkUdp/src/main.cpp b/tests/addons/networkUdp/src/main.cpp new file mode 100644 index 00000000000..97e715386c1 --- /dev/null +++ b/tests/addons/networkUdp/src/main.cpp @@ -0,0 +1,214 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" +#include "ofxNetwork.h" + +class ofApp: public ofxUnitTestsApp{ + void testNonBlocking(){ + int port = ofRandom(15000, 65535); + ofxUDPManager server; + test(server.Create(),"create udp socket"); + test(server.SetNonBlocking(true), "set non-blocking"); + test(server.Bind(port), "bind udp socket"); + test(server.Connect("127.0.0.1", port+1), "set ip and port to send for udp socket"); + + std::string messageSent="message"; + std::vector bufferReceive(messageSent.size(),0); + std::string messageReceived; + + ofxUDPManager client; + test(client.Create(), "create udp socket"); + test(client.SetNonBlocking(true), "set udp socket non blocking"); + test(client.Bind(port+1), "bind udp socket"); + test(client.Connect("127.0.0.1", port), "set ip and port to send for udp socket"); + + + test(client.Send(messageSent.c_str(), messageSent.size()), "client send non blocking"); + + auto received = 0; + auto left = messageSent.size(); + for(int i=0;i<10 && received=0, "server receiving non block"); + if(ret>0){ + received += ret; + left -= ret; + } + ofSleepMillis(10); + } + + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "client messageSent == server messageReceived"); + + + test(server.Send(messageSent.c_str(), messageSent.size()), "server send non blocking"); + + received = 0; + left = messageSent.size(); + bufferReceive.assign(messageSent.size(),0); + for(int i=0;i<10 && received=0, "client receiving non block"); + if(ret>0){ + received += ret; + left -= ret; + } + ofSleepMillis(10); + } + + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "server messageSent == client messageReceived"); + } + + void testBlocking(){ + int port = ofRandom(15000, 65535); + ofxUDPManager server; + test(server.Create(),"create udp socket"); + test(server.SetNonBlocking(false), "set blocking"); + test(server.Bind(port), "bind udp socket"); + test(server.Connect("127.0.0.1", port+1), "set ip and port to send for udp socket"); + + std::string messageSent="message"; + std::vector bufferReceive(messageSent.size(),0); + std::string messageReceived; + + ofxUDPManager client; + test(client.Create(), "create udp socket"); + test(client.SetNonBlocking(false), "set udp socket blocking"); + test(client.Bind(port+1), "bind udp socket"); + test(client.Connect("127.0.0.1", port), "set ip and port to send for udp socket"); + + + test(client.Send(messageSent.c_str(), messageSent.size()), "client send blocking"); + auto ret = server.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "server receiving block"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "client messageSent == server messageReceived"); + + + test(server.Send(messageSent.c_str(), messageSent.size()), "server send blocking"); + bufferReceive.assign(messageSent.size(),0); + ret = client.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "client receiving block"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "server messageSent == client messageReceived"); + + + test(client.Send(messageSent.c_str(), messageSent.size()), "client send blocking 2nd time"); + ret = server.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "server receiving block 2nd time"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "2nd client messageSent == server messageReceived"); + + + test(server.Send(messageSent.c_str(), messageSent.size()), "server send blocking 2nd time"); + bufferReceive.assign(messageSent.size(),0); + ret = client.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "client receiving block 2nd time"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "2nd server messageSent == client messageReceived"); + } + + void testTimeOutRecv(){ + int port = ofRandom(15000, 65535); + ofxUDPManager server; + test(server.Create(),"create udp socket"); + test(server.SetNonBlocking(false), "set blocking"); + test(server.Bind(port), "bind udp socket"); + server.SetTimeoutReceive(5); + + char c; + auto then = ofGetElapsedTimeMillis(); + auto ret = server.Receive(&c,1); + auto now = ofGetElapsedTimeMillis(); + test_eq(ret,SOCKET_TIMEOUT,"socket receive timeout"); + // seems timers in the test servers are not very accurate so + // we test this with a margin of 500ms + test_gt(now-then, 4500, "socket receive timeouts after 5s"); + } + + void testPortsStayBound(){ + ofLogNotice() << "----------------------"; + ofLogNotice() << "testPortsStayBound"; + ofLogNotice() << "tests #3656"; + + int serverport = ofRandom(15000, 65535); + int clientport = serverport-1; + ofxUDPManager server; + test(server.Create(),"create udp socket"); + test(server.SetNonBlocking(false), "set blocking"); + test(server.Bind(serverport), "bind udp socket"); + test(server.Connect("127.0.0.1", clientport), "set ip and port to send for udp socket"); + + std::string messageSent="message"; + std::vector bufferReceive(messageSent.size(),0); + std::string messageReceived; + + ofxUDPManager client; + test(client.Create(), "create udp socket"); + test(client.SetNonBlocking(false), "set udp socket blocking"); + test(client.Bind(clientport), "bind udp socket"); + test(client.Connect("127.0.0.1", serverport), "set ip and port to send for udp socket"); + + + std::string receivedAddress; + int receivedPort; + + test(client.Send(messageSent.c_str(), messageSent.size()), "client send blocking"); + auto ret = server.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "server receiving block"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "client messageSent == server messageReceived"); + test(server.GetRemoteAddr(receivedAddress, receivedPort), "Could get remote address and port"); + test_eq(receivedPort, clientport, "server received from clients bound port"); + + + test(server.Send(messageSent.c_str(), messageSent.size()), "server send blocking"); + bufferReceive.assign(messageSent.size(),0); + ret = client.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "client receiving block"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "server messageSent == client messageReceived"); + test(client.GetRemoteAddr(receivedAddress, receivedPort), "Could get remote address and port"); + test_eq(receivedPort, serverport, "client received from servers bound port"); + + + test(client.Send(messageSent.c_str(), messageSent.size()), "client send blocking 2nd time"); + ret = server.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "server receiving block 2nd time"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "2nd client messageSent == server messageReceived"); + test(server.GetRemoteAddr(receivedAddress, receivedPort), "Could get remote address and port"); + test_eq(receivedPort, clientport, "server received from clients bound port"); + + + test(server.Send(messageSent.c_str(), messageSent.size()), "server send blocking 2nd time"); + bufferReceive.assign(messageSent.size(),0); + ret = client.Receive(bufferReceive.data(), messageSent.size()); + test(ret>=0, "client receiving block 2nd time"); + messageReceived.assign(bufferReceive.begin(), bufferReceive.end()); + test_eq(messageSent, messageReceived, "2nd server messageSent == client messageReceived"); + test(client.GetRemoteAddr(receivedAddress, receivedPort), "Could get remote address and port"); + test_eq(receivedPort, serverport, "client received from servers bound port"); + } + + void run(){ + testNonBlocking(); + testBlocking(); + testTimeOutRecv(); + testPortsStayBound(); + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + +} diff --git a/tests/events/events/addons.make b/tests/events/events/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/events/events/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/events/events/bin/data/.gitkeep b/tests/events/events/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/events/events/events.sln b/tests/events/events/events.sln new file mode 100644 index 00000000000..1af6767fc57 --- /dev/null +++ b/tests/events/events/events.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "events", "events.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/events/events/events.vcxproj b/tests/events/events/events.vcxproj new file mode 100644 index 00000000000..56e237afc95 --- /dev/null +++ b/tests/events/events/events.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + events + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/events/events/events.vcxproj.filters b/tests/events/events/events.vcxproj.filters new file mode 100644 index 00000000000..6d70bb598e3 --- /dev/null +++ b/tests/events/events/events.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/events/events/events.vcxproj.user b/tests/events/events/events.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/events/events/events.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/events/events/icon.rc b/tests/events/events/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/events/events/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/events/events/src/main.cpp b/tests/events/events/src/main.cpp new file mode 100644 index 00000000000..333eb0a23e0 --- /dev/null +++ b/tests/events/events/src/main.cpp @@ -0,0 +1,173 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" + +namespace { + int lastIntFromCFunc = 0; + int lastIntFromCFuncWithToken = 0; + int selfUnregisterValue = 0; + bool toggleVoidFunc = false; + ofEvent selfUnregisterEvent; + + void intFunctListener(const int & i){ + lastIntFromCFunc = i; + } + + void intFunctListenerWithToken(const int & i){ + lastIntFromCFuncWithToken = i; + } + + void selfUnregister(const int & i){ + selfUnregisterValue = i; + ofRemoveListener(selfUnregisterEvent, selfUnregister); + } + + void voidFunc(){ + toggleVoidFunc = !toggleVoidFunc; + } +} + +class ofApp: public ofxUnitTestsApp{ + int lastInt = 0; + int lastIntFromLambda = 0; + int lastIntWithToken = 0; + bool toggleForVoidListener = false; + bool toggleForVoidLambdaListener = false; + bool toggleForVoidListenerWithToken = false; + + void intListener(const int & i){ + lastInt = i; + } + + void intListenerWithToken(const int & i){ + lastIntWithToken = i; + } + + void voidListener(){ + toggleForVoidListener = !toggleForVoidListener; + } + + void voidListenerWithToken(){ + toggleForVoidListenerWithToken = !toggleForVoidListenerWithToken; + } + + void run(){ + { + ofEvent intEvent; + ofAddListener(intEvent, this, &ofApp::intListener); + ofAddListener(intEvent, intFunctListener); + auto listenerLambda = intEvent.newListener([&](const int & i){ + lastIntFromLambda = i; + }, 0); + auto listenerMember = intEvent.newListener(this, &ofApp::intListenerWithToken); + auto listenerFunc = intEvent.newListener(intFunctListenerWithToken); + + ofNotifyEvent(intEvent, 5); + test_eq(lastInt, 5, "Testing int event to member function"); + test_eq(lastIntWithToken, 5, "Testing int event to member function with release token"); + test_eq(lastIntFromLambda, 5, "Testing int event to lambda function"); + test_eq(lastIntFromCFunc, 5, "Testing int event to c function"); + test_eq(lastIntFromCFuncWithToken, 5, "Testing int event to c function with release token"); + + intEvent.disable(); + ofNotifyEvent(intEvent, 6); + test_eq(lastInt, 5, "Testing disabled int event to member function"); + test_eq(lastIntWithToken, 5, "Testing disabled int event to member function with release token"); + test_eq(lastIntFromLambda, 5, "Testing disabled int event to lambda function"); + test_eq(lastIntFromCFunc, 5, "Testing disabled int event to c function"); + test_eq(lastIntFromCFuncWithToken, 5, "Testing disabled int event to c function with release token"); + + intEvent.enable(); + ofNotifyEvent(intEvent, 6); + test_eq(lastInt, 6, "Testing re-enabled int event to member function"); + test_eq(lastIntWithToken, 6, "Testing re-enabled int event to member function with release token"); + test_eq(lastIntFromLambda, 6, "Testing re-enabled int event to lambda function"); + test_eq(lastIntFromCFunc, 6, "Testing re-enabled int event to c function"); + test_eq(lastIntFromCFuncWithToken, 6, "Testing re-enabled int event to c function with release token"); + + ofRemoveListener(intEvent, this, &ofApp::intListener); + ofRemoveListener(intEvent, &intFunctListener); + listenerLambda.unsubscribe(); + listenerMember.unsubscribe(); + listenerFunc.unsubscribe(); + ofNotifyEvent(intEvent, 5); + test_eq(lastInt, 6, "Testing remove listener on int event to member function"); + test_eq(lastIntWithToken, 6, "Testing remove listener on int event to member function with release token"); + test_eq(lastIntFromLambda, 6, "Testing remove listener on int event to lambda function"); + test_eq(lastIntFromCFunc, 6, "Testing remove listener on int event to c function"); + test_eq(lastIntFromCFuncWithToken, 6, "Testing remove listener on int event to c function with release token"); + } + + { + ofEventListener listener; + { + ofEvent intEvent; + listener = intEvent.newListener([&](const int & i){ + lastIntFromLambda = i; + }, 0); + } + listener.unsubscribe(); + } + + { + lastIntFromCFunc = 0; + auto listener = selfUnregisterEvent.newListener(selfUnregister); + selfUnregisterEvent.notify(5); + test_eq(selfUnregisterValue, 5, "Testing remove listener on event callback, first call"); + selfUnregisterEvent.notify(6); + test_eq(selfUnregisterValue, 5, "Testing remove listener on event callback, second call"); + } + + { + ofEvent voidEvent; + ofAddListener(voidEvent, this, &ofApp::voidListener); + auto listenerVoidLambda = voidEvent.newListener([&]{ + toggleForVoidLambdaListener = !toggleForVoidLambdaListener; + }); + auto listenerVoidMember = voidEvent.newListener(this, &ofApp::voidListenerWithToken); + auto listenerVoidFunc = voidEvent.newListener(voidFunc); + + voidEvent.notify(); + test_eq(toggleForVoidListener, true, "Void event with member function"); + test_eq(toggleForVoidLambdaListener, true, "Void event with lambda function"); + test_eq(toggleForVoidListenerWithToken, true, "Void event with member function with release token"); + test_eq(toggleVoidFunc, true, "Void event with c function"); + + voidEvent.disable(); + voidEvent.notify(); + test_eq(toggleForVoidListener, true, "Disabled void event with member function"); + test_eq(toggleForVoidLambdaListener, true, "Disabled void event with lambda function"); + test_eq(toggleForVoidListenerWithToken, true, "Disabled void event with member function with release token"); + test_eq(toggleVoidFunc, true, "Disabled void event with c function"); + + voidEvent.enable(); + voidEvent.notify(); + test_eq(toggleForVoidListener, false, "Re-enabled void event with member function"); + test_eq(toggleForVoidLambdaListener, false, "Re-enabled void event with lambda function"); + test_eq(toggleForVoidListenerWithToken, false, "Re-enabled void event with member function with release token"); + test_eq(toggleVoidFunc, false, "Re-enabled void event with c function"); + + ofRemoveListener(voidEvent, this, &ofApp::voidListener); + listenerVoidLambda.unsubscribe(); + listenerVoidMember.unsubscribe(); + listenerVoidFunc.unsubscribe(); + test_eq(toggleForVoidListener, false, "Unregistered void event with member function"); + test_eq(toggleForVoidLambdaListener, false, "Unregistered void event with lambda function"); + test_eq(toggleForVoidListenerWithToken, false, "Unregistered void event with member function with release token"); + test_eq(toggleVoidFunc, false, "Unregistered void event with c function"); + } + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + +} diff --git a/tests/graphics/pixels/addons.make b/tests/graphics/pixels/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/graphics/pixels/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/graphics/pixels/bin/data/.gitkeep b/tests/graphics/pixels/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/graphics/pixels/icon.rc b/tests/graphics/pixels/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/graphics/pixels/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/graphics/pixels/pixels.sln b/tests/graphics/pixels/pixels.sln new file mode 100644 index 00000000000..9029e16c473 --- /dev/null +++ b/tests/graphics/pixels/pixels.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pixels", "pixels.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/graphics/pixels/pixels.vcxproj b/tests/graphics/pixels/pixels.vcxproj new file mode 100644 index 00000000000..726f7e4bad7 --- /dev/null +++ b/tests/graphics/pixels/pixels.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + pixels + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/graphics/pixels/pixels.vcxproj.filters b/tests/graphics/pixels/pixels.vcxproj.filters new file mode 100644 index 00000000000..4ece7ef42f4 --- /dev/null +++ b/tests/graphics/pixels/pixels.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + src + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/graphics/pixels/pixels.vcxproj.user b/tests/graphics/pixels/pixels.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/graphics/pixels/pixels.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/graphics/pixels/src/main.cpp b/tests/graphics/pixels/src/main.cpp new file mode 100644 index 00000000000..5c1848087a8 --- /dev/null +++ b/tests/graphics/pixels/src/main.cpp @@ -0,0 +1,341 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" + +class ofApp: public ofxUnitTestsApp{ + + bool hasImageFormat(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_RGB565: + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + case OF_PIXELS_GRAY: + return true; + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_NATIVE: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_UNKNOWN: + return false; + } + test(false,"asked for non checked pixel format"); + return false; + } + + ofImageType imageType(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_RGB565: + return OF_IMAGE_COLOR; + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + return OF_IMAGE_COLOR_ALPHA; + case OF_PIXELS_GRAY: + return OF_IMAGE_GRAYSCALE; + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_NATIVE: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_UNKNOWN: + test(false,"asked for image format for pixel format with no correspondence"); + return OF_IMAGE_UNDEFINED; + } + return OF_IMAGE_UNDEFINED; + } + + string formatName(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + return "RGB"; + case OF_PIXELS_BGR: + return "BGR"; + case OF_PIXELS_RGB565: + return "RGB565"; + case OF_PIXELS_RGBA: + return "RGBA"; + case OF_PIXELS_BGRA: + return "BGRA"; + case OF_PIXELS_GRAY: + return "GRAY"; + case OF_PIXELS_GRAY_ALPHA: + return "GRAY_ALPHA"; + case OF_PIXELS_YUY2: + return "YUY2"; + case OF_PIXELS_UYVY: + return "UYVY"; + case OF_PIXELS_Y: + return "Y"; + case OF_PIXELS_U: + return "U"; + case OF_PIXELS_V: + return "V"; + case OF_PIXELS_UV: + return "UV"; + case OF_PIXELS_VU: + return "VU"; + case OF_PIXELS_NV12: + return "NV12"; + case OF_PIXELS_NV21: + return "NV21"; + case OF_PIXELS_YV12: + return "YV12"; + case OF_PIXELS_I420: + return "I420"; + case OF_PIXELS_NATIVE: + return "NATIVE"; + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_UNKNOWN: + return "UNKOWN"; + } + test(false,"asked for format name for pixel format with no correspondence"); + return "UNKOWN"; + } + + int bitsPerPixel(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + return 8*3; + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + return 8*4; + case OF_PIXELS_GRAY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + return 8; + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + return 8*2; + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + return 12; + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_RGB565: + return 8*2; + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: + return 0; + } + test(false,"asked for bits per pixel for pixel format with no correspondence"); + return 0; + } + + bool hasWorkingIterators(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + return true; + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_RGB565: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: + return false; + } + test(false,"asked for working iterators for pixel format with no correspondence"); + return 0; + } + + int getNumPlanes(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_RGB565: + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + return 1; + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + return 2; + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + return 3; + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: + return 0; + } + test(false,"asked for num planes for pixel format with no correspondence"); + return 0; + } + + bool hasChannels(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + case OF_PIXELS_RGB565: + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + case OF_PIXELS_GRAY: + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + return true; + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: + return false; + } + test(false,"asked for num channels for pixel format with no correspondence"); + return false; + } + + int numChannels(ofPixelFormat pixelFormat){ + switch(pixelFormat){ + case OF_PIXELS_RGB: + case OF_PIXELS_BGR: + return 3; + case OF_PIXELS_RGB565: + case OF_PIXELS_GRAY_ALPHA: + case OF_PIXELS_YUY2: + case OF_PIXELS_UYVY: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + return 2; + case OF_PIXELS_RGBA: + case OF_PIXELS_BGRA: + return 4; + case OF_PIXELS_GRAY: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + return 1; + case OF_PIXELS_NV12: + case OF_PIXELS_NV21: + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_NUM_FORMATS: + case OF_PIXELS_NATIVE: + case OF_PIXELS_UNKNOWN: + return 0; + } + test(false,"asked for num channels for pixel format with no correspondence"); + return 0; + } + + void run(){ + ofPixels pixels; + const int w = 320; + const int h = 240; + + for(ofPixelFormat pixelFormat=OF_PIXELS_GRAY;pixelFormat(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + +} diff --git a/tests/math/quaternionTests/addons.make b/tests/math/quaternionTests/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/math/quaternionTests/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/math/quaternionTests/bin/data/.gitkeep b/tests/math/quaternionTests/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/math/quaternionTests/icon.rc b/tests/math/quaternionTests/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/math/quaternionTests/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/math/quaternionTests/quaternionTests.sln b/tests/math/quaternionTests/quaternionTests.sln new file mode 100644 index 00000000000..a06fe53cfc7 --- /dev/null +++ b/tests/math/quaternionTests/quaternionTests.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "quaternionTests", "quaternionTests.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/math/quaternionTests/quaternionTests.vcxproj b/tests/math/quaternionTests/quaternionTests.vcxproj new file mode 100644 index 00000000000..fdbbb817a7a --- /dev/null +++ b/tests/math/quaternionTests/quaternionTests.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + quaternionTests + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/math/quaternionTests/quaternionTests.vcxproj.filters b/tests/math/quaternionTests/quaternionTests.vcxproj.filters new file mode 100644 index 00000000000..4ece7ef42f4 --- /dev/null +++ b/tests/math/quaternionTests/quaternionTests.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + src + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/math/quaternionTests/quaternionTests.vcxproj.user b/tests/math/quaternionTests/quaternionTests.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/math/quaternionTests/quaternionTests.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/math/quaternionTests/src/main.cpp b/tests/math/quaternionTests/src/main.cpp new file mode 100644 index 00000000000..917736c5b56 --- /dev/null +++ b/tests/math/quaternionTests/src/main.cpp @@ -0,0 +1,53 @@ +#include "ofMain.h" +#include "ofxUnitTests.h" +#include "ofAppNoWindow.h" + +bool aprox_eq(const ofVec3f & v1, const ofVec3f & v2){ + bool eq = abs(v1.x - v2.x) < 0.0001 && + abs(v1.y - v2.y) < 0.0001 && + abs(v1.z - v2.z) < 0.0001; + if(!eq){ + ofLogError() << "value1: " << v1; + ofLogError() << "value2: " << v2; + } + return eq; +} + +class ofApp: public ofxUnitTestsApp{ +public: + void run(){ + ofQuaternion q1(30,ofVec3f(1,0,0)); + ofQuaternion q2(30,ofVec3f(0,0,1)); + ofQuaternion q3(30,ofVec3f(0,1,0)); + ofVec3f v(100,100,100); + auto q12 = q1 * q2; + auto q13 = q1 * q3; + auto q23 = q2 * q3; + auto q21 = q2 * q1; + auto q31 = q3 * q1; + auto q32 = q3 * q2; + ofLogNotice() << "testing #4461"; + test(aprox_eq(v*q12,(v*q1)*q2),"v*q12 == (v*q1)*q2"); + test(aprox_eq(v*q13,(v*q1)*q3),"v*q13 == (v*q1)*q3"); + test(aprox_eq(v*q23,(v*q2)*q3),"v*q23 == (v*q2)*q3"); + test(aprox_eq(v*q21,(v*q2)*q1),"v*q21 == (v*q2)*q1"); + test(aprox_eq(v*q31,(v*q3)*q1),"v*q31 == (v*q3)*q1"); + test(aprox_eq(v*q32,(v*q3)*q2),"v*q32 == (v*q3)*q2"); + ofLogNotice() << "end testing #4461"; + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + + +} + diff --git a/tests/utils/buffer/addons.make b/tests/utils/buffer/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/utils/buffer/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/utils/buffer/bin/data/.gitkeep b/tests/utils/buffer/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/utils/buffer/buffer.sln b/tests/utils/buffer/buffer.sln new file mode 100644 index 00000000000..1788998fe8e --- /dev/null +++ b/tests/utils/buffer/buffer.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "buffer", "buffer.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/utils/buffer/buffer.vcxproj b/tests/utils/buffer/buffer.vcxproj new file mode 100644 index 00000000000..bfb6b4bad3a --- /dev/null +++ b/tests/utils/buffer/buffer.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + buffer + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/utils/buffer/buffer.vcxproj.filters b/tests/utils/buffer/buffer.vcxproj.filters new file mode 100644 index 00000000000..6d70bb598e3 --- /dev/null +++ b/tests/utils/buffer/buffer.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/utils/buffer/buffer.vcxproj.user b/tests/utils/buffer/buffer.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/utils/buffer/buffer.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/utils/buffer/icon.rc b/tests/utils/buffer/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/utils/buffer/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/utils/buffer/src/main.cpp b/tests/utils/buffer/src/main.cpp new file mode 100644 index 00000000000..a62d2f3b2c3 --- /dev/null +++ b/tests/utils/buffer/src/main.cpp @@ -0,0 +1,189 @@ +#include "ofFileUtils.h" +#include "ofUtils.h" +#include "ofxUnitTests.h" + +class ofApp: public ofxUnitTestsApp{ + void run(){ + std::vector src(2048); + for(auto & c: src){ + c = ofRandom(255); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "constructor allocator"; + ofBuffer buffer(src.data(), src.size()); + test_eq(buffer.size(), src.size(), "constructor does correct allocation"); + test(buffer.end() == buffer.begin() + src.size(), "correct boundaries"); + bool bufferEqual = true; + auto srcIt = src.begin(); + for(auto & c: buffer){ + bufferEqual &= c == *srcIt++; + } + test(bufferEqual, "data is correct"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "text constructor allocator"; + std::string text("This is a text test"); + ofBuffer buffer(text); + test_eq(buffer.size(), text.size(), "constructor does correct allocation"); + test(buffer.end() == buffer.begin() + text.size(), "correct boundaries"); + bool bufferEqual = true; + auto srcIt = text.begin(); + for(auto & c: buffer){ + bufferEqual &= c == *srcIt++; + } + test(bufferEqual, "data is correct"); + test_eq(text, buffer.getText(), "getText"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "set allocator"; + ofBuffer buffer; + buffer.set(src.data(), src.size()); + test_eq(buffer.size(), src.size(), "set does correct allocation"); + test(buffer.end() == buffer.begin() + src.size(), "correct boundaries"); + bool bufferEqual = true; + auto srcIt = src.begin(); + for(auto & c: buffer){ + bufferEqual &= c == *srcIt++; + } + test(bufferEqual, "data is correct"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "text set allocator"; + std::string text("This is a text test"); + ofBuffer buffer; + buffer.set(text); + test_eq(buffer.size(), text.size(), "text set does correct allocation"); + test(buffer.end() == buffer.begin() + text.size(), "correct boundaries"); + bool bufferEqual = true; + auto srcIt = text.begin(); + for(auto & c: buffer){ + bufferEqual &= c == *srcIt++; + } + test(bufferEqual, "data is correct"); + test_eq(text, buffer.getText(), "getText"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "allocate & setall"; + ofBuffer buffer; + auto bufferSize = 2048; + buffer.allocate(bufferSize); + test_eq(buffer.size(), bufferSize, "allocate does correct allocation"); + test(buffer.end() == buffer.begin() + bufferSize, "correct boundaries"); + bool bufferEqual = true; + buffer.setall(5); + for(auto & c: buffer){ + bufferEqual &= c == 5; + } + test(bufferEqual, "data is correct"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "append text"; + std::string text("This is a text test"); + ofBuffer buffer; + for(int i=0;i<5;i++){ + buffer.append(text); + } + test_eq(buffer.size(), text.size() * 5, "text append does correct allocation"); + test(buffer.end() == buffer.begin() + text.size() * 5, "correct boundaries"); + bool bufferEqual = true; + auto bufferIt = buffer.begin(); + for(int i=0;i<5;i++){ + for(auto & c: text){ + bufferEqual &= c == *bufferIt++; + } + } + test(bufferEqual, "data is correct"); + test_eq(text+text+text+text+text, buffer.getText(), "getText"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "append raw data"; + ofBuffer buffer; + for(int i=0;i<5;i++){ + buffer.append(src.data(), src.size()); + } + test_eq(buffer.size(), src.size() * 5, "text append does correct allocation"); + test(buffer.end() == buffer.begin() + src.size() * 5, "correct boundaries"); + bool bufferEqual = true; + auto bufferIt = buffer.begin(); + for(int i=0;i<5;i++){ + for(auto & c: src){ + bufferEqual &= c == *bufferIt++; + } + } + test(bufferEqual, "data is correct"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "append raw data"; + ofBuffer buffer; + test_eq((uint64_t)buffer.getData(),(uint64_t)nullptr,"unallocated buffer getData"); + test(buffer.begin() == buffer.end(),"unallocated buffer begin"); + buffer.set(src.data(), src.size()); + test(buffer.getData() == &*buffer.begin(),"getData == begin"); + } + + { + ofLogNotice() << "-------------------"; + ofLogNotice() << "lines iterator"; + std::vector lines; + lines.push_back("Lorem ipsum dolor sit amet,"); + lines.push_back("consectetur adipiscing elit."); + lines.push_back("Vivamus viverra tortor ut condimentum"); + lines.push_back("condimentum. Vestibulum id luctus lectus."); + lines.push_back("Duis porttitor turpis orci, eget pellentesque"); + lines.push_back("enim varius eu. Integer lectus urna,"); + lines.push_back("auctor in tincidunt nec, porta vitae tellus."); + lines.push_back("Integer ac blandit felis, ullamcorper iaculis felis."); + lines.push_back("Fusce eget sollicitudin purus, sed porttitor ante."); + lines.push_back("Integer mattis tortor at lectus venenatis laoreet."); + lines.push_back("Phasellus nibh massa, pellentesque non consequat vitae,"); + lines.push_back("volutpat ac quam. Cras ac mauris in justo"); + lines.push_back("hendrerit tincidunt eget a magna. Nullam volutpat,"); + lines.push_back("erat sit amet facilisis tempor,"); + lines.push_back("tellus urna volutpat dolor,"); + lines.push_back("a ornare nisl libero quis orci."); + lines.push_back("Fusce in nunc id orci lobortis semper."); + ofBuffer buffer; + for(auto & line: lines){ + buffer.append(line + "\n"); // This should append one more line but the result should be correct + } + + auto numLines = 0; + auto linesIt = lines.begin(); + auto allLinesEqual = true; + for(auto line: buffer.getLines()){ + allLinesEqual &= line == *linesIt++; + ++numLines; + } + test(allLinesEqual, "all lines are correct"); + test_eq(numLines,lines.size(),"lines iterator correct numLines"); + } + } +}; + + +#include "ofAppNoWindow.h" +#include "ofAppRunner.h" +//======================================================================== +int main( ){ + ofInit(); + auto window = std::make_shared(); + auto app = std::make_shared(); + ofRunApp(window, app); + return ofRunMainLoop(); +} diff --git a/tests/utils/fileUtils/addons.make b/tests/utils/fileUtils/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/utils/fileUtils/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/utils/fileUtils/fileUtils.sln b/tests/utils/fileUtils/fileUtils.sln new file mode 100644 index 00000000000..7ba2a84cc28 --- /dev/null +++ b/tests/utils/fileUtils/fileUtils.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fileUtils", "fileUtils.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/utils/fileUtils/fileUtils.vcxproj b/tests/utils/fileUtils/fileUtils.vcxproj new file mode 100644 index 00000000000..73ea9c6d25e --- /dev/null +++ b/tests/utils/fileUtils/fileUtils.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + fileUtils + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/utils/fileUtils/fileUtils.vcxproj.filters b/tests/utils/fileUtils/fileUtils.vcxproj.filters new file mode 100644 index 00000000000..4ece7ef42f4 --- /dev/null +++ b/tests/utils/fileUtils/fileUtils.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + src + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/utils/fileUtils/fileUtils.vcxproj.user b/tests/utils/fileUtils/fileUtils.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/utils/fileUtils/fileUtils.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/utils/fileUtils/icon.rc b/tests/utils/fileUtils/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/utils/fileUtils/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/utils/fileUtils/src/main.cpp b/tests/utils/fileUtils/src/main.cpp new file mode 100644 index 00000000000..37206588830 --- /dev/null +++ b/tests/utils/fileUtils/src/main.cpp @@ -0,0 +1,293 @@ +#include "ofFileUtils.h" +#include "ofUtils.h" +#include "ofxUnitTests.h" + +std::filesystem::path initial_cwd; + +class ofApp: public ofxUnitTestsApp{ + void run(){ + ofDirectory dir("."); + dir.create(true); + dir.exists(); + for(auto f: dir){ + f.setWriteable(true); + if(f.isDirectory()){ + ofDirectory(f.path()).remove(true); + }else{ + f.remove(); + } + } + test(ofDirectory(".").getFiles().empty(),"removing old tests files","other tests will fail too"); + + + + //======================================================================== + ofLogNotice() << "testing ofFile"; + { + ofFile("test.txt").create(); + } + test(ofFile("test.txt").exists(),"ofFile::create && ofFile::exists"); + test(!ofFile("test2.txt").exists(),"!ofFile::exists"); + test_eq(ofFile("test.txt").getExtension(),"txt","ofFile::getExtension",ofFile("test.txt").getExtension()); + test_eq(ofFile("test.txt").getFileName(),"test.txt","ofFile::getFileName",ofFile("test.txt").getFileName()); + test_eq(ofFile("test.txt").getBaseName(),"test","ofFile::getBaseName",ofFile("test.txt").getBaseName()); + test_eq(ofFile("test.txt").getAbsolutePath(), ofFilePath::join(ofToDataPath("",true),"test.txt"),"ofFile::getAbsolutePath"); + + if(ofGetTargetPlatform()!=OF_TARGET_MINGW && ofGetTargetPlatform()!=OF_TARGET_WINVS){ + // seems you can't effectively set a file to not be read in windows + ofFile("noread").create(); + { + ofFile fw("noread",ofFile::WriteOnly); + fw << "testing"; + } + boost::system::error_code error; + boost::filesystem::permissions(ofToDataPath("noread"), boost::filesystem::no_perms, error); + test(!error, "error setting no read permissions, " + error.message()); + if(!test(!ofFile("noread").canRead(),"!ofFile::canRead")){ + ofFile fr("noread"); + std::string str; + fr >> str; + cout << "testing if file can be really read" << endl; + cout << str << endl; + } + } + + ofFile("nowrite").create(); + ofFile("nowrite").setReadOnly(); + test(ofFile("nowrite").canRead(),"ofFile::canRead"); + test(!ofFile("nowrite").canWrite(),"!ofFile::canWrite"); + + test(ofFile("test.txt").isFile(),"ofFile::isFile with existing file"); + test(!ofFile("test2.txt").isFile(),"!ofFile::isFile with non-existing file"); + test(!ofFile(".").isFile(),"!ofFile::isFile with folder"); + + test(ofFile(".").isDirectory(),"ofFile::isDirectory with dir"); + test(!ofFile("nonexistent").isDirectory(),"ofFile::isDirectory with non existing"); + test(!ofFile("test.txt").isDirectory(),"ofFile::isDirectory with file"); + + test(ofFile("test.txt").copyTo("test2.txt"),"ofFile::copyTo"); + test(ofFile("test2.txt").isFile(),"ofFile::copyTo exists"); + + test(ofFile("test2.txt").moveTo("test3.txt"),"ofFile::moveTo"); + test(ofFile("test3.txt").isFile(),"ofFile::moveTo creates"); + test(!ofFile("test2.txt").exists(),"ofFile::moveTo removes"); + + test(ofFile("test3.txt").moveTo("test2.txt"),"ofFile::moveTo"); + test(ofFile("test2.txt").isFile(),"ofFile::moveTo creates"); + test(!ofFile("test3.txt").exists(),"ofFile::moveTo removes"); + + test(ofFile("test2.txt").remove(),"ofFile::remove"); + test(!ofFile("test2.txt").exists(),"ofFile::remove !exists"); + + test_eq(ofFile("test.txt").getSize(),uint64_t(0),"ofFile::getSize"); + { + ofFile("test.txt",ofFile::WriteOnly) << "hola"; + } + test_eq(ofFile("test.txt").getSize(),uint64_t(4),"ofFile write and getSize"); + + + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "testing ofDirectory"; + size_t numFilesCreated; + if(ofGetTargetPlatform()!=OF_TARGET_MINGW && ofGetTargetPlatform()!=OF_TARGET_WINVS){ + numFilesCreated = 3; + }else{ + numFilesCreated = 2; + } + if(!test_eq(ofDirectory(".").getFiles().size(), numFilesCreated, "ofDirectory::ofDirectory with path")){ + ofLogError() << "data folder contains: "; + for(auto & f: ofDirectory(".").getFiles()){ + ofLogError() << f.path(); + } + } + + test(ofDirectory("d1").create(),"ofDirectory::create"); + test(ofDirectory("d1").isDirectory(),"ofDirectory::isDirectory"); + test(ofDirectory("d1").isDirectory(),"ofDirectory::exists"); + + test(ofDirectory("d2/d3").create(true),"ofDirectory::create recursive"); + test(ofDirectory("d2/d3").isDirectory(),"ofDirectory::isDirectory recursive"); + test(ofDirectory("d2/d3").isDirectory(),"ofDirectory::exists recursive"); + + test(ofDirectory("d1").canRead(),"ofDirectory::canRead"); + test(ofDirectory("d1").canWrite(),"ofDirectory::canWrite"); + if(ofGetTargetPlatform()!=OF_TARGET_MINGW && ofGetTargetPlatform()!=OF_TARGET_WINVS){ + // this doesn't make sense in windows + test(ofDirectory("d1").canExecute(),"ofDirectory::canExecute"); + } + + ofDirectory("noreaddir").create(); + ofDirectory("noreaddir").setReadOnly(); + test(ofDirectory("noreaddir").canRead(),"ofDirectory::canRead readonly"); + test(!ofDirectory("noreaddir").canWrite(),"!ofDirectory::canWrite readonly"); + + test(ofFile("d2/f1").create(),"ofFile::create in dir"); + test(ofFile("d2/d3/f2").create(),"ofFile::create in dirs"); + test(ofDirectory("d2").copyTo("d4"),"ofDirectory::copyTo"); + test(ofDirectory("d4").isDirectory(),"ofDirectory::copyTo dir exists"); + test(ofDirectory("d4/d3").isDirectory(),"ofDirectory::copyTo recursive dir exists"); + test(ofFile("d4/f1").isFile(),"ofDirectory::copyTo f1 exists"); + test(ofFile("d4/d3/f2").isFile(),"ofDirectory::copyTo f2 exists"); + + test(ofDirectory("d4").moveTo("d5"),"ofDirectory::moveTo"); + test(ofDirectory("d5").isDirectory(),"ofDirectory::moveTo dir exists"); + test(ofDirectory("d5/d3").isDirectory(),"ofDirectory::moveTo recursive dir exists"); + test(ofFile("d5/f1").isFile(),"ofDirectory::moveTo f1 exists"); + test(ofFile("d5/d3/f2").isFile(),"ofDirectory::moveTo f2 exists"); + + test(ofDirectory("d5").renameTo("d4"),"ofDirectory::renameTo"); + test(ofDirectory("d4").isDirectory(),"ofDirectory::renameTo dir exists"); + test(ofDirectory("d4/d3").isDirectory(),"ofDirectory::renameTo recursive dir exists"); + test(ofFile("d4/f1").isFile(),"ofDirectory::renameTo f1 exists"); + test(ofFile("d4/d3/f2").isFile(),"ofDirectory::renameTo f2 exists"); + + test(ofDirectory("d4").remove(true),"ofDirectory::remove recursive"); + test(!ofDirectory("d4").exists(),"!ofDirectory::exists after remove"); + + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "testing ofFilePath"; + test_eq(ofFilePath::getFileExt("test.txt"),"txt","ofFilePath::getFileExt"); + test_eq(ofFilePath::removeExt("test.txt"),"test","ofFilePath::removeExt"); + if(ofGetTargetPlatform()!=OF_TARGET_MINGW && ofGetTargetPlatform()!=OF_TARGET_WINVS){ + test_eq(ofFilePath::removeExt("/home/user/file.txt"),"/home/user/file","ofFilePath::removeExt absolute path"); + test_eq(ofFilePath::addLeadingSlash("test"),"/test","ofFilePath::addLeadingSlash"); + test_eq(ofFilePath::addLeadingSlash("/test"),"/test","ofFilePath::addLeadingSlash"); + test_eq(ofFilePath::addTrailingSlash("test"),"test/","ofFilePath::addTrailingSlash"); + test_eq(ofFilePath::addTrailingSlash("test/"),"test/","ofFilePath::addTrailingSlash"); + test_eq(ofFilePath::removeTrailingSlash("test/"),"test","ofFilePath::removeTrailingSlash"); + test_eq(ofFilePath::getPathForDirectory("dir/other"),"dir/other/","ofFilePath::getPathForDirectory"); + test_eq(ofFilePath::getPathForDirectory("dir/other/"),"dir/other/","ofFilePath::getPathForDirectory with trailing /"); + test(ofFilePath::isAbsolute("/test"),"ofFilePath::isAbsolute"); + }else{ + test_eq(ofFilePath::removeExt("c:\\users\\user\\file.txt"),"c:\\users\\user\\file","ofFilePath::removeExt absolute path"); + test_eq(ofFilePath::addLeadingSlash("test"),"\\test","ofFilePath::addLeadingSlash"); + test_eq(ofFilePath::addLeadingSlash("\\test"),"\\test","ofFilePath::addLeadingSlash"); + test_eq(ofFilePath::addTrailingSlash("test"),"test\\","ofFilePath::addTrailingSlash"); + test_eq(ofFilePath::addTrailingSlash("test\\"),"test\\","ofFilePath::addTrailingSlash"); + test_eq(ofFilePath::removeTrailingSlash("test\\"),"test","ofFilePath::removeTrailingSlash"); + test_eq(ofFilePath::getPathForDirectory("dir\\other"),"dir\\other\\","ofFilePath::getPathForDirectory"); + test_eq(ofFilePath::getPathForDirectory("dir\\other\\"),"dir\\other\\","ofFilePath::getPathForDirectory with trailing \\"); + test(ofFilePath::isAbsolute("c:\\test"),"ofFilePath::isAbsolute"); + } + test_eq(ofFilePath::getFileName("test/test.txt"),"test.txt","ofFilePath::getFileName",ofFilePath::getFileName("test/test.txt")); + test_eq(ofFilePath::getBaseName("test/test.txt"),"test","ofFilePath::getBaseName",ofFilePath::getBaseName("test/test.txt")); + test_eq(ofFilePath::getBaseName(ofFilePath::removeTrailingSlash(ofFilePath::getEnclosingDirectory("testdir/test.txt"))),"testdir","ofFilePath::getEnclosingDirectory",ofFilePath::getBaseName(ofFilePath::getEnclosingDirectory("testdir/test.txt"))); +#ifdef TARGET_WIN32 + test_eq(ofFilePath::join("d1","d2"),"d1\\d2","ofFilePath::join",ofFilePath::join("d1","d2")); +#else + test_eq(ofFilePath::join("d1","d2"),"d1/d2","ofFilePath::join",ofFilePath::join("d1","d2")); +#endif + + test(std::filesystem::exists(ofFile("test.txt")), "ofFile cast to filesystem::path"); + test(std::filesystem::exists(ofDirectory("d1")), "ofDirectory cast to filesystem::path"); + + + + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "tests #4285"; + test(!ofDirectory::doesDirectoryExist("d5/d1"),"!ofDirectory::doesDirectoryExist"); + test(ofDirectory::createDirectory("d5/d1",true,true),"ofDirectory::create recursive"); + test(ofDirectory::createDirectory(ofToDataPath("d5/d2",true),false,true),"ofDirectory::create recursive"); + test(ofDirectory::createDirectory(ofToDataPath("d5/d3"),false,true),"ofDirectory::create recursive"); + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "tests #4299"; + test_eq(std::filesystem::path(ofFilePath::getCurrentWorkingDirectory()), initial_cwd, "ofFilePath::getCurrentWorkingDirectory()"); + if(ofGetTargetPlatform()==OF_TARGET_OSX){ + test_eq(ofToDataPath("",false),"../../../data/","ofToDataPath relative"); + }else if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ + test_eq(ofToDataPath("",false),"data\\","ofToDataPath relative"); + }else{ + test_eq(ofToDataPath("",false),"data/","ofToDataPath relative"); + } + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "tests #4462"; + if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ + test_eq(ofToDataPath("movies\\",true).back(), '\\', "absolute ofToDataPath with \\ should end in \\"); + test_eq(ofToDataPath("movies",true).back(), 's', "absolute ofToDataPath without \\ should not end in \\"); + ofDirectory("movies").create(); + test_eq(ofToDataPath("movies\\",true).back(), '\\', "absolute ofToDataPath with \\ should end in \\"); + test_eq(ofToDataPath("movies",true).back(), 's', "absolute ofToDataPath without \\ should not end in \\"); + }else{ + test_eq(ofToDataPath("movies/",true).back(), '/', "absolute ofToDataPath with / should end in /"); + test_eq(ofToDataPath("movies",true).back(), 's', "absolute ofToDataPath without / should not end in /"); + ofDirectory("movies").create(); + test_eq(ofToDataPath("movies/",true).back(), '/', "absolute ofToDataPath with / should end in /"); + test_eq(ofToDataPath("movies",true).back(), 's', "absolute ofToDataPath without / should not end in /"); + } + + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "tests #4598"; + test_eq(ofToDataPath("").back(), std::filesystem::path::preferred_separator, "ofToDataPath with empty string shouldn't crash"); + + //======================================================================== + ofLogNotice() << ""; + ofLogNotice() << "tests #4563"; +#ifdef TARGET_LINUX + test_eq(ofToDataPath("a.txt"), "data/a.txt","#4563 test1"); + test_eq(ofToDataPath("data.txt"), "data/data.txt", "#4563 test2"); + test_eq(ofToDataPath(""), "data/", "#4563 test3"); +#elif defined(TARGET_OSX) + test_eq(ofToDataPath("a.txt"), "../../../data/a.txt","#4563 test1"); + test_eq(ofToDataPath("data.txt"), "../../../data/data.txt", "#4563 test2"); + test_eq(ofToDataPath(""), "../../../data/", "#4563 test3"); +#endif + + + //======================================================================== + // clean test files + dir.open("."); + for(auto f: dir){ + f.setWriteable(true); + if(f.isDirectory()){ + ofDirectory(f.path()).remove(true); + }else{ + f.remove(); + } + } + + //======================================================================== + ofLogNotice() << "#4564"; + dir.remove(true); + if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ + ofDirectory currentVideoDirectory(ofToDataPath("..\\..\\..\\video", true)); + auto path = currentVideoDirectory.path(); + std::string pathEnd("data\\..\\..\\..\\video\\"); + test_eq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); + }else{ + ofDirectory currentVideoDirectory(ofToDataPath("../../../video", true)); + auto path = currentVideoDirectory.path(); + std::string pathEnd("data/../../../video/"); + test_eq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); + } + } +}; + + +#include "ofAppNoWindow.h" +#include "ofAppRunner.h" +//======================================================================== +int main( ){ + initial_cwd = std::filesystem::current_path(); + ofInit(); + auto window = std::make_shared(); + auto app = std::make_shared(); + ofRunApp(window, app); + return ofRunMainLoop(); +} diff --git a/tests/utils/strings/addons.make b/tests/utils/strings/addons.make new file mode 100644 index 00000000000..0e0303d2e09 --- /dev/null +++ b/tests/utils/strings/addons.make @@ -0,0 +1 @@ +ofxUnitTests diff --git a/tests/utils/strings/bin/data/.gitkeep b/tests/utils/strings/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/utils/strings/icon.rc b/tests/utils/strings/icon.rc new file mode 100644 index 00000000000..7e26eb3534f --- /dev/null +++ b/tests/utils/strings/icon.rc @@ -0,0 +1,8 @@ +// Icon Resource Definition +#define MAIN_ICON 102 + +#if defined(_DEBUG) +MAIN_ICON ICON "icon_debug.ico" +#else +MAIN_ICON ICON "icon.ico" +#endif diff --git a/tests/utils/strings/src/main.cpp b/tests/utils/strings/src/main.cpp new file mode 100644 index 00000000000..25c3ad41f78 --- /dev/null +++ b/tests/utils/strings/src/main.cpp @@ -0,0 +1,84 @@ +#include "ofMain.h" +#include "ofAppNoWindow.h" +#include "ofxUnitTests.h" + +class ofApp: public ofxUnitTestsApp{ + void run(){ + test_eq(ofTrimFront(" trim this string "),"trim this string ","trimfront"); + test_eq(ofTrimBack(" trim this string ")," trim this string","trimback"); + test_eq(ofTrim(" trim this string "),"trim this string","trim"); + + auto split0 = ofSplitString("hi this is a split test", " "); + test_eq(split0.size(),6u,"split size"); + test_eq(split0[0],"hi","split 0"); + test_eq(split0[1],"this","split 1"); + test_eq(split0[2],"is","split 2"); + test_eq(split0[3],"a","split 3"); + test_eq(split0[4],"split","split 4"); + test_eq(split0[5],"test","split 5"); + + + auto split1 = ofSplitString(" hi this is a split test ", " "); + test_eq(split1.size(),8u,"split no trim size"); + test_eq(split1[0],"","split no trim 0"); + test_eq(split1[1],"hi","split no trim 1"); + test_eq(split1[2],"this","split no trim 2"); + test_eq(split1[3],"is","split no trim 3"); + test_eq(split1[4],"a","split no trim 4"); + test_eq(split1[5],"split","split no trim 5"); + test_eq(split1[6],"test","split no trim 6"); + test_eq(split1[7],"","split no trim 7"); + + auto split2 = ofSplitString(" hi this is a split test ", " ", true, true); + test_eq(split2.size(),6u,"split trim size"); + test_eq(split2[0],"hi","split trim 0"); + test_eq(split2[1],"this","split trim 1"); + test_eq(split2[2],"is","split trim 2"); + test_eq(split2[3],"a","split trim 3"); + test_eq(split2[4],"split","split trim 4"); + test_eq(split2[5],"test","split trim 5"); + + auto split3 = ofSplitString(" hi this is a split test ", " ", true, true); + test_eq(split2.size(),6u,"split trim2 size"); + test_eq(split2[0],"hi","split trim2 0"); + test_eq(split2[1],"this","split trim2 1"); + test_eq(split2[2],"is","split trim2 2"); + test_eq(split2[3],"a","split trim2 3"); + test_eq(split2[4],"split","split trim2 4"); + test_eq(split2[5],"test","split trim2 5"); + + test_eq(ofJoinString({"hi","this","is","a","join","test"}," "),"hi this is a join test","join string"); + test_eq(ofJoinString({"hi"}," "),"hi","join string 1 element"); + test_eq(ofJoinString({}," "),"","join string 0 elements"); + + std::string replace = "hi this is a replace test"; + ofStringReplace(replace,"replace","replaceeee"); + test_eq(replace , "hi this is a replaceeee test","replace string element"); + + test_eq(ofToLower("AbCéÉBbCcc"),"abcéébbccc","tolower"); + test_eq(ofToUpper("AbCéÉBbCcc"),"ABCÉÉBBCCC","toupper"); + + // test #4363 + std::vector strs; + strs.push_back("hi"); + strs.push_back("this"); + strs.push_back("is"); + strs.push_back("a"); + strs.push_back("join"); + strs.push_back("test"); + test_eq(ofJoinString(strs,","),"hi,this,is,a,join,test","test #4363"); + } +}; + +//======================================================================== +int main( ){ + ofInit(); + auto window = make_shared(); + auto app = make_shared(); + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(window, app); + return ofRunMainLoop(); + +} diff --git a/tests/utils/strings/strings.sln b/tests/utils/strings/strings.sln new file mode 100644 index 00000000000..f8397cba19f --- /dev/null +++ b/tests/utils/strings/strings.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strings", "strings.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64 + {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64 + {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/utils/strings/strings.vcxproj b/tests/utils/strings/strings.vcxproj new file mode 100644 index 00000000000..dcdbafa703c --- /dev/null +++ b/tests/utils/strings/strings.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FD42DF7-442E-479A-BA76-D0022F99702A} + Win32Proj + strings + + + + Application + Unicode + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + true + v140 + + + + + + + + + + + + + + + + + + + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + $(ProjectName)_debug + true + true + + + bin\ + obj\$(Configuration)\ + false + + + bin\ + obj\$(Configuration)\ + false + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + Disabled + EnableFastChecks + %(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + true + Console + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + true + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + false + %(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + %(AdditionalIncludeDirectories);src;..\..\..\addons\ofxUnitTests\src + CompileAsCpp + + + false + false + Console + true + true + false + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + + + + + + + + {5837595d-aca9-485c-8e76-729040ce4b0b} + + + + + /D_DEBUG %(AdditionalOptions) + /D_DEBUG %(AdditionalOptions) + $(OF_ROOT)\libs\openFrameworksCompiled\project\vs + + + + + + + + + diff --git a/tests/utils/strings/strings.vcxproj.filters b/tests/utils/strings/strings.vcxproj.filters new file mode 100644 index 00000000000..4ece7ef42f4 --- /dev/null +++ b/tests/utils/strings/strings.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + src + + + + + {d8376475-7454-4a24-b08a-aac121d3ad6f} + + + {71834F65-F3A9-211E-73B8-DC85} + + + {99AF7102-9423-91D4-8CD7-6602} + + + {6DB6A1EA-29BB-7859-928B-898A} + + + + + src + + + addons\ofxUnitTests\src + + + + + + diff --git a/tests/utils/strings/strings.vcxproj.user b/tests/utils/strings/strings.vcxproj.user new file mode 100644 index 00000000000..09a332bc18f --- /dev/null +++ b/tests/utils/strings/strings.vcxproj.user @@ -0,0 +1,19 @@ + + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + + $(ProjectDir)/bin + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tutorials/shader/01_simpleColorQuad/src/main.cpp b/tutorials/shader/01_simpleColorQuad/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/01_simpleColorQuad/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/02_simpleVertexDisplacement/src/main.cpp b/tutorials/shader/02_simpleVertexDisplacement/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/02_simpleVertexDisplacement/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/03_simpleShaderInteraction/src/main.cpp b/tutorials/shader/03_simpleShaderInteraction/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/03_simpleShaderInteraction/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/04_simpleTexturing/src/main.cpp b/tutorials/shader/04_simpleTexturing/src/main.cpp deleted file mode 100644 index 8780f7e8d6e..00000000000 --- a/tutorials/shader/04_simpleTexturing/src/main.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/05_alphaMasking/src/main.cpp b/tutorials/shader/05_alphaMasking/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/05_alphaMasking/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/06_multiTexture/src/main.cpp b/tutorials/shader/06_multiTexture/src/main.cpp deleted file mode 100644 index 671ec75cd0f..00000000000 --- a/tutorials/shader/06_multiTexture/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/07_fboAlphaMask/src/main.cpp b/tutorials/shader/07_fboAlphaMask/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/07_fboAlphaMask/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/08_displacementMap/src/main.cpp b/tutorials/shader/08_displacementMap/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/08_displacementMap/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -} diff --git a/tutorials/shader/09_gaussianBlurFilter/src/main.cpp b/tutorials/shader/09_gaussianBlurFilter/src/main.cpp deleted file mode 100644 index b3b3b5d3bcb..00000000000 --- a/tutorials/shader/09_gaussianBlurFilter/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -// comment out the line below if you want to use a fixed pipeline opengl renderer, -// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. -#define USE_PROGRAMMABLE_RENDERER - -#ifdef USE_PROGRAMMABLE_RENDERER -#include "ofGLProgrammableRenderer.h" -#endif - -//======================================================================== -int main( ){ - -#ifdef USE_PROGRAMMABLE_RENDERER - ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); -#endif - - ofSetupOpenGL(1024,768, 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 ofApp()); - -}