diff --git a/extras/Demo/Builds/Android/jni/Android.mk b/extras/Demo/Builds/Android/jni/Android.mk
index 6d3a4fc8b1..bf2e9e7176 100644
--- a/extras/Demo/Builds/Android/jni/Android.mk
+++ b/extras/Demo/Builds/Android/jni/Android.mk
@@ -36,6 +36,7 @@ LOCAL_SRC_FILES := \
../../../Source/Demos/MultiTouch.cpp\
../../../Source/Demos/NetworkingDemo.cpp\
../../../Source/Demos/OpenGLDemo.cpp\
+ ../../../Source/Demos/OpenGLDemo2D.cpp\
../../../Source/Demos/PropertiesDemo.cpp\
../../../Source/Demos/SystemInfoDemo.cpp\
../../../Source/Demos/TimersAndEventsDemo.cpp\
diff --git a/extras/Demo/Builds/Linux/Makefile b/extras/Demo/Builds/Linux/Makefile
index d9edb849c2..0be879a43a 100644
--- a/extras/Demo/Builds/Linux/Makefile
+++ b/extras/Demo/Builds/Linux/Makefile
@@ -79,6 +79,7 @@ OBJECTS := \
$(OBJDIR)/MultiTouch_595f3a2e.o \
$(OBJDIR)/NetworkingDemo_fbd1b19f.o \
$(OBJDIR)/OpenGLDemo_fdac55da.o \
+ $(OBJDIR)/OpenGLDemo2D_48eeadec.o \
$(OBJDIR)/PropertiesDemo_8ff1a8de.o \
$(OBJDIR)/SystemInfoDemo_984acd28.o \
$(OBJDIR)/TimersAndEventsDemo_f2656547.o \
@@ -263,6 +264,11 @@ $(OBJDIR)/OpenGLDemo_fdac55da.o: ../../Source/Demos/OpenGLDemo.cpp
@echo "Compiling OpenGLDemo.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/OpenGLDemo2D_48eeadec.o: ../../Source/Demos/OpenGLDemo2D.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling OpenGLDemo2D.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/PropertiesDemo_8ff1a8de.o: ../../Source/Demos/PropertiesDemo.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling PropertiesDemo.cpp"
diff --git a/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj b/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
index 8b273de11c..dd64b9ace6 100644
--- a/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
+++ b/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
@@ -49,6 +49,7 @@
2346D126B3690390A0925F06 = {isa = PBXBuildFile; fileRef = 24B00BED20980D12119C228F; };
C54286354BE46CB39B4C5225 = {isa = PBXBuildFile; fileRef = FD46383E356A5DDC1AD53380; };
FE559832F5E168F0FF04CB6E = {isa = PBXBuildFile; fileRef = 2DA02BCCDBFD5BF2DA2D2FA9; };
+ E635FA4F49200CDAE3E4E6F0 = {isa = PBXBuildFile; fileRef = 39A06D3252DDA6F97FB09495; };
CDC1A7E9F07FBFDD5DA92031 = {isa = PBXBuildFile; fileRef = 5AB15A508A07934A89398A6B; };
5B96583E8DAA4EA4EA1ACF18 = {isa = PBXBuildFile; fileRef = 84BAF97675BE522B63DC9A4B; };
372B92C7E54D51285649FDD1 = {isa = PBXBuildFile; fileRef = B731664FB9EEEBC618BAB5A0; };
@@ -311,6 +312,7 @@
38FB6ABB883ECAD52027CE19 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChildProcess.cpp"; path = "../../../../modules/juce_core/threads/juce_ChildProcess.cpp"; sourceTree = "SOURCE_ROOT"; };
3924287A67ED97279455625B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChannelRemappingAudioSource.cpp"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; };
393A46D91FB481557E4DF792 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_mac_CoreMidi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp"; sourceTree = "SOURCE_ROOT"; };
+ 39A06D3252DDA6F97FB09495 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OpenGLDemo2D.cpp; path = ../../Source/Demos/OpenGLDemo2D.cpp; sourceTree = "SOURCE_ROOT"; };
39E4404D57A8B66DF520B66F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MACAddress.h"; path = "../../../../modules/juce_core/network/juce_MACAddress.h"; sourceTree = "SOURCE_ROOT"; };
3A42694A047942A44E8216F5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JPEGLoader.cpp"; path = "../../../../modules/juce_graphics/image_formats/juce_JPEGLoader.cpp"; sourceTree = "SOURCE_ROOT"; };
3AB9E51994CD35A10F87EFF1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringArray.h"; path = "../../../../modules/juce_core/text/juce_StringArray.h"; sourceTree = "SOURCE_ROOT"; };
@@ -931,6 +933,7 @@
E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E7EA99CD84E1EC598F4984DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Array.h"; path = "../../../../modules/juce_core/containers/juce_Array.h"; sourceTree = "SOURCE_ROOT"; };
E80CA3836329ED0EEC74BAE6 = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; };
+ E8B785D8DD9C49BC7FF5EA75 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGL_linux.h"; path = "../../../../modules/juce_opengl/native/juce_OpenGL_linux.h"; sourceTree = "SOURCE_ROOT"; };
EA7D346CAE6A07C0B395816B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../../../modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; };
EACCBFA17F4D07ECE058EEBB = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
229D2DAADACF15540C3BBD15 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JuceDemo.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
@@ -939,7 +942,6 @@
E7B21011F93915ADD2CC5DD9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GlyphArrangement.cpp"; path = "../../../../modules/juce_graphics/fonts/juce_GlyphArrangement.cpp"; sourceTree = "SOURCE_ROOT"; };
E7EE6BDC0E3A0739529AED91 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSubsectionReader.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"; sourceTree = "SOURCE_ROOT"; };
E8128A35828C860977FEC54C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatWriter.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
- E8B785D8DD9C49BC7FF5EA75 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGL_linux.h"; path = "../../../../modules/juce_opengl/native/juce_OpenGL_linux.h"; sourceTree = "SOURCE_ROOT"; };
E98EA1189613978EA4E78D85 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentListener.h"; path = "../../../../modules/juce_gui_basics/components/juce_ComponentListener.h"; sourceTree = "SOURCE_ROOT"; };
E9A3E96E32C301EE817059C1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E9B8B3FAECC80B66257B14F9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BlowFish.h"; path = "../../../../modules/juce_cryptography/encryption/juce_BlowFish.h"; sourceTree = "SOURCE_ROOT"; };
@@ -1042,6 +1044,7 @@
24B00BED20980D12119C228F,
FD46383E356A5DDC1AD53380,
2DA02BCCDBFD5BF2DA2D2FA9,
+ 39A06D3252DDA6F97FB09495,
5AB15A508A07934A89398A6B,
84BAF97675BE522B63DC9A4B,
B731664FB9EEEBC618BAB5A0,
@@ -2288,6 +2291,7 @@
2346D126B3690390A0925F06,
C54286354BE46CB39B4C5225,
FE559832F5E168F0FF04CB6E,
+ E635FA4F49200CDAE3E4E6F0,
CDC1A7E9F07FBFDD5DA92031,
5B96583E8DAA4EA4EA1ACF18,
372B92C7E54D51285649FDD1,
diff --git a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
index 5d272f008b..d41753724a 100644
--- a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
@@ -153,6 +153,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
index a2cf51a888..836736c893 100644
--- a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
@@ -403,6 +403,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
index 1f5534717e..29704ad07e 100644
--- a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
@@ -159,6 +159,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
index a2cf51a888..836736c893 100644
--- a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
@@ -403,6 +403,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
index 50ed53a55a..1683e1352e 100644
--- a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
@@ -159,6 +159,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
index 8dd489900b..38b296356f 100644
--- a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
@@ -403,6 +403,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj b/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
index c03c039d5b..40cd5f7211 100644
--- a/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
+++ b/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
@@ -44,6 +44,7 @@
2346D126B3690390A0925F06 = {isa = PBXBuildFile; fileRef = 24B00BED20980D12119C228F; };
C54286354BE46CB39B4C5225 = {isa = PBXBuildFile; fileRef = FD46383E356A5DDC1AD53380; };
FE559832F5E168F0FF04CB6E = {isa = PBXBuildFile; fileRef = 2DA02BCCDBFD5BF2DA2D2FA9; };
+ E635FA4F49200CDAE3E4E6F0 = {isa = PBXBuildFile; fileRef = 39A06D3252DDA6F97FB09495; };
CDC1A7E9F07FBFDD5DA92031 = {isa = PBXBuildFile; fileRef = 5AB15A508A07934A89398A6B; };
5B96583E8DAA4EA4EA1ACF18 = {isa = PBXBuildFile; fileRef = 84BAF97675BE522B63DC9A4B; };
372B92C7E54D51285649FDD1 = {isa = PBXBuildFile; fileRef = B731664FB9EEEBC618BAB5A0; };
@@ -305,6 +306,7 @@
38FB6ABB883ECAD52027CE19 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChildProcess.cpp"; path = "../../../../modules/juce_core/threads/juce_ChildProcess.cpp"; sourceTree = "SOURCE_ROOT"; };
3924287A67ED97279455625B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChannelRemappingAudioSource.cpp"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; };
393A46D91FB481557E4DF792 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_mac_CoreMidi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp"; sourceTree = "SOURCE_ROOT"; };
+ 39A06D3252DDA6F97FB09495 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OpenGLDemo2D.cpp; path = ../../Source/Demos/OpenGLDemo2D.cpp; sourceTree = "SOURCE_ROOT"; };
39E4404D57A8B66DF520B66F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MACAddress.h"; path = "../../../../modules/juce_core/network/juce_MACAddress.h"; sourceTree = "SOURCE_ROOT"; };
3A42694A047942A44E8216F5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JPEGLoader.cpp"; path = "../../../../modules/juce_graphics/image_formats/juce_JPEGLoader.cpp"; sourceTree = "SOURCE_ROOT"; };
3AB9E51994CD35A10F87EFF1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringArray.h"; path = "../../../../modules/juce_core/text/juce_StringArray.h"; sourceTree = "SOURCE_ROOT"; };
@@ -912,53 +914,52 @@
E4BD5632ADD38CF8BAD38A76 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_CallOutBox.cpp"; path = "../../../../modules/juce_gui_basics/windows/juce_CallOutBox.cpp"; sourceTree = "SOURCE_ROOT"; };
E5058DD199CEC42ECE922239 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Justification.h"; path = "../../../../modules/juce_graphics/placement/juce_Justification.h"; sourceTree = "SOURCE_ROOT"; };
E52756E1DB553ED02D829F61 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_cryptography/juce_module_info"; sourceTree = "SOURCE_ROOT"; };
+ E5E02A3C4E942105FEDCA885 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChannelRemappingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
E6333272C33612B6A7D6073E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_AudioCDBurner.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp"; sourceTree = "SOURCE_ROOT"; };
E682A3A52BD15D5CA4933C12 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeParallelogram.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h"; sourceTree = "SOURCE_ROOT"; };
E6E0ADA4E3632540A8ADC7D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ConnectedChildProcess.cpp"; path = "../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp"; sourceTree = "SOURCE_ROOT"; };
E6E0FE3CBDBE2554B527CF60 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSourcePlayer.cpp"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp"; sourceTree = "SOURCE_ROOT"; };
E70A283A87989F5A1CEDE6A4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ResamplingAudioSource.cpp"; path = "../../../../modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; };
E7113B21A18CD89165BAFD4B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../../../modules/juce_events/native/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; };
- E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E7B21011F93915ADD2CC5DD9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GlyphArrangement.cpp"; path = "../../../../modules/juce_graphics/fonts/juce_GlyphArrangement.cpp"; sourceTree = "SOURCE_ROOT"; };
E7EA99CD84E1EC598F4984DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Array.h"; path = "../../../../modules/juce_core/containers/juce_Array.h"; sourceTree = "SOURCE_ROOT"; };
E7EE6BDC0E3A0739529AED91 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSubsectionReader.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"; sourceTree = "SOURCE_ROOT"; };
- E8128A35828C860977FEC54C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatWriter.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
E8B785D8DD9C49BC7FF5EA75 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGL_linux.h"; path = "../../../../modules/juce_opengl/native/juce_OpenGL_linux.h"; sourceTree = "SOURCE_ROOT"; };
E98EA1189613978EA4E78D85 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentListener.h"; path = "../../../../modules/juce_gui_basics/components/juce_ComponentListener.h"; sourceTree = "SOURCE_ROOT"; };
E9A3E96E32C301EE817059C1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
- E9B8B3FAECC80B66257B14F9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BlowFish.h"; path = "../../../../modules/juce_cryptography/encryption/juce_BlowFish.h"; sourceTree = "SOURCE_ROOT"; };
E9BBEE1B3986E0829AA44133 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImagePreviewComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h"; sourceTree = "SOURCE_ROOT"; };
EA082125C757D1FD63BA38C5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentAnimator.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h"; sourceTree = "SOURCE_ROOT"; };
+ EACCBFA17F4D07ECE058EEBB = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
+ EB6F5F8F57F0117C10735583 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioIODevice.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioIODevice.h"; sourceTree = "SOURCE_ROOT"; };
+ ED3DE86815324354C48631D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_XMLCodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
+ ED6224ABC715AAB68661F4D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_box2d.cpp"; path = "../../../../modules/juce_box2d/juce_box2d.cpp"; sourceTree = "SOURCE_ROOT"; };
+ F1E995A1E00C6545A4C3297B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KeyMappingsDemo.cpp; path = ../../Source/Demos/KeyMappingsDemo.cpp; sourceTree = "SOURCE_ROOT"; };
+ FBCD860CD7113A3136B127C8 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
+ 229D2DAADACF15540C3BBD15 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JuceDemo.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
+ E34DFFF51D0F7C34FB826C4C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FloatVectorOperations.h"; path = "../../../../modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h"; sourceTree = "SOURCE_ROOT"; };
+ E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
+ E8128A35828C860977FEC54C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatWriter.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
+ E9B8B3FAECC80B66257B14F9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BlowFish.h"; path = "../../../../modules/juce_cryptography/encryption/juce_BlowFish.h"; sourceTree = "SOURCE_ROOT"; };
EA3436079F0D78BB76CD15F7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseInactivityDetector.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h"; sourceTree = "SOURCE_ROOT"; };
EA7D346CAE6A07C0B395816B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../../../modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; };
EA9FE6D1E0A072E73312916C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentDragger.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_ComponentDragger.h"; sourceTree = "SOURCE_ROOT"; };
- EACCBFA17F4D07ECE058EEBB = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
EB369EA30D31CD710A09B7FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_ios_MessageManager.mm"; path = "../../../../modules/juce_events/native/juce_ios_MessageManager.mm"; sourceTree = "SOURCE_ROOT"; };
- EB6F5F8F57F0117C10735583 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioIODevice.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioIODevice.h"; sourceTree = "SOURCE_ROOT"; };
EC8A992EA9CFA558DB9F950E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharacterFunctions.h"; path = "../../../../modules/juce_core/text/juce_CharacterFunctions.h"; sourceTree = "SOURCE_ROOT"; };
ECAB8BD2816B0BEFCD9F6961 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AsyncUpdater.h"; path = "../../../../modules/juce_events/broadcasters/juce_AsyncUpdater.h"; sourceTree = "SOURCE_ROOT"; };
- ED3DE86815324354C48631D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_XMLCodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
- ED6224ABC715AAB68661F4D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_box2d.cpp"; path = "../../../../modules/juce_box2d/juce_box2d.cpp"; sourceTree = "SOURCE_ROOT"; };
+ ED80E9909586DD64BDE03A70 = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = portmeirion.jpg; path = ../../Resources/portmeirion.jpg; sourceTree = "SOURCE_ROOT"; };
EE7001BD5206A8D8EA2D125B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RectangleList.h"; path = "../../../../modules/juce_graphics/geometry/juce_RectangleList.h"; sourceTree = "SOURCE_ROOT"; };
EEA020419EF58E90C10AAE26 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableWindow.h"; path = "../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h"; sourceTree = "SOURCE_ROOT"; };
+ EEAA1BB6254EDE07A7ABAD65 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IIRFilterAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
EF8055850F3DEA173761E3B5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MessageManager.cpp"; path = "../../../../modules/juce_events/messages/juce_MessageManager.cpp"; sourceTree = "SOURCE_ROOT"; };
+ EFD1BD42000EE640A17EE1ED = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatReaderSource.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp"; sourceTree = "SOURCE_ROOT"; };
EFD480AA79620EC53C2686EA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Draggable3DOrientation.h"; path = "../../../../modules/juce_opengl/opengl/juce_Draggable3DOrientation.h"; sourceTree = "SOURCE_ROOT"; };
F037091D4A3012EBBA1E808F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KeyboardFocusTraverser.cpp"; path = "../../../../modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp"; sourceTree = "SOURCE_ROOT"; };
F0ACCF70936A0BBA2A2AB289 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Value.cpp"; path = "../../../../modules/juce_data_structures/values/juce_Value.cpp"; sourceTree = "SOURCE_ROOT"; };
F1A30E40F7388D16BA35B0DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SHA256.cpp"; path = "../../../../modules/juce_cryptography/hashing/juce_SHA256.cpp"; sourceTree = "SOURCE_ROOT"; };
- F1E995A1E00C6545A4C3297B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KeyMappingsDemo.cpp; path = ../../Source/Demos/KeyMappingsDemo.cpp; sourceTree = "SOURCE_ROOT"; };
- F29F6395C4935C1A663A1D15 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GZIPDecompressorInputStream.h"; path = "../../../../modules/juce_core/zip/juce_GZIPDecompressorInputStream.h"; sourceTree = "SOURCE_ROOT"; };
- F380FE12E78619086BA33CDB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_InterprocessConnection.cpp"; path = "../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp"; sourceTree = "SOURCE_ROOT"; };
- F91A3C07D81BE2D4A191C9A2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Timer.h"; path = "../../../../modules/juce_events/timers/juce_Timer.h"; sourceTree = "SOURCE_ROOT"; };
- FBCD860CD7113A3136B127C8 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
- 229D2DAADACF15540C3BBD15 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JuceDemo.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
- E34DFFF51D0F7C34FB826C4C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FloatVectorOperations.h"; path = "../../../../modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h"; sourceTree = "SOURCE_ROOT"; };
- E5E02A3C4E942105FEDCA885 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChannelRemappingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
- ED80E9909586DD64BDE03A70 = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = portmeirion.jpg; path = ../../Resources/portmeirion.jpg; sourceTree = "SOURCE_ROOT"; };
- EEAA1BB6254EDE07A7ABAD65 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IIRFilterAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
- EFD1BD42000EE640A17EE1ED = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatReaderSource.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp"; sourceTree = "SOURCE_ROOT"; };
F1A9F544E889DDA995415F6D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioSourcePlayer.h"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h"; sourceTree = "SOURCE_ROOT"; };
F26339EFC03BD8D22016EEB6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_HeapBlock.h"; path = "../../../../modules/juce_core/memory/juce_HeapBlock.h"; sourceTree = "SOURCE_ROOT"; };
+ F29F6395C4935C1A663A1D15 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GZIPDecompressorInputStream.h"; path = "../../../../modules/juce_core/zip/juce_GZIPDecompressorInputStream.h"; sourceTree = "SOURCE_ROOT"; };
+ F380FE12E78619086BA33CDB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_InterprocessConnection.cpp"; path = "../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp"; sourceTree = "SOURCE_ROOT"; };
F3A9E0AE5ED05CA1AD6F56E5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SystemAudioVolume.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h"; sourceTree = "SOURCE_ROOT"; };
F3AF542BB3A9E6CC1D6E37DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PluginListComponent.cpp"; path = "../../../../modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
F3B746DC92EFE7A9B8EA9E43 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_UndoableAction.h"; path = "../../../../modules/juce_data_structures/undomanager/juce_UndoableAction.h"; sourceTree = "SOURCE_ROOT"; };
@@ -981,6 +982,7 @@
F843FC09B4C2A10C76D8D35C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PluginDirectoryScanner.cpp"; path = "../../../../modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp"; sourceTree = "SOURCE_ROOT"; };
F881704607DB79F9A3CF7491 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Audio.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp"; sourceTree = "SOURCE_ROOT"; };
F89584972F16A8EC49E5E74D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeCoordinatePositioner.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.h"; sourceTree = "SOURCE_ROOT"; };
+ F91A3C07D81BE2D4A191C9A2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Timer.h"; path = "../../../../modules/juce_events/timers/juce_Timer.h"; sourceTree = "SOURCE_ROOT"; };
F965E478C21D19EF32760A9C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FilePreviewComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h"; sourceTree = "SOURCE_ROOT"; };
F97F775EDCD2D1C497625D4F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_Fonts.mm"; path = "../../../../modules/juce_graphics/native/juce_mac_Fonts.mm"; sourceTree = "SOURCE_ROOT"; };
F98BEA2FEE66A3DEAD9D43B1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_mac_SystemTrayIcon.cpp"; path = "../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -1032,6 +1034,7 @@
24B00BED20980D12119C228F,
FD46383E356A5DDC1AD53380,
2DA02BCCDBFD5BF2DA2D2FA9,
+ 39A06D3252DDA6F97FB09495,
5AB15A508A07934A89398A6B,
84BAF97675BE522B63DC9A4B,
B731664FB9EEEBC618BAB5A0,
@@ -2270,6 +2273,7 @@
2346D126B3690390A0925F06,
C54286354BE46CB39B4C5225,
FE559832F5E168F0FF04CB6E,
+ E635FA4F49200CDAE3E4E6F0,
CDC1A7E9F07FBFDD5DA92031,
5B96583E8DAA4EA4EA1ACF18,
372B92C7E54D51285649FDD1,
diff --git a/extras/Demo/JuceDemo.jucer b/extras/Demo/JuceDemo.jucer
index 4ee5f6203d..c15855472f 100644
--- a/extras/Demo/JuceDemo.jucer
+++ b/extras/Demo/JuceDemo.jucer
@@ -250,6 +250,8 @@
+
demo ("20 Graphics: OpenGL");
+
+#endif
diff --git a/extras/Demo/Source/Demos/OpenGLDemo2D.cpp b/extras/Demo/Source/Demos/OpenGLDemo2D.cpp
new file mode 100644
index 0000000000..e94c6bea4d
--- /dev/null
+++ b/extras/Demo/Source/Demos/OpenGLDemo2D.cpp
@@ -0,0 +1,250 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-12 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+#include "../JuceDemoHeader.h"
+
+#if JUCE_OPENGL
+
+//==============================================================================
+class OpenGL2DShaderDemo : public Component,
+ private CodeDocument::Listener,
+ private ComboBox::Listener,
+ private Timer
+{
+public:
+ OpenGL2DShaderDemo()
+ : fragmentEditorComp (fragmentDocument, nullptr)
+ {
+ setOpaque (true);
+ MainAppWindow::getMainAppWindow()->setOpenGLRenderingEngine();
+
+ addAndMakeVisible (statusLabel);
+ statusLabel.setJustificationType (Justification::topLeft);
+ statusLabel.setColour (Label::textColourId, Colours::black);
+ statusLabel.setFont (Font (14.0f));
+
+ Array presets (getPresets());
+ StringArray presetNames;
+
+ for (int i = 0; i < presets.size(); ++i)
+ presetBox.addItem (presets[i].name, i + 1);
+
+ addAndMakeVisible (presetLabel);
+ presetLabel.setText ("Shader Preset:", dontSendNotification);
+ presetLabel.attachToComponent (&presetBox, true);
+
+ addAndMakeVisible (presetBox);
+ presetBox.addListener (this);
+
+ Colour editorBackground (Colours::white.withAlpha (0.6f));
+ fragmentEditorComp.setColour (CodeEditorComponent::backgroundColourId, editorBackground);
+ fragmentEditorComp.setOpaque (false);
+ fragmentDocument.addListener (this);
+ addAndMakeVisible (fragmentEditorComp);
+
+ presetBox.setSelectedItemIndex (0);
+ }
+
+ ~OpenGL2DShaderDemo()
+ {
+ shader = nullptr;
+ }
+
+ void paint (Graphics& g)
+ {
+ g.fillCheckerBoard (getLocalBounds(), 48, 48, Colours::lightgrey, Colours::white);
+
+ if (shader == nullptr || shader->getFragmentShaderCode() != fragmentCode)
+ {
+ shader = nullptr;
+
+ if (fragmentCode.isNotEmpty())
+ {
+ shader = new OpenGLGraphicsContextCustomShader (fragmentCode);
+
+ Result result (shader->checkCompilation (g.getInternalContext()));
+
+ if (result.failed())
+ {
+ statusLabel.setText (result.getErrorMessage(), dontSendNotification);
+ shader = nullptr;
+ }
+ }
+ }
+
+ if (shader != nullptr)
+ {
+ statusLabel.setText (String::empty, dontSendNotification);
+
+ shader->fillRect (g.getInternalContext(), getLocalBounds());
+ }
+ }
+
+ void resized() override
+ {
+ Rectangle area (getLocalBounds().reduced (4));
+
+ statusLabel.setBounds (area.removeFromTop (75));
+
+ area.removeFromTop (area.getHeight() / 2);
+
+ Rectangle presets (area.removeFromTop (25));
+ presets.removeFromLeft (100);
+ presetBox.setBounds (presets.removeFromLeft (150));
+
+ area.removeFromTop (4);
+ fragmentEditorComp.setBounds (area);
+ }
+
+ void selectPreset (int preset)
+ {
+ const ShaderPreset& p = getPresets()[preset];
+ fragmentDocument.replaceAllContent (p.fragmentShader);
+ startTimer (1);
+ }
+
+ ScopedPointer shader;
+
+ Label statusLabel, presetLabel;
+ ComboBox presetBox;
+ CodeDocument fragmentDocument;
+ CodeEditorComponent fragmentEditorComp;
+ String fragmentCode;
+
+private:
+ enum { shaderLinkDelay = 500 };
+
+ void codeDocumentTextInserted (const String& /*newText*/, int /*insertIndex*/) override
+ {
+ startTimer (shaderLinkDelay);
+ }
+
+ void codeDocumentTextDeleted (int /*startIndex*/, int /*endIndex*/) override
+ {
+ startTimer (shaderLinkDelay);
+ }
+
+ void timerCallback() override
+ {
+ stopTimer();
+ fragmentCode = fragmentDocument.getAllContent();
+ repaint();
+ }
+
+ void comboBoxChanged (ComboBox*) override
+ {
+ selectPreset (presetBox.getSelectedItemIndex());
+ }
+
+ struct ShaderPreset
+ {
+ const char* name;
+ const char* fragmentShader;
+ };
+
+ static Array getPresets()
+ {
+ #define SHADER_DEMO_HEADER \
+ "/* This demo shows the use of the OpenGLGraphicsContextCustomShader,\n" \
+ " which allows a 2D area to be filled using a GL shader program.\n" \
+ "\n" \
+ " Edit the shader program below and it will be \n" \
+ " recompiled in real-time!\n" \
+ "*/\n\n"
+
+ ShaderPreset presets[] =
+ {
+ {
+ "Simple Gradient",
+
+ SHADER_DEMO_HEADER
+ "void main()\n"
+ "{\n"
+ " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
+ " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
+ " " JUCE_MEDIUMP " float alpha = pixelPos.x / 1000.0;\n"
+ " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
+ "}\n"
+ },
+
+ {
+ "Circular Gradient",
+
+ SHADER_DEMO_HEADER
+ "void main()\n"
+ "{\n"
+ " " JUCE_MEDIUMP " vec4 colour1 = vec4 (1.0, 0.4, 0.6, 1.0);\n"
+ " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.3, 0.4, 0.4, 1.0);\n"
+ " " JUCE_MEDIUMP " float alpha = distance (pixelPos, vec2 (600.0, 500.0)) / 400.0;\n"
+ " gl_FragColor = pixelAlpha * mix (colour1, colour2, alpha);\n"
+ "}\n"
+ },
+
+ {
+ "Cicle",
+
+ SHADER_DEMO_HEADER
+ "void main()\n"
+ "{\n"
+ " " JUCE_MEDIUMP " vec4 colour1 = vec4 (0.1, 0.1, 0.9, 1.0);\n"
+ " " JUCE_MEDIUMP " vec4 colour2 = vec4 (0.0, 0.8, 0.6, 1.0);\n"
+ " " JUCE_MEDIUMP " float distance = distance (pixelPos, vec2 (600.0, 500.0));\n"
+ "\n"
+ " " JUCE_MEDIUMP " const float innerRadius = 200.0;\n"
+ " " JUCE_MEDIUMP " const float outerRadius = 210.0;\n"
+ "\n"
+ " if (distance < innerRadius)\n"
+ " gl_FragColor = colour1;\n"
+ " else if (distance > outerRadius)\n"
+ " gl_FragColor = colour2;\n"
+ " else\n"
+ " gl_FragColor = mix (colour1, colour2, (distance - innerRadius) / (outerRadius - innerRadius));\n"
+ "\n"
+ " gl_FragColor *= pixelAlpha;\n"
+ "}\n"
+ },
+
+ {
+ "Solid Colour",
+
+ SHADER_DEMO_HEADER
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4 (1.0, 0.6, 0.1, pixelAlpha);\n"
+ "}\n"
+ }
+ };
+
+ return Array (presets, numElementsInArray (presets));
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGL2DShaderDemo)
+};
+
+//==============================================================================
+// This static object will register this demo type in a global list of demos..
+static JuceDemoType demo ("20 Graphics: OpenGL 2D");
+
+#endif
diff --git a/extras/Demo/Source/MainWindow.cpp b/extras/Demo/Source/MainWindow.cpp
index 291694587f..035a83d2f7 100644
--- a/extras/Demo/Source/MainWindow.cpp
+++ b/extras/Demo/Source/MainWindow.cpp
@@ -215,7 +215,14 @@ public:
bool isShowingOpenGLDemo() const
{
- return currentDemo != nullptr && currentDemo->getName().contains ("OpenGL");
+ return currentDemo != nullptr
+ && currentDemo->getName().contains ("OpenGL")
+ && ! isShowingOpenGL2DDemo();
+ }
+
+ bool isShowingOpenGL2DDemo() const
+ {
+ return currentDemo != nullptr && currentDemo->getName().contains ("OpenGL 2D");
}
private:
@@ -605,6 +612,11 @@ void MainAppWindow::setRenderingEngine (int index)
peer->setCurrentRenderingEngine (index);
}
+void MainAppWindow::setOpenGLRenderingEngine()
+{
+ setRenderingEngine (getRenderingEngines().indexOf (openGLRendererName));
+}
+
int MainAppWindow::getActiveRenderingEngine() const
{
#if JUCE_OPENGL
diff --git a/extras/Demo/Source/MainWindow.h b/extras/Demo/Source/MainWindow.h
index d47509ceda..2bfe058211 100644
--- a/extras/Demo/Source/MainWindow.h
+++ b/extras/Demo/Source/MainWindow.h
@@ -51,6 +51,7 @@ public:
StringArray getRenderingEngines() const;
int getActiveRenderingEngine() const;
void setRenderingEngine (int index);
+ void setOpenGLRenderingEngine();
// (returns the exploding JUCE logo path)
static Path getJUCELogoPath();
diff --git a/modules/juce_opengl/juce_opengl.h b/modules/juce_opengl/juce_opengl.h
index d805383a9b..d4f675024c 100644
--- a/modules/juce_opengl/juce_opengl.h
+++ b/modules/juce_opengl/juce_opengl.h
@@ -95,6 +95,7 @@ namespace juce
class OpenGLTexture;
class OpenGLFrameBuffer;
+class OpenGLShaderProgram;
#include "native/juce_MissingGLDefinitions.h"
#include "opengl/juce_OpenGLHelpers.h"
diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp
index 8c05d8c02a..ac3644ec66 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp
+++ b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp
@@ -739,9 +739,17 @@ void OpenGLContext::setAssociatedObject (const char* name, ReferenceCountedObjec
if (index >= 0)
{
- c->associatedObjects.set (index, newObject);
+ if (newObject != nullptr)
+ {
+ c->associatedObjects.set (index, newObject);
+ }
+ else
+ {
+ c->associatedObjectNames.remove (index);
+ c->associatedObjects.remove (index);
+ }
}
- else
+ else if (newObject != nullptr)
{
c->associatedObjectNames.add (name);
c->associatedObjects.add (newObject);
diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
index afd0e38ae2..b257841b25 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
+++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
@@ -354,12 +354,13 @@ public:
" gl_Position = vec4 (scaledPos.x - 1.0, 1.0 - scaledPos.y, 0, 1.0);"
"}");
- program.addFragmentShader (fragmentShader);
+ compiledOk = program.addFragmentShader (fragmentShader);
program.link();
JUCE_CHECK_OPENGL_ERROR
}
OpenGLShaderProgram program;
+ bool compiledOk;
};
struct ShaderBase : public ShaderProgramHolder
@@ -1492,12 +1493,13 @@ class SavedState : public RenderingHelpers::SavedStateBase
public:
SavedState (GLState* const s)
- : BaseClass (s->target.bounds), state (s)
+ : BaseClass (s->target.bounds), state (s), isUsingCustomShader (false)
{}
SavedState (const SavedState& other)
: BaseClass (other), font (other.font),
- state (other.state), transparencyLayer (other.transparencyLayer),
+ state (other.state), isUsingCustomShader (false),
+ transparencyLayer (other.transparencyLayer),
previousTarget (other.previousTarget.createCopy())
{}
@@ -1618,9 +1620,13 @@ public:
template
void fillWithSolidColour (IteratorType& iter, const PixelARGB colour, bool replaceContents) const
{
- state->activeTextures.disableTextures (state->shaderQuadQueue);
- state->blendMode.setBlendMode (state->shaderQuadQueue, replaceContents);
- state->setShader (state->currentShader.programs->solidColourProgram);
+ if (! isUsingCustomShader)
+ {
+ state->activeTextures.disableTextures (state->shaderQuadQueue);
+ state->blendMode.setBlendMode (state->shaderQuadQueue, replaceContents);
+ state->setShader (state->currentShader.programs->solidColourProgram);
+ }
+
state->shaderQuadQueue.add (iter, colour);
}
@@ -1631,16 +1637,21 @@ public:
state->shaderQuadQueue.add (iter, fillType.colour.getPixelARGB());
}
- void fillRectWithCustomShader (OpenGLRendering::ShaderPrograms::ShaderBase& shader, const Rectangle& area, Colour colour)
+ void fillRectWithCustomShader (OpenGLRendering::ShaderPrograms::ShaderBase& shader, const Rectangle& area)
{
state->setShader (shader);
- state->shaderQuadQueue.add (area, colour.getPixelARGB());
+ isUsingCustomShader = true;
+
+ fillRect (area, true);
+
+ isUsingCustomShader = false;
state->currentShader.clearShader (state->shaderQuadQueue);
}
//==============================================================================
Font font;
GLState* state;
+ bool isUsingCustomShader;
private:
Image transparencyLayer;
@@ -1659,9 +1670,9 @@ public:
stack.initialise (new SavedState (&glState));
}
- void fillRectWithCustomShader (ShaderPrograms::ShaderBase& shader, const Rectangle& area, Colour colour)
+ void fillRectWithCustomShader (ShaderPrograms::ShaderBase& shader, const Rectangle& area)
{
- static_cast (*stack).fillRectWithCustomShader (shader, area, colour);
+ static_cast (*stack).fillRectWithCustomShader (shader, area);
}
GLState glState;
@@ -1750,39 +1761,88 @@ void clearOpenGLGlyphCache()
//==============================================================================
-struct OpenGLGraphicsContextCustomShader::Pimpl : public OpenGLRendering::ShaderPrograms::ShaderBase
+struct CustomProgram : public ReferenceCountedObject,
+ public OpenGLRendering::ShaderPrograms::ShaderBase
{
- Pimpl (OpenGLRendering::ShaderContext& c, const String& fragmentShader)
+ CustomProgram (OpenGLRendering::ShaderContext& c, const String& fragmentShader)
: ShaderBase (c.glState.target.context, fragmentShader.toRawUTF8())
{
}
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
-};
+ static CustomProgram* get (const String& hashName)
+ {
+ if (OpenGLContext* c = OpenGLContext::getCurrentContext())
+ return static_cast (c->getAssociatedObject (hashName.toRawUTF8()));
-OpenGLGraphicsContextCustomShader::OpenGLGraphicsContextCustomShader (Pimpl* p) : pimpl (p) {}
-OpenGLGraphicsContextCustomShader::~OpenGLGraphicsContextCustomShader() {}
+ return nullptr;
+ }
-OpenGLGraphicsContextCustomShader* OpenGLGraphicsContextCustomShader::create (LowLevelGraphicsContext& gc, StringRef fragmentShaderCode)
-{
- if (OpenGLRendering::ShaderContext* sc = dynamic_cast (&gc))
+ static CustomProgram* getOrCreate (LowLevelGraphicsContext& gc, const String& hashName, const String& code, String& errorMessage)
{
- ScopedPointer p (new Pimpl (*sc, String (JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS "\n") + fragmentShaderCode));
+ if (CustomProgram* c = get (hashName))
+ return c;
+
+ if (OpenGLRendering::ShaderContext* sc = dynamic_cast (&gc))
+ {
+ ReferenceCountedObjectPtr c (new CustomProgram (*sc, code));
+
+ if (c->compiledOk)
+ {
+ if (OpenGLContext* context = OpenGLContext::getCurrentContext())
+ {
+ context->setAssociatedObject (hashName.toRawUTF8(), c);
+ return c;
+ }
+ }
- if (! p->program.isLinked())
- return nullptr;
+ errorMessage = c->program.getLastError();
+ }
- return new OpenGLGraphicsContextCustomShader (p.release());
+ return nullptr;
}
- jassertfalse; // You've passed-in a non-GL context!
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomProgram)
+};
+
+OpenGLGraphicsContextCustomShader::OpenGLGraphicsContextCustomShader (const String& fragmentShaderCode)
+ : code (String (JUCE_DECLARE_VARYING_COLOUR
+ JUCE_DECLARE_VARYING_PIXELPOS
+ "\nfloat pixelAlpha = frontColour.a;\n") + fragmentShaderCode),
+ hashName (String::toHexString (fragmentShaderCode.hashCode64()) + "_shader")
+{
+}
+
+OpenGLGraphicsContextCustomShader::~OpenGLGraphicsContextCustomShader()
+{
+ if (OpenGLContext* context = OpenGLContext::getCurrentContext())
+ context->setAssociatedObject (hashName.toRawUTF8(), nullptr);
+}
+
+OpenGLShaderProgram* OpenGLGraphicsContextCustomShader::getProgram (LowLevelGraphicsContext& gc) const
+{
+ String errorMessage;
+
+ if (CustomProgram* c = CustomProgram::getOrCreate (gc, hashName, code, errorMessage))
+ return &(c->program);
+
return nullptr;
}
-void OpenGLGraphicsContextCustomShader::fillRect (LowLevelGraphicsContext& gc, const Rectangle& area, Colour colour) const
+void OpenGLGraphicsContextCustomShader::fillRect (LowLevelGraphicsContext& gc, const Rectangle& area) const
{
- jassert (pimpl != nullptr);
+ String errorMessage;
if (OpenGLRendering::ShaderContext* sc = dynamic_cast (&gc))
- sc->fillRectWithCustomShader (*pimpl, area, colour);
+ if (CustomProgram* c = CustomProgram::getOrCreate (gc, hashName, code, errorMessage))
+ sc->fillRectWithCustomShader (*c, area);
+}
+
+Result OpenGLGraphicsContextCustomShader::checkCompilation (LowLevelGraphicsContext& gc)
+{
+ String errorMessage;
+
+ if (CustomProgram::getOrCreate (gc, hashName, code, errorMessage) != nullptr)
+ return Result::ok();
+
+ return Result::fail (errorMessage);
}
diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
index c087d81b64..b94a80c83e 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
+++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
@@ -47,41 +47,47 @@ LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context,
//==============================================================================
-/**
+/**
Used to create custom shaders for use with an openGL 2D rendering context.
-
+
Given a GL-based rendering context, you can write a fragment shader that applies some
kind of per-pixel effect.
*/
struct JUCE_API OpenGLGraphicsContextCustomShader
{
+ /** Creates a custom shader.
+
+ The shader code will not be compiled until actually needed, so it's OK to call this
+ constructor when no GL context is active.
+
+ The code should be a normal fragment shader. As well as the usual GLSL variables, there is
+ also an automatically declared varying vec2 called "pixelPos", which indicates the pixel
+ position within the graphics context of the pixel being drawn. There is also a varying value
+ "pixelAlpha", which indicates the alpha by which the pixel should be multiplied, so that the
+ edges of any clip-region masks are anti-aliased correctly.
+ */
+ OpenGLGraphicsContextCustomShader (const String& fragmentShaderCode);
+
/** Destructor. */
~OpenGLGraphicsContextCustomShader();
- /** Attempts to compile and return a new shader object.
- This must be called only when an openGL context is active. It'll return nullptr
- if the code fails to compile or some other error occurs.
-
- The shader code should be a normal fragment shader. As well as the usual variables, there
- will be some extra ones: "frontColour", which is the colour that gets passed into the fillRect
- method, and "pixelPos", which is a vec2 indicating the pixel position within the graphics context
- of the pixel being drawn.
+ /** Returns the program, if it has been linked and is active.
+ This can be called when you're about to use fillRect, to set up any uniforms/textures that
+ the program may require.
*/
- static OpenGLGraphicsContextCustomShader* create (LowLevelGraphicsContext&,
- StringRef fragmentShaderCode);
+ OpenGLShaderProgram* getProgram (LowLevelGraphicsContext&) const;
- /** Applies the shader to a rectangle within the graphics context.
- NB: This will ignore any clip region that is active.
- */
- void fillRect (LowLevelGraphicsContext&, const Rectangle& area, Colour colour) const;
+ /** Applies the shader to a rectangle within the graphics context. */
+ void fillRect (LowLevelGraphicsContext&, const Rectangle& area) const;
-private:
- struct Pimpl;
- friend struct Pimpl;
- friend struct ContainerDeletePolicy;
- ScopedPointer pimpl;
+ /** Attempts to compile the program if necessary, and returns an error message if it fails. */
+ Result checkCompilation (LowLevelGraphicsContext&);
- OpenGLGraphicsContextCustomShader (Pimpl*);
+ /** Returns the code that was used to create this object. */
+ const String& getFragmentShaderCode() const noexcept { return code; }
+
+private:
+ String code, hashName;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLGraphicsContextCustomShader)
};
diff --git a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.cpp b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.cpp
index 07f33b0e81..8e53dc228a 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.cpp
+++ b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.cpp
@@ -23,17 +23,33 @@
*/
OpenGLShaderProgram::OpenGLShaderProgram (const OpenGLContext& c) noexcept
- : context (c)
+ : context (c), programID (0)
{
- // This object can only be created and used when the current thread has an active OpenGL context.
+}
+
+OpenGLShaderProgram::~OpenGLShaderProgram() noexcept
+{
+ release();
+}
+
+GLuint OpenGLShaderProgram::getProgramID() const noexcept
+{
+ // This method can only be used when the current thread has an active OpenGL context.
jassert (OpenGLHelpers::isContextActive());
- programID = context.extensions.glCreateProgram();
+ if (programID == 0)
+ programID = context.extensions.glCreateProgram();
+
+ return programID;
}
-OpenGLShaderProgram::~OpenGLShaderProgram() noexcept
+void OpenGLShaderProgram::release() noexcept
{
- context.extensions.glDeleteProgram (programID);
+ if (programID != 0)
+ {
+ context.extensions.glDeleteProgram (programID);
+ programID = 0;
+ }
}
double OpenGLShaderProgram::getLanguageVersion()
@@ -83,7 +99,7 @@ bool OpenGLShaderProgram::addShader (StringRef code, GLenum type)
return false;
}
- context.extensions.glAttachShader (programID, shaderID);
+ context.extensions.glAttachShader (getProgramID(), shaderID);
context.extensions.glDeleteShader (shaderID);
JUCE_CHECK_OPENGL_ERROR
return true;
@@ -94,16 +110,21 @@ bool OpenGLShaderProgram::addFragmentShader (StringRef code) { return addShader
bool OpenGLShaderProgram::link() noexcept
{
- context.extensions.glLinkProgram (programID);
+ // This method can only be used when the current thread has an active OpenGL context.
+ jassert (OpenGLHelpers::isContextActive());
+
+ GLuint progID = getProgramID();
+
+ context.extensions.glLinkProgram (progID);
GLint status = GL_FALSE;
- context.extensions.glGetProgramiv (programID, GL_LINK_STATUS, &status);
+ context.extensions.glGetProgramiv (progID, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLchar infoLog [16384];
GLsizei infoLogLength = 0;
- context.extensions.glGetProgramInfoLog (programID, sizeof (infoLog), &infoLogLength, infoLog);
+ context.extensions.glGetProgramInfoLog (progID, sizeof (infoLog), &infoLogLength, infoLog);
errorLog = String (infoLog, (size_t) infoLogLength);
#if JUCE_DEBUG && ! JUCE_DONT_ASSERT_ON_GLSL_COMPILE_ERROR
@@ -124,13 +145,13 @@ void OpenGLShaderProgram::use() const noexcept
}
OpenGLShaderProgram::Uniform::Uniform (const OpenGLShaderProgram& program, const char* const name)
- : uniformID (program.context.extensions.glGetUniformLocation (program.programID, name)), context (program.context)
+ : uniformID (program.context.extensions.glGetUniformLocation (program.getProgramID(), name)), context (program.context)
{
jassert (uniformID >= 0);
}
OpenGLShaderProgram::Attribute::Attribute (const OpenGLShaderProgram& program, const char* name)
- : attributeID (program.context.extensions.glGetAttribLocation (program.programID, name))
+ : attributeID (program.context.extensions.glGetAttribLocation (program.getProgramID(), name))
{
jassert (attributeID >= 0);
}
diff --git a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h
index 17d0f258de..6a74ebf2a8 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h
+++ b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h
@@ -82,12 +82,12 @@ public:
/** Get the output for the last shader compilation or link that failed. */
const String& getLastError() const noexcept { return errorLog; }
- /** Returns true if the program is linked and ready for use. */
- bool isLinked() const noexcept { return programID != 0; }
-
/** Selects this program into the current context. */
void use() const noexcept;
+ /** Deletes the program. */
+ void release() noexcept;
+
/** Represents an openGL uniform value.
After a program has been linked, you can create Uniform objects to let you
set the uniforms that your shaders use.
@@ -154,10 +154,11 @@ public:
};
/** The ID number of the compiled program. */
- GLuint programID;
+ GLuint getProgramID() const noexcept;
private:
const OpenGLContext& context;
+ mutable GLuint programID;
String errorLog;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLShaderProgram)