diff --git a/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj b/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
index f9c32d1bd4..5022108bd1 100644
--- a/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
+++ b/extras/JuceDemo/Builds/MacOSX/Juce Demo.xcodeproj/project.pbxproj
@@ -195,6 +195,7 @@
2820D74789660269902DB93A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Uuid.cpp"; path = "../../../../modules/juce_core/misc/juce_Uuid.cpp"; sourceTree = "SOURCE_ROOT"; };
282C1DA3A161FEF2AD6F94A6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_CodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
2954678FE7AB78F318FBD4F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileInputStream.h"; path = "../../../../modules/juce_core/files/juce_FileInputStream.h"; sourceTree = "SOURCE_ROOT"; };
+ 295A470694011EBCA802822B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OpenGLGraphicsContext.cpp"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; };
2968B26144E09D6A6659E739 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DirectShowComponent.h"; path = "../../../../modules/juce_video/playback/juce_DirectShowComponent.h"; sourceTree = "SOURCE_ROOT"; };
2A835EF38887CAB750B49AC6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativePointPath.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePointPath.h"; sourceTree = "SOURCE_ROOT"; };
2ACD67859FBC33EB743708CB = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextButton.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_TextButton.h"; sourceTree = "SOURCE_ROOT"; };
@@ -624,6 +625,7 @@
A6FCBC9721E7FC9DE30B6DC4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Midi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp"; sourceTree = "SOURCE_ROOT"; };
A72FB74D13AA5C6A472E9E82 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChangeBroadcaster.cpp"; path = "../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp"; sourceTree = "SOURCE_ROOT"; };
A763E7AF50D548D8C4A4C3D1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDeviceManager.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h"; sourceTree = "SOURCE_ROOT"; };
+ A7B3B265DACC82D9E9CFB3DA = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGLGraphicsContext.h"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; };
A7BD5AB895B2531A75FE0268 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BufferingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
A7F413D4C880363878469E5A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_JSON.h"; path = "../../../../modules/juce_core/json/juce_JSON.h"; sourceTree = "SOURCE_ROOT"; };
A80CC48B8215D447643CA411 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ToolbarItemFactory.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h"; sourceTree = "SOURCE_ROOT"; };
@@ -1869,6 +1871,8 @@
8878426C7F58CB22969E7133,
AC3EFDDC80761A45E8BE0624,
43E4604C39E9A992216F6B98,
+ 295A470694011EBCA802822B,
+ A7B3B265DACC82D9E9CFB3DA,
D7239D5B984E07808E2DB28C,
D2C40CDF46D894BFC72BDC56,
E46977801F19277F4D3B324B,
diff --git a/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj b/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
index 9ebe58ca6d..f49513f88c 100644
--- a/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
+++ b/extras/JuceDemo/Builds/VisualStudio2005/Juce Demo.vcproj
@@ -4220,6 +4220,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj b/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
index 7c982899bd..84cb693340 100644
--- a/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
+++ b/extras/JuceDemo/Builds/VisualStudio2008/Juce Demo.vcproj
@@ -4220,6 +4220,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
index e0d88e7227..2ee0b709bb 100644
--- a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
+++ b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj
@@ -1133,6 +1133,9 @@
true
+
+ true
+
true
@@ -1578,6 +1581,7 @@
+
diff --git a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
index ff3a96bcaa..9db7eaca1c 100644
--- a/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
+++ b/extras/JuceDemo/Builds/VisualStudio2010/Juce Demo.vcxproj.filters
@@ -1486,6 +1486,9 @@
Juce Modules\juce_opengl\opengl
+
+ Juce Modules\juce_opengl\opengl
+
Juce Modules\juce_opengl\opengl
@@ -2775,6 +2778,9 @@
Juce Modules\juce_opengl\opengl
+
+ Juce Modules\juce_opengl\opengl
+
Juce Modules\juce_opengl\opengl
diff --git a/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj b/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
index 7c84ef9557..693c8d2694 100644
--- a/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
+++ b/extras/JuceDemo/Builds/iOS/Juce Demo.xcodeproj/project.pbxproj
@@ -188,6 +188,7 @@
2820D74789660269902DB93A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Uuid.cpp"; path = "../../../../modules/juce_core/misc/juce_Uuid.cpp"; sourceTree = "SOURCE_ROOT"; };
282C1DA3A161FEF2AD6F94A6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_CodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
2954678FE7AB78F318FBD4F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileInputStream.h"; path = "../../../../modules/juce_core/files/juce_FileInputStream.h"; sourceTree = "SOURCE_ROOT"; };
+ 295A470694011EBCA802822B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OpenGLGraphicsContext.cpp"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; };
2968B26144E09D6A6659E739 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DirectShowComponent.h"; path = "../../../../modules/juce_video/playback/juce_DirectShowComponent.h"; sourceTree = "SOURCE_ROOT"; };
2A835EF38887CAB750B49AC6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativePointPath.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePointPath.h"; sourceTree = "SOURCE_ROOT"; };
2ACD67859FBC33EB743708CB = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextButton.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_TextButton.h"; sourceTree = "SOURCE_ROOT"; };
@@ -616,6 +617,7 @@
A6FCBC9721E7FC9DE30B6DC4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Midi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp"; sourceTree = "SOURCE_ROOT"; };
A72FB74D13AA5C6A472E9E82 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ChangeBroadcaster.cpp"; path = "../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp"; sourceTree = "SOURCE_ROOT"; };
A763E7AF50D548D8C4A4C3D1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDeviceManager.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h"; sourceTree = "SOURCE_ROOT"; };
+ A7B3B265DACC82D9E9CFB3DA = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGLGraphicsContext.h"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; };
A7BD5AB895B2531A75FE0268 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BufferingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
A7F413D4C880363878469E5A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_JSON.h"; path = "../../../../modules/juce_core/json/juce_JSON.h"; sourceTree = "SOURCE_ROOT"; };
A80CC48B8215D447643CA411 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ToolbarItemFactory.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h"; sourceTree = "SOURCE_ROOT"; };
@@ -1859,6 +1861,8 @@
8878426C7F58CB22969E7133,
AC3EFDDC80761A45E8BE0624,
43E4604C39E9A992216F6B98,
+ 295A470694011EBCA802822B,
+ A7B3B265DACC82D9E9CFB3DA,
D7239D5B984E07808E2DB28C,
D2C40CDF46D894BFC72BDC56,
E46977801F19277F4D3B324B,
diff --git a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp
index fdc3a0122e..ee1f4a8e2a 100644
--- a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp
+++ b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp
@@ -133,7 +133,7 @@ private:
// Functions to create a couple of images to use as textures..
static Image createImage1()
{
- Image image (new OpenGLFrameBufferImage (Image::ARGB, 256, 256));
+ Image image (new OpenGLFrameBufferImage (256, 256));
Graphics g (image);
@@ -148,7 +148,7 @@ private:
static Image createImage2()
{
- Image image (new OpenGLFrameBufferImage (Image::ARGB, 128, 128));
+ Image image (new OpenGLFrameBufferImage (128, 128));
Graphics g (image);
g.fillAll (Colours::darkred.withAlpha (0.7f));
diff --git a/extras/audio plugin host/Builds/MacOSX/Plugin Host.xcodeproj/project.pbxproj b/extras/audio plugin host/Builds/MacOSX/Plugin Host.xcodeproj/project.pbxproj
index 7a0e39bda5..15e42d017c 100644
--- a/extras/audio plugin host/Builds/MacOSX/Plugin Host.xcodeproj/project.pbxproj
+++ b/extras/audio plugin host/Builds/MacOSX/Plugin Host.xcodeproj/project.pbxproj
@@ -260,6 +260,7 @@
3ED29A00C88C8C3B8B3DE56D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ShapeButton.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_ShapeButton.h"; sourceTree = "SOURCE_ROOT"; };
3ED373A6B2C53518BAA012E6 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativeRectangle.cpp"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp"; sourceTree = "SOURCE_ROOT"; };
3EFBFA5735C496DC209ED1CE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_win32_HiddenMessageWindow.h"; path = "../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h"; sourceTree = "SOURCE_ROOT"; };
+ 3F263028F4926C6F3318E6A4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OpenGLGraphicsContext.cpp"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; };
3F924E9D75C642D0A14828E8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativePointPath.cpp"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePointPath.cpp"; sourceTree = "SOURCE_ROOT"; };
3F963B869D58A34E97922E97 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativePointPath.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePointPath.h"; sourceTree = "SOURCE_ROOT"; };
410A767D64DBE4AB92D56251 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextButton.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_TextButton.h"; sourceTree = "SOURCE_ROOT"; };
@@ -856,6 +857,7 @@
FE79AFFDB5029AC6AE7F4CFC = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RecentlyOpenedFilesList.h"; path = "../../../../modules/juce_gui_extra/misc/juce_RecentlyOpenedFilesList.h"; sourceTree = "SOURCE_ROOT"; };
FE7C03DACFC725D712D9F508 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_utils.mm"; path = "../../../../modules/juce_audio_utils/juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; };
FEB2517E7420B23086B6580B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MenuBarModel.cpp"; path = "../../../../modules/juce_gui_basics/menus/juce_MenuBarModel.cpp"; sourceTree = "SOURCE_ROOT"; };
+ FF28173366C5BCF1BAE2CEA9 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGLGraphicsContext.h"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; };
FFC1C8C289D7D3FF39865E40 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ImageComponent.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_ImageComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
FFD8E80D93D1005D5983C057 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ToolbarItemFactory.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h"; sourceTree = "SOURCE_ROOT"; };
FFFA6E3ECEFDF1DE95D0F632 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_JackAudio.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -1791,6 +1793,8 @@
BE0231D93CBB02BBC2704D1D,
43D23C18695F24F9A3DFA7B4,
438CA87567F47F9AF39788D1,
+ 3F263028F4926C6F3318E6A4,
+ FF28173366C5BCF1BAE2CEA9,
153D339EB2CCEC711215AD04,
9B4278735225CBEED635FF03,
C0EECABDA5446EAD76E2578F,
diff --git a/extras/audio plugin host/Builds/VisualStudio2005/Plugin Host.vcproj b/extras/audio plugin host/Builds/VisualStudio2005/Plugin Host.vcproj
index 9eca1ce9af..3860e9871b 100644
--- a/extras/audio plugin host/Builds/VisualStudio2005/Plugin Host.vcproj
+++ b/extras/audio plugin host/Builds/VisualStudio2005/Plugin Host.vcproj
@@ -4143,6 +4143,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/extras/audio plugin host/Builds/VisualStudio2008/Plugin Host.vcproj b/extras/audio plugin host/Builds/VisualStudio2008/Plugin Host.vcproj
index e1368cfb59..c23e1c5af5 100644
--- a/extras/audio plugin host/Builds/VisualStudio2008/Plugin Host.vcproj
+++ b/extras/audio plugin host/Builds/VisualStudio2008/Plugin Host.vcproj
@@ -4143,6 +4143,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/extras/static library/Builds/MacOSX/juce.xcodeproj/project.pbxproj b/extras/static library/Builds/MacOSX/juce.xcodeproj/project.pbxproj
index fe79b14fd5..957a63724b 100644
--- a/extras/static library/Builds/MacOSX/juce.xcodeproj/project.pbxproj
+++ b/extras/static library/Builds/MacOSX/juce.xcodeproj/project.pbxproj
@@ -642,6 +642,7 @@
CDF3D87F97FF1526499CC3A1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Registry.cpp"; path = "../../../../modules/juce_core/native/juce_win32_Registry.cpp"; sourceTree = "SOURCE_ROOT"; };
CE55DEAD4829A44E6F68EBA3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_opengl.mm"; path = "../../../../modules/juce_opengl/juce_opengl.mm"; sourceTree = "SOURCE_ROOT"; };
CE598F0D6317056C9958D8DD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChangeListener.h"; path = "../../../../modules/juce_events/broadcasters/juce_ChangeListener.h"; sourceTree = "SOURCE_ROOT"; };
+ CEBE83A5D278021237C24D66 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OpenGLGraphicsContext.cpp"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; };
CEEB08E0152E40C0F7F7D9ED = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DynamicLibrary.h"; path = "../../../../modules/juce_core/threads/juce_DynamicLibrary.h"; sourceTree = "SOURCE_ROOT"; };
CF16F0D87956060986A260CE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TreeView.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_TreeView.h"; sourceTree = "SOURCE_ROOT"; };
CF234664EFB623E0E51BF84F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioUnitPluginFormat.h"; path = "../../../../modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h"; sourceTree = "SOURCE_ROOT"; };
@@ -683,6 +684,7 @@
D9725F490FFF28EE21FAE674 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImageEffectFilter.h"; path = "../../../../modules/juce_graphics/effects/juce_ImageEffectFilter.h"; sourceTree = "SOURCE_ROOT"; };
D974DED975BAB28D7E4DD088 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioTransportSource.h"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.h"; sourceTree = "SOURCE_ROOT"; };
D9A6F0D617C0DFE739401654 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ButtonPropertyComponent.h"; path = "../../../../modules/juce_gui_basics/properties/juce_ButtonPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; };
+ D9A93A1A24319A4E650E53B2 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGLGraphicsContext.h"; path = "../../../../modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; };
D9C8927A19B0A1D2AF2304B8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../../../modules/juce_events/native/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; };
D9D8C7CDA1EA11E65E539C00 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableCornerComponent.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ResizableCornerComponent.h"; sourceTree = "SOURCE_ROOT"; };
D9F02568E68C40FADFE9210F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FlacAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -1710,6 +1712,8 @@
6096E343983724F254B268C3,
73C6ABF23C4B143DB2BC7226,
9D4FC9BEE122256B2557D088,
+ CEBE83A5D278021237C24D66,
+ D9A93A1A24319A4E650E53B2,
92346B7BA7AFD6750405F6F3,
AEB9A6FBC99A1C710C51D799,
6DCD8800E380DB691DC9D467,
diff --git a/extras/static library/Builds/VisualStudio2008/juce.vcproj b/extras/static library/Builds/VisualStudio2008/juce.vcproj
index 6618ab9bfa..3f24242da0 100644
--- a/extras/static library/Builds/VisualStudio2008/juce.vcproj
+++ b/extras/static library/Builds/VisualStudio2008/juce.vcproj
@@ -4034,6 +4034,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/extras/static library/Builds/VisualStudio2010/juce.vcxproj b/extras/static library/Builds/VisualStudio2010/juce.vcxproj
index 9157b2e939..5b202f8414 100644
--- a/extras/static library/Builds/VisualStudio2010/juce.vcxproj
+++ b/extras/static library/Builds/VisualStudio2010/juce.vcxproj
@@ -1096,6 +1096,9 @@
true
+
+ true
+
true
@@ -1524,6 +1527,7 @@
+
diff --git a/extras/static library/Builds/VisualStudio2010/juce.vcxproj.filters b/extras/static library/Builds/VisualStudio2010/juce.vcxproj.filters
index b7382117a7..7b628553cd 100644
--- a/extras/static library/Builds/VisualStudio2010/juce.vcxproj.filters
+++ b/extras/static library/Builds/VisualStudio2010/juce.vcxproj.filters
@@ -1372,6 +1372,9 @@
Juce Modules\juce_opengl\opengl
+
+ Juce Modules\juce_opengl\opengl
+
Juce Modules\juce_opengl\opengl
@@ -2610,6 +2613,9 @@
Juce Modules\juce_opengl\opengl
+
+ Juce Modules\juce_opengl\opengl
+
Juce Modules\juce_opengl\opengl
diff --git a/modules/juce_opengl/juce_opengl.cpp b/modules/juce_opengl/juce_opengl.cpp
index 2924319f5f..60893ebb85 100644
--- a/modules/juce_opengl/juce_opengl.cpp
+++ b/modules/juce_opengl/juce_opengl.cpp
@@ -132,6 +132,7 @@
// START_AUTOINCLUDE opengl/*.cpp
#include "opengl/juce_OpenGLComponent.cpp"
#include "opengl/juce_OpenGLFrameBuffer.cpp"
+#include "opengl/juce_OpenGLGraphicsContext.cpp"
#include "opengl/juce_OpenGLHelpers.cpp"
#include "opengl/juce_OpenGLImage.cpp"
#include "opengl/juce_OpenGLTexture.cpp"
diff --git a/modules/juce_opengl/juce_opengl.h b/modules/juce_opengl/juce_opengl.h
index e82a054523..3a81426c23 100644
--- a/modules/juce_opengl/juce_opengl.h
+++ b/modules/juce_opengl/juce_opengl.h
@@ -29,10 +29,7 @@
#include "../juce_gui_extra/juce_gui_extra.h"
#undef JUCE_OPENGL
-
-#if ! JUCE_ANDROID
- #define JUCE_OPENGL 1
-#endif
+#define JUCE_OPENGL 1
#if JUCE_IOS || JUCE_ANDROID
#define JUCE_OPENGL_ES 1
@@ -95,6 +92,9 @@ BEGIN_JUCE_NAMESPACE
#ifndef __JUCE_OPENGLFRAMEBUFFER_JUCEHEADER__
#include "opengl/juce_OpenGLFrameBuffer.h"
#endif
+#ifndef __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__
+ #include "opengl/juce_OpenGLGraphicsContext.h"
+#endif
#ifndef __JUCE_OPENGLHELPERS_JUCEHEADER__
#include "opengl/juce_OpenGLHelpers.h"
#endif
diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
new file mode 100644
index 0000000000..774fed6841
--- /dev/null
+++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
@@ -0,0 +1,1199 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-11 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.
+
+ ==============================================================================
+*/
+
+BEGIN_JUCE_NAMESPACE
+
+namespace
+{
+ void applyFlippedMatrix (int x, int y, int width, int height)
+ {
+ OpenGLHelpers::prepareFor2D (width, height);
+ OpenGLHelpers::applyTransform (AffineTransform::translation ((float) -x, (float) -y)
+ .followedBy (AffineTransform::verticalFlip ((float) height)));
+ }
+}
+
+struct OpenGLTarget
+{
+ OpenGLTarget (GLuint frameBufferID_, int width_, int height_) noexcept
+ : frameBuffer (nullptr), frameBufferID (frameBufferID_),
+ x (0), y (0), width (width_), height (height_)
+ {}
+
+ OpenGLTarget (OpenGLFrameBuffer& frameBuffer_, const Point& origin) noexcept
+ : frameBuffer (&frameBuffer_), frameBufferID (0), x (origin.getX()), y (origin.getY()),
+ width (frameBuffer_.getWidth()), height (frameBuffer_.getHeight())
+ {}
+
+ OpenGLTarget (const OpenGLTarget& other) noexcept
+ : frameBuffer (other.frameBuffer), frameBufferID (other.frameBufferID),
+ x (other.x), y (other.y), width (other.width), height (other.height)
+ {}
+
+ void makeActiveFor2D() const
+ {
+ if (frameBuffer != nullptr)
+ frameBuffer->makeCurrentRenderingTarget();
+ else
+ OpenGLFrameBuffer::setCurrentFrameBufferTarget (frameBufferID);
+
+ applyFlippedMatrix (x, y, width, height);
+ glDisable (GL_DEPTH_TEST);
+ }
+
+ void scissor (Rectangle r) const
+ {
+ r = r.translated (-x, -y);
+ OpenGLHelpers::enableScissorTest (r.withY (height - r.getBottom()));
+ }
+
+ OpenGLFrameBuffer* frameBuffer;
+ GLuint frameBufferID;
+ int x, y, width, height;
+};
+
+//==============================================================================
+namespace
+{
+ enum { defaultOversamplingLevel = 4 };
+
+ void fillRectangleList (const RectangleList& list)
+ {
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ GLfloat vertices [8];
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+
+ for (RectangleList::Iterator i (list); i.next();)
+ {
+ vertices[0] = vertices[4] = (GLfloat) i.getRectangle()->getX();
+ vertices[1] = vertices[3] = (GLfloat) i.getRectangle()->getY();
+ vertices[2] = vertices[6] = (GLfloat) i.getRectangle()->getRight();
+ vertices[5] = vertices[7] = (GLfloat) i.getRectangle()->getBottom();
+
+ glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+ }
+ }
+
+ inline void setColour (const float alpha) noexcept
+ {
+ glColor4f (alpha, alpha, alpha, alpha);
+ }
+
+ void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords, const int numVertices) noexcept
+ {
+ glEnable (GL_TEXTURE_2D);
+ glDisableClientState (GL_COLOR_ARRAY);
+ glDisableClientState (GL_NORMAL_ARRAY);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
+ glDrawArrays (GL_TRIANGLE_STRIP, 0, numVertices);
+ }
+
+ void drawTriangleStrip (const GLfloat* const vertices, const GLfloat* const textureCoords,
+ const int numVertices, const GLuint textureID) noexcept
+ {
+ jassert (textureID != 0);
+ glBindTexture (GL_TEXTURE_2D, textureID);
+ drawTriangleStrip (vertices, textureCoords, numVertices);
+ glBindTexture (GL_TEXTURE_2D, 0);
+ }
+
+ void drawTextureQuad (GLuint textureID, int x, int y, int w, int h)
+ {
+ const GLfloat l = (GLfloat) x;
+ const GLfloat t = (GLfloat) y;
+ const GLfloat r = (GLfloat) (x + w);
+ const GLfloat b = (GLfloat) (y + h);
+
+ const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
+ const GLfloat textureCoords[] = { 0, 1.0f, 1.0f, 1.0f, 0, 0, 1.0f, 0 };
+
+ drawTriangleStrip (vertices, textureCoords, 4, textureID);
+ }
+
+ void fillRectWithTexture (const Rectangle& rect, GLuint textureID, const float alpha)
+ {
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glColor4f (1.0f, 1.0f, 1.0f, alpha);
+
+ drawTextureQuad (textureID, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ void clipFrameBuffers (const OpenGLTarget& dest, OpenGLFrameBuffer& source,
+ const Point sourceOrigin, const bool shouldMaskRGB)
+ {
+ dest.makeActiveFor2D();
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
+ setColour (1.0f);
+
+ if (shouldMaskRGB)
+ glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+
+ drawTextureQuad (source.getTextureID(), sourceOrigin.getX(), sourceOrigin.getY(),
+ source.getWidth(), source.getHeight());
+
+ if (shouldMaskRGB)
+ glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ void renderPath (const Path& path, const AffineTransform& transform, int oversamplingLevel)
+ {
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ glDisable (GL_TEXTURE_2D);
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_ONE, GL_ONE);
+
+ TriangulatedPath (path, transform).draw (oversamplingLevel);
+ }
+
+ void setNormalBlendingMode() noexcept
+ {
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ void setBlendMode (const bool replaceExistingContents) noexcept
+ {
+ if (replaceExistingContents)
+ glDisable (GL_BLEND);
+ else
+ setNormalBlendingMode();
+ }
+
+ void fillRectWithTiledTexture (const OpenGLTarget& target, int textureWidth, int textureHeight,
+ const Rectangle& clip, const AffineTransform& transform, float alpha)
+ {
+ glEnable (GL_TEXTURE_2D);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState (GL_COLOR_ARRAY);
+ glDisableClientState (GL_NORMAL_ARRAY);
+ glColor4f (1.0f, 1.0f, 1.0f, alpha);
+
+ static bool canDoNonPowerOfTwos = OpenGLHelpers::isExtensionSupported ("GL_ARB_texture_non_power_of_two");
+
+ if (canDoNonPowerOfTwos || (isPowerOfTwo (textureWidth) && isPowerOfTwo (textureHeight)))
+ {
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ const GLfloat clipX = (GLfloat) clip.getX();
+ const GLfloat clipY = (GLfloat) clip.getY();
+ const GLfloat clipR = (GLfloat) clip.getRight();
+ const GLfloat clipB = (GLfloat) clip.getBottom();
+
+ const GLfloat vertices[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
+ GLfloat textureCoords[] = { clipX, clipY, clipR, clipY, clipX, clipB, clipR, clipB };
+
+ {
+ const AffineTransform t (transform.inverted().scaled (1.0f / textureWidth,
+ 1.0f / textureHeight));
+ t.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
+ t.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
+ }
+
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
+
+ glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+ }
+ else
+ {
+ // For hardware that can't handle non-power-of-two textures, this is a fallback algorithm
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ target.scissor (clip);
+ glPushMatrix();
+ OpenGLHelpers::applyTransform (transform);
+
+ GLfloat vertices[8];
+ const GLfloat textureCoords[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
+
+ const Rectangle targetArea (clip.transformed (transform.inverted()));
+ int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), textureWidth);
+ int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), textureHeight);
+ const int right = targetArea.getRight();
+ const int bottom = targetArea.getBottom();
+
+ while (y < bottom)
+ {
+ vertices[1] = vertices[3] = (GLfloat) y;
+ vertices[5] = vertices[7] = (GLfloat) (y + textureHeight);
+
+ for (int x1 = x; x1 < right; x1 += textureWidth)
+ {
+ vertices[0] = vertices[4] = (GLfloat) x1;
+ vertices[2] = vertices[6] = (GLfloat) (x1 + textureWidth);
+ glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+ }
+
+ y += textureHeight;
+ }
+
+ glPopMatrix();
+ glDisable (GL_SCISSOR_TEST);
+ }
+ }
+
+ void fillWithLinearGradient (const Rectangle& rect,
+ const ColourGradient& grad,
+ const AffineTransform& transform,
+ const int textureSize)
+ {
+ const Point p1 (grad.point1.transformedBy (transform));
+ const Point p2 (grad.point2.transformedBy (transform));
+ const Point p3 (Point (grad.point1.getX() - (grad.point2.getY() - grad.point1.getY()) / textureSize,
+ grad.point1.getY() + (grad.point2.getX() - grad.point1.getX()) / textureSize).transformedBy (transform));
+
+ const AffineTransform textureTransform (AffineTransform::fromTargetPoints (p1.getX(), p1.getY(), 0.0f, 0.0f,
+ p2.getX(), p2.getY(), 1.0f, 0.0f,
+ p3.getX(), p3.getY(), 0.0f, 1.0f));
+
+ const GLfloat l = (GLfloat) rect.getX();
+ const GLfloat r = (GLfloat) rect.getRight();
+ const GLfloat t = (GLfloat) rect.getY();
+ const GLfloat b = (GLfloat) rect.getBottom();
+
+ const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
+ GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
+
+ textureTransform.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
+ textureTransform.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
+
+ drawTriangleStrip (vertices, textureCoords, 4);
+ }
+
+ void fillWithRadialGradient (const OpenGLTarget& target, const Rectangle& rect,
+ const ColourGradient& grad, const AffineTransform& transform)
+ {
+ const Point centre (grad.point1.transformedBy (transform));
+
+ const float screenRadius = centre.getDistanceFrom (rect.getCentre().toFloat())
+ + Point (rect.getWidth() / 2,
+ rect.getHeight() / 2).getDistanceFromOrigin()
+ + 8.0f;
+
+ const AffineTransform inverse (transform.inverted());
+ const float sourceRadius = jmax (Point (screenRadius, 0.0f).transformedBy (inverse).getDistanceFromOrigin(),
+ Point (0.0f, screenRadius).transformedBy (inverse).getDistanceFromOrigin());
+
+ const int numDivisions = 90;
+ GLfloat vertices [4 + numDivisions * 2];
+ GLfloat textureCoords [4 + numDivisions * 2];
+
+ {
+ GLfloat* t = textureCoords;
+ *t++ = 0.0f;
+ *t++ = 0.0f;
+
+ const GLfloat texturePos = sourceRadius / grad.point1.getDistanceFrom (grad.point2);
+
+ for (int i = numDivisions + 1; --i >= 0;)
+ {
+ *t++ = texturePos;
+ *t++ = 0.0f;
+ }
+ }
+
+ {
+ GLfloat* v = vertices;
+ *v++ = centre.getX();
+ *v++ = centre.getY();
+
+ const Point first (grad.point1.translated (0, -sourceRadius)
+ .transformedBy (transform));
+ *v++ = first.getX();
+ *v++ = first.getY();
+
+ for (int i = 1; i < numDivisions; ++i)
+ {
+ const float angle = i * (float_Pi * 2.0f / numDivisions);
+ const Point p (grad.point1.translated (std::sin (angle) * sourceRadius,
+ std::cos (angle) * -sourceRadius)
+ .transformedBy (transform));
+ *v++ = p.getX();
+ *v++ = p.getY();
+ }
+
+ *v++ = first.getX();
+ *v++ = first.getY();
+ }
+
+ target.scissor (rect);
+ glEnable (GL_TEXTURE_2D);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState (GL_COLOR_ARRAY);
+ glDisableClientState (GL_NORMAL_ARRAY);
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer (2, GL_FLOAT, 0, textureCoords);
+ setColour (1.0f);
+ glDrawArrays (GL_TRIANGLE_FAN, 0, numDivisions + 2);
+ glDisable (GL_SCISSOR_TEST);
+ }
+
+ void fillRectWithColourGradient (const OpenGLTarget& target, const Rectangle& rect,
+ const ColourGradient& gradient, const AffineTransform& transform)
+ {
+ if (gradient.point1 == gradient.point2)
+ {
+ OpenGLHelpers::fillRectWithColour (rect, gradient.getColourAtPosition (1.0));
+ }
+ else
+ {
+ const int textureSize = 256;
+ OpenGLTexture texture;
+
+ HeapBlock lookup (textureSize);
+ gradient.createLookupTable (lookup, textureSize);
+ texture.load (lookup, textureSize, 1);
+ texture.bind();
+
+ if (gradient.isRadial)
+ fillWithRadialGradient (target, rect, gradient, transform);
+ else
+ fillWithLinearGradient (rect, gradient, transform, textureSize);
+ }
+ }
+
+ void fillRectWithFillType (const OpenGLTarget& target, const Rectangle& rect,
+ const FillType& fill, const bool replaceExistingContents)
+ {
+ jassert (! fill.isInvisible());
+ jassert (! fill.isColour());
+
+ if (fill.isGradient())
+ {
+ target.makeActiveFor2D();
+ setBlendMode (replaceExistingContents);
+
+ ColourGradient g2 (*(fill.gradient));
+ g2.multiplyOpacity (fill.getOpacity());
+
+ fillRectWithColourGradient (target, rect, g2, fill.transform);
+ }
+ else if (fill.isTiledImage())
+ {
+ OpenGLTextureFromImage t (fill.image);
+
+ target.makeActiveFor2D();
+ setBlendMode (replaceExistingContents);
+
+ glBindTexture (GL_TEXTURE_2D, t.textureID);
+ fillRectWithTiledTexture (target, t.width, t.height, rect,
+ fill.transform, fill.colour.getFloatAlpha());
+ glBindTexture (GL_TEXTURE_2D, 0);
+ }
+ }
+}
+
+class ClipRegion_Mask;
+
+//==============================================================================
+class ClipRegionBase : public SingleThreadedReferenceCountedObject
+{
+public:
+ ClipRegionBase() noexcept {}
+ virtual ~ClipRegionBase() {}
+
+ typedef ReferenceCountedObjectPtr Ptr;
+
+ virtual Ptr clone() const = 0;
+ virtual Ptr applyClipTo (const Ptr& target) = 0;
+ virtual Ptr clipToRectangle (const Rectangle&) = 0;
+ virtual Ptr clipToRectangleList (const RectangleList&) = 0;
+ virtual Ptr excludeClipRectangle (const Rectangle&) = 0;
+ virtual Ptr clipToPath (const Path& p, const AffineTransform&) = 0;
+ virtual Ptr clipToEdgeTable (const EdgeTable&) = 0;
+ virtual Ptr clipToImageAlpha (const OpenGLTextureFromImage&, const AffineTransform&) = 0;
+ virtual Ptr clipToMask (ClipRegion_Mask*) = 0;
+ virtual void translate (const Point& delta) = 0;
+ virtual const Rectangle& getClipBounds() const = 0;
+ virtual void fillAll (const OpenGLTarget&, const FillType& fill, bool replaceContents) = 0;
+ virtual void fillRect (const OpenGLTarget&, const Rectangle& area, const FillType& fill, bool replaceContents) = 0;
+ virtual void drawImage (const OpenGLTarget&, const OpenGLTextureFromImage&, float alpha, const Rectangle& targetArea) = 0;
+};
+
+//==============================================================================
+class ClipRegion_Mask : public ClipRegionBase
+{
+public:
+ ClipRegion_Mask (const ClipRegion_Mask& other)
+ : clip (other.clip),
+ maskOrigin (other.maskOrigin)
+ {
+ const bool ok = mask.initialise (other.mask);
+ (void) ok; jassert (ok);
+ }
+
+ explicit ClipRegion_Mask (const Rectangle& r)
+ : clip (r),
+ maskOrigin (r.getPosition())
+ {
+ const bool ok = mask.initialise (r.getWidth(), r.getHeight());
+ (void) ok; jassert (ok);
+ mask.clear (Colours::white);
+ }
+
+ explicit ClipRegion_Mask (const Rectangle& r)
+ : clip (r.getSmallestIntegerContainer()),
+ maskOrigin (clip.getPosition())
+ {
+ initialiseClear();
+
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ RenderingHelpers::FloatRectangleRasterisingInfo fr (r);
+ FillFloatRectCallback callback;
+ fr.iterate (callback);
+ }
+
+ explicit ClipRegion_Mask (const EdgeTable& e)
+ : clip (e.getMaximumBounds()),
+ maskOrigin (clip.getPosition())
+ {
+ initialiseClear();
+ OpenGLHelpers::fillEdgeTable (e, 0, 0, 0);
+ }
+
+ ClipRegion_Mask (const Rectangle& bounds, const Path& p, const AffineTransform& transform, int oversamplingLevel)
+ : clip (bounds), maskOrigin (clip.getPosition())
+ {
+ initialiseClear();
+ renderPath (p, transform, oversamplingLevel);
+ }
+
+ static ClipRegion_Mask* createFromPath (Rectangle bounds, const Path& p, const AffineTransform& transform)
+ {
+ bounds = bounds.getIntersection (p.getBoundsTransformed (transform).getSmallestIntegerContainer());
+
+ return bounds.isEmpty() ? nullptr
+ : new ClipRegion_Mask (bounds, p, transform, (int) defaultOversamplingLevel);
+ }
+
+ Ptr clone() const { return new ClipRegion_Mask (*this); }
+ const Rectangle& getClipBounds() const { return clip; }
+ Ptr applyClipTo (const Ptr& target) { return target->clipToMask (this); }
+
+ void translate (const Point& delta)
+ {
+ maskOrigin += delta;
+ clip += delta;
+ }
+
+ Ptr clipToRectangle (const Rectangle& r)
+ {
+ clip = clip.getIntersection (r);
+ return clip.isEmpty() ? nullptr : this;
+ }
+
+ Ptr clipToRectangleList (const RectangleList& r)
+ {
+ clip = clip.getIntersection (r.getBounds());
+ if (clip.isEmpty())
+ return nullptr;
+
+ RectangleList excluded (clip);
+
+ if (excluded.subtract (r))
+ {
+ if (excluded.getNumRectangles() == 1)
+ return excludeClipRectangle (excluded.getRectangle (0));
+
+ makeMaskActive();
+ glDisable (GL_BLEND);
+ setColour (0);
+ fillRectangleList (excluded);
+ }
+
+ return this;
+ }
+
+ Ptr excludeClipRectangle (const Rectangle& r)
+ {
+ if (r.contains (clip))
+ return nullptr;
+
+ makeMaskActive();
+ glDisable (GL_BLEND);
+ setColour (0);
+ OpenGLHelpers::fillRect (r);
+ return this;
+ }
+
+ Ptr clipToPath (const Path& p, const AffineTransform& t)
+ {
+ ClipRegion_Mask* tempMask = createFromPath (clip, p, t);
+ const Ptr tempMaskPtr (tempMask);
+ return tempMask == nullptr ? nullptr : clipToMask (tempMask);
+ }
+
+ Ptr clipToEdgeTable (const EdgeTable& et)
+ {
+ ClipRegion_Mask* const tempMask = new ClipRegion_Mask (et);
+ const Ptr tempMaskPtr (tempMask);
+ return clipToMask (tempMask);
+ }
+
+ Ptr clipToMask (ClipRegion_Mask* m)
+ {
+ jassert (m != nullptr && m != this);
+ clip = clip.getIntersection (m->clip);
+
+ if (clip.isEmpty())
+ return nullptr;
+
+ clipFrameBuffers (OpenGLTarget (mask, maskOrigin), m->mask, m->maskOrigin, true);
+ return this;
+ }
+
+ Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform)
+ {
+ makeMaskActive();
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_ZERO, GL_SRC_ALPHA);
+ glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+ fillMaskWithSourceImage (image, transform);
+ glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ return this;
+ }
+
+ void fillAll (const OpenGLTarget& target, const FillType& fill, bool replaceContents)
+ {
+ jassert (! replaceContents);
+ fillRectInternal (target, clip, fill, false);
+ }
+
+ void fillRect (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, bool replaceContents)
+ {
+ jassert (! replaceContents);
+ const Rectangle r (clip.getIntersection (area));
+
+ if (! r.isEmpty())
+ fillRectInternal (target, r, fill, false);
+ }
+
+ void fillRectInternal (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, bool replaceContents)
+ {
+ if (fill.isColour())
+ {
+ target.makeActiveFor2D();
+
+ setBlendMode (replaceContents);
+ OpenGLHelpers::setColour (fill.colour);
+ target.scissor (area);
+ drawFrameBuffer (mask, maskOrigin);
+ glDisable (GL_SCISSOR_TEST);
+ }
+ else
+ {
+ OpenGLFrameBuffer patternBuffer;
+ bool ok = patternBuffer.initialise (area.getWidth(), area.getHeight());
+ (void) ok; jassert (ok);
+
+ fillRectWithFillType (OpenGLTarget (patternBuffer, area.getPosition()), area, fill, true);
+ clipAndDraw (target, OpenGLTarget (patternBuffer, area.getPosition()));
+ }
+ }
+
+ void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, float alpha, const Rectangle& targetArea)
+ {
+ const Rectangle bufferArea (targetArea.getIntersection (clip));
+
+ if (! bufferArea.isEmpty())
+ {
+ OpenGLFrameBuffer buffer;
+ bool ok = buffer.initialise (bufferArea.getWidth(), bufferArea.getHeight());
+ (void) ok; jassert (ok);
+
+ OpenGLTarget bufferTarget (buffer, bufferArea.getPosition());
+ bufferTarget.makeActiveFor2D();
+ glDisable (GL_BLEND);
+ fillRectWithTexture (targetArea, source.textureID, alpha);
+
+ clipAndDraw (target, bufferTarget);
+ }
+ }
+
+ void drawImageSelfDestructively (const OpenGLTarget& target, const OpenGLTextureFromImage& source,
+ float alpha, const AffineTransform& transform)
+ {
+ makeMaskActive();
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_DST_ALPHA, GL_ZERO);
+ fillMaskWithSourceImage (source, transform);
+
+ target.makeActiveFor2D();
+ setColour (alpha);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ drawFrameBuffer (mask, maskOrigin);
+ }
+
+private:
+ OpenGLFrameBuffer mask;
+ Rectangle clip;
+ Point maskOrigin;
+
+ void prepareFor2D() const
+ {
+ applyFlippedMatrix (maskOrigin.getX(), maskOrigin.getY(), mask.getWidth(), mask.getHeight());
+ }
+
+ void makeMaskActive()
+ {
+ const bool b = mask.makeCurrentRenderingTarget();
+ (void) b; jassert (b);
+ prepareFor2D();
+ }
+
+ void initialiseClear()
+ {
+ jassert (! clip.isEmpty());
+ bool ok = mask.initialise (clip.getWidth(), clip.getHeight());
+ mask.makeCurrentAndClear();
+ (void) ok; jassert (ok);
+ glDisable (GL_TEXTURE_2D);
+ glDisable (GL_BLEND);
+ prepareFor2D();
+ }
+
+ struct FillFloatRectCallback
+ {
+ void operator() (const int x, const int y, const int w, const int h, const int alpha) const
+ {
+ const GLfloat l = (GLfloat) x;
+ const GLfloat t = (GLfloat) y;
+ const GLfloat r = (GLfloat) (x + w);
+ const GLfloat b = (GLfloat) (y + h);
+
+ const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
+ glColor4f (1.0f, 1.0f, 1.0f, alpha / 255.0f);
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+ }
+ };
+
+ void clipAndDraw (const OpenGLTarget& target, const OpenGLTarget& buffer)
+ {
+ clipFrameBuffers (buffer, mask, maskOrigin, false);
+
+ target.makeActiveFor2D();
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ setColour (1.0f);
+
+ drawFrameBuffer (*buffer.frameBuffer, Point (buffer.x, buffer.y));
+ }
+
+ void drawFrameBuffer (const OpenGLFrameBuffer& buffer, const Point& topLeft)
+ {
+ drawTextureQuad (buffer.getTextureID(), topLeft.getX(), topLeft.getY(),
+ buffer.getWidth(), buffer.getHeight());
+ }
+
+ void fillMaskWithSourceImage (const OpenGLTextureFromImage& image, const AffineTransform& transform) const
+ {
+ setColour (1.0f);
+ glBindTexture (GL_TEXTURE_2D, image.textureID);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ const GLfloat l = (GLfloat) maskOrigin.getX();
+ const GLfloat t = (GLfloat) maskOrigin.getY();
+ const GLfloat r = (GLfloat) (maskOrigin.getX() + mask.getWidth());
+ const GLfloat b = (GLfloat) (maskOrigin.getY() + mask.getHeight());
+ const GLfloat vertices[] = { l, t, r, t, l, b, r, b };
+ GLfloat textureCoords[] = { l, t, r, t, l, b, r, b };
+
+ const AffineTransform inv (transform.inverted().scaled (1.0f / image.width,
+ 1.0f / image.height));
+
+ inv.transformPoints (textureCoords[0], textureCoords[1], textureCoords[2], textureCoords[3]);
+ inv.transformPoints (textureCoords[4], textureCoords[5], textureCoords[6], textureCoords[7]);
+
+ drawTriangleStrip (vertices, textureCoords, 4);
+ }
+
+ ClipRegion_Mask& operator= (const ClipRegion_Mask&);
+};
+
+
+//==============================================================================
+class ClipRegion_Rectangle : public ClipRegionBase
+{
+public:
+ explicit ClipRegion_Rectangle (const Rectangle& r) noexcept
+ : clip (r)
+ {}
+
+ Ptr clone() const { return new ClipRegion_Rectangle (clip); }
+ const Rectangle& getClipBounds() const { return clip; }
+ Ptr applyClipTo (const Ptr& target) { return target->clipToRectangle (clip); }
+ void translate (const Point& delta) { clip += delta; }
+
+ Ptr clipToRectangle (const Rectangle& r)
+ {
+ clip = clip.getIntersection (r);
+ return clip.isEmpty() ? nullptr : this;
+ }
+
+ Ptr clipToRectangleList (const RectangleList& r)
+ {
+ if (r.getNumRectangles() <= 1)
+ return clipToRectangle (r.getRectangle (0));
+
+ if (r.containsRectangle (clip))
+ return this;
+
+ return toMask()->clipToRectangleList (r);
+ }
+
+ Ptr excludeClipRectangle (const Rectangle& r)
+ {
+ return r.contains (clip) ? nullptr
+ : toMask()->excludeClipRectangle (r);
+ }
+
+ Ptr clipToMask (ClipRegion_Mask* m) { return m->clipToRectangle (clip); }
+ Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); }
+ Ptr clipToEdgeTable (const EdgeTable& et) { return toMask()->clipToEdgeTable (et); }
+ Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); }
+
+ void fillAll (const OpenGLTarget& target, const FillType& fill, bool replaceContents)
+ {
+ fillRectInternal (target, clip, fill, replaceContents);
+ }
+
+ void fillRect (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, bool replaceContents)
+ {
+ const Rectangle r (clip.getIntersection (area));
+
+ if (! r.isEmpty())
+ fillRectInternal (target, r, fill, replaceContents);
+ }
+
+ void drawImage (const OpenGLTarget& target, const OpenGLTextureFromImage& source, float alpha, const Rectangle& targetArea)
+ {
+ target.makeActiveFor2D();
+ target.scissor (clip);
+ setNormalBlendingMode();
+ fillRectWithTexture (targetArea, source.textureID, alpha);
+ glDisable (GL_SCISSOR_TEST);
+ }
+
+private:
+ Rectangle clip;
+
+ void fillRectInternal (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, bool replaceContents)
+ {
+ if (fill.isColour())
+ {
+ target.makeActiveFor2D();
+ setBlendMode (replaceContents);
+ glDisable (GL_TEXTURE_2D);
+ OpenGLHelpers::fillRectWithColour (area, fill.colour);
+ }
+ else
+ {
+ fillRectWithFillType (target, area, fill, replaceContents);
+ }
+ }
+
+ Ptr toMask() const
+ {
+ return new ClipRegion_Mask (clip);
+ }
+
+ ClipRegion_Rectangle& operator= (const ClipRegion_Rectangle&);
+};
+
+
+//==============================================================================
+class OpenGLRenderer::SavedState
+{
+public:
+ SavedState (const OpenGLTarget& target_)
+ : clip (new ClipRegion_Rectangle (Rectangle (target_.width, target_.height))),
+ transform (0, 0), interpolationQuality (Graphics::mediumResamplingQuality),
+ target (target_), transparencyLayerAlpha (1.0f)
+ {
+ }
+
+ SavedState (const SavedState& other)
+ : clip (other.clip), transform (other.transform), font (other.font),
+ fillType (other.fillType), interpolationQuality (other.interpolationQuality),
+ target (other.target), transparencyLayerAlpha (other.transparencyLayerAlpha),
+ transparencyLayer (other.transparencyLayer)
+ {
+ }
+
+ bool clipToRectangle (const Rectangle& r)
+ {
+ if (clip != nullptr)
+ {
+ if (transform.isOnlyTranslated)
+ {
+ cloneClipIfMultiplyReferenced();
+ clip = clip->clipToRectangle (transform.translated (r));
+ }
+ else
+ {
+ Path p;
+ p.addRectangle (r);
+ clipToPath (p, AffineTransform::identity);
+ }
+ }
+
+ return clip != nullptr;
+ }
+
+ bool clipToRectangleList (const RectangleList& r)
+ {
+ if (clip != nullptr)
+ {
+ if (transform.isOnlyTranslated)
+ {
+ cloneClipIfMultiplyReferenced();
+ RectangleList offsetList (r);
+ offsetList.offsetAll (transform.xOffset, transform.yOffset);
+ clip = clip->clipToRectangleList (offsetList);
+ }
+ else
+ {
+ clipToPath (r.toPath(), AffineTransform::identity);
+ }
+ }
+
+ return clip != nullptr;
+ }
+
+ bool excludeClipRectangle (const Rectangle& r)
+ {
+ if (clip != nullptr)
+ {
+ cloneClipIfMultiplyReferenced();
+
+ if (transform.isOnlyTranslated)
+ {
+ clip = clip->excludeClipRectangle (transform.translated (r));
+ }
+ else
+ {
+ Path p;
+ p.addRectangle (r.toFloat());
+ p.applyTransform (transform.complexTransform);
+ p.addRectangle (clip->getClipBounds().toFloat());
+ p.setUsingNonZeroWinding (false);
+ clip = clip->clipToPath (p, AffineTransform::identity);
+ }
+ }
+
+ return clip != nullptr;
+ }
+
+ void clipToPath (const Path& p, const AffineTransform& t)
+ {
+ if (clip != nullptr)
+ {
+ cloneClipIfMultiplyReferenced();
+ clip = clip->clipToPath (p, transform.getTransformWith (t));
+ }
+ }
+
+ void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
+ {
+ if (clip != nullptr)
+ {
+ Path p;
+ p.addRectangle (sourceImage.getBounds());
+ clipToPath (p, t);
+
+ if (sourceImage.hasAlphaChannel() && clip != nullptr)
+ {
+ cloneClipIfMultiplyReferenced();
+ clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t));
+ }
+ }
+ }
+
+ bool clipRegionIntersects (const Rectangle& r) const
+ {
+ return clip != nullptr
+ && (transform.isOnlyTranslated ? clip->getClipBounds().intersects (transform.translated (r))
+ : getClipBounds().intersects (r));
+ }
+
+ Rectangle getClipBounds() const
+ {
+ return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
+ : Rectangle();
+ }
+
+ SavedState* beginTransparencyLayer (float opacity)
+ {
+ SavedState* s = new SavedState (*this);
+
+ if (clip != nullptr)
+ {
+ const Rectangle& clipBounds = clip->getClipBounds();
+
+ OpenGLFrameBufferImage* fbi = new OpenGLFrameBufferImage (clipBounds.getWidth(), clipBounds.getHeight());
+ fbi->frameBuffer.clear (Colours::transparentBlack);
+ s->transparencyLayer = Image (fbi);
+ s->target = OpenGLTarget (fbi->frameBuffer, Point());
+ s->transparencyLayerAlpha = opacity;
+ s->transform.moveOriginInDeviceSpace (-clipBounds.getX(), -clipBounds.getY());
+ s->cloneClipIfMultiplyReferenced();
+ s->clip->translate (-clipBounds.getPosition());
+ }
+
+ return s;
+ }
+
+ void endTransparencyLayer (SavedState& finishedLayerState)
+ {
+ if (clip != nullptr)
+ clip->drawImage (target, finishedLayerState.transparencyLayer,
+ finishedLayerState.transparencyLayerAlpha, clip->getClipBounds());
+ }
+
+ //==============================================================================
+ void fillRect (const Rectangle& r, const bool replaceContents)
+ {
+ if (clip != nullptr)
+ {
+ if (transform.isOnlyTranslated)
+ {
+ clip->fillRect (target, r.translated (transform.xOffset, transform.yOffset),
+ getFillType(), replaceContents);
+ }
+ else
+ {
+ Path p;
+ p.addRectangle (r);
+ fillPath (p, AffineTransform::identity);
+ }
+ }
+ }
+
+ void fillRect (const Rectangle& r)
+ {
+ if (clip != nullptr)
+ {
+ if (transform.isOnlyTranslated)
+ {
+ fillShape (new ClipRegion_Mask (r.translated ((float) transform.xOffset,
+ (float) transform.yOffset)), false);
+ }
+ else
+ {
+ Path p;
+ p.addRectangle (r);
+ fillPath (p, AffineTransform::identity);
+ }
+ }
+ }
+
+ void fillPath (const Path& path, const AffineTransform& t)
+ {
+ if (clip != nullptr)
+ {
+ ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->getClipBounds(), path,
+ transform.getTransformWith (t));
+
+ if (m != nullptr)
+ fillShape (m, false);
+ }
+ }
+
+ void drawGlyph (int glyphNumber, const AffineTransform& t)
+ {
+ if (clip != nullptr)
+ {
+ const float fontHeight = font.getHeight();
+
+ const ScopedPointer et (font.getTypeface()->getEdgeTableForGlyph
+ (glyphNumber, transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
+ .followedBy (t))));
+
+ if (et != nullptr)
+ fillShape (new ClipRegion_Mask (*et), false);
+ }
+ }
+
+ void drawLine (const Line & line)
+ {
+ Path p;
+ p.addLineSegment (line, 1.0f);
+ fillPath (p, AffineTransform::identity);
+ }
+
+ void fillShape (ClipRegionBase::Ptr shapeToFill, const bool replaceContents)
+ {
+ jassert (clip != nullptr && shapeToFill != nullptr);
+
+ if (! fillType.isInvisible())
+ {
+ shapeToFill = clip->applyClipTo (shapeToFill);
+
+ if (shapeToFill != nullptr)
+ shapeToFill->fillAll (target, getFillType(), replaceContents);
+ }
+ }
+
+ //==============================================================================
+ void drawImage (const Image& image, const AffineTransform& trans)
+ {
+ if (clip == nullptr || fillType.colour.isTransparent())
+ return;
+
+ const AffineTransform t (transform.getTransformWith (trans));
+ const float alpha = fillType.colour.getFloatAlpha();
+
+ if (t.isOnlyTranslation())
+ {
+ int tx = (int) (t.getTranslationX() * 256.0f);
+ int ty = (int) (t.getTranslationY() * 256.0f);
+
+ if (((tx | ty) & 0xf8) == 0)
+ {
+ tx = ((tx + 128) >> 8);
+ ty = ((ty + 128) >> 8);
+
+ clip->drawImage (target, image, alpha, Rectangle (tx, ty, image.getWidth(), image.getHeight()));
+ return;
+ }
+ }
+
+ if (t.isSingularity())
+ return;
+
+ Path p;
+ p.addRectangle (image.getBounds());
+ ClipRegion_Mask* m = ClipRegion_Mask::createFromPath (clip->getClipBounds(), p, t);
+
+ if (m != nullptr)
+ {
+ ClipRegionBase::Ptr c (clip->applyClipTo (m));
+
+ if (c != nullptr)
+ {
+ m = dynamic_cast (c.getObject());
+
+ jassert (m != nullptr);
+ m->drawImageSelfDestructively (target, image, alpha, t);
+ }
+ }
+ }
+
+ //==============================================================================
+ ClipRegionBase::Ptr clip;
+ RenderingHelpers::TranslationOrTransform transform;
+ Font font;
+ FillType fillType;
+ Graphics::ResamplingQuality interpolationQuality;
+
+private:
+ OpenGLTarget target;
+ float transparencyLayerAlpha;
+ Image transparencyLayer;
+
+ void cloneClipIfMultiplyReferenced()
+ {
+ if (clip->getReferenceCount() > 1)
+ clip = clip->clone();
+ }
+
+ FillType getFillType() const
+ {
+ return fillType.transformed (transform.getTransform());
+ }
+
+ SavedState& operator= (const SavedState&);
+};
+
+
+//==============================================================================
+OpenGLRenderer::OpenGLRenderer (OpenGLComponent& target)
+ : stack (new SavedState (OpenGLTarget (target.getFrameBufferID(), target.getWidth(), target.getHeight())))
+{
+ target.makeCurrentRenderingTarget();
+}
+
+OpenGLRenderer::OpenGLRenderer (OpenGLFrameBuffer& target)
+ : stack (new SavedState (OpenGLTarget (target, Point())))
+{
+ // This object can only be created and used when the current thread has an active OpenGL context.
+ jassert (OpenGLHelpers::isContextActive());
+}
+
+OpenGLRenderer::~OpenGLRenderer() {}
+
+bool OpenGLRenderer::isVectorDevice() const { return false; }
+void OpenGLRenderer::setOrigin (int x, int y) { stack->transform.setOrigin (x, y); }
+void OpenGLRenderer::addTransform (const AffineTransform& t) { stack->transform.addTransform (t); }
+float OpenGLRenderer::getScaleFactor() { return stack->transform.getScaleFactor(); }
+Rectangle OpenGLRenderer::getClipBounds() const { return stack->getClipBounds(); }
+bool OpenGLRenderer::isClipEmpty() const { return stack->clip == nullptr; }
+bool OpenGLRenderer::clipRegionIntersects (const Rectangle& r) { return stack->clipRegionIntersects (r); }
+bool OpenGLRenderer::clipToRectangle (const Rectangle& r) { return stack->clipToRectangle (r); }
+bool OpenGLRenderer::clipToRectangleList (const RectangleList& r) { return stack->clipToRectangleList (r); }
+void OpenGLRenderer::excludeClipRectangle (const Rectangle& r) { stack->excludeClipRectangle (r); }
+void OpenGLRenderer::clipToPath (const Path& path, const AffineTransform& t) { stack->clipToPath (path, t); }
+void OpenGLRenderer::clipToImageAlpha (const Image& im, const AffineTransform& t) { stack->clipToImageAlpha (im, t); }
+void OpenGLRenderer::saveState() { stack.save(); }
+void OpenGLRenderer::restoreState() { stack.restore(); }
+void OpenGLRenderer::beginTransparencyLayer (float opacity) { stack.beginTransparencyLayer (opacity); }
+void OpenGLRenderer::endTransparencyLayer() { stack.endTransparencyLayer(); }
+void OpenGLRenderer::setFill (const FillType& fillType) { stack->fillType = fillType; }
+void OpenGLRenderer::setOpacity (float newOpacity) { stack->fillType.setOpacity (newOpacity); }
+void OpenGLRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) { stack->interpolationQuality = quality; }
+void OpenGLRenderer::fillRect (const Rectangle& r, bool replace) { stack->fillRect (r, replace); }
+void OpenGLRenderer::fillPath (const Path& path, const AffineTransform& t) { stack->fillPath (path, t); }
+void OpenGLRenderer::drawImage (const Image& im, const AffineTransform& t) { stack->drawImage (im, t); }
+void OpenGLRenderer::drawVerticalLine (int x, float top, float bottom) { stack->fillRect (Rectangle ((float) x, top, 1.0f, bottom - top)); }
+void OpenGLRenderer::drawHorizontalLine (int y, float left, float right) { stack->fillRect (Rectangle (left, (float) y, right - left, 1.0f)); }
+void OpenGLRenderer::drawGlyph (int glyphNumber, const AffineTransform& t) { stack->drawGlyph (glyphNumber, t); }
+void OpenGLRenderer::drawLine (const Line & line) { stack->drawLine (line); }
+void OpenGLRenderer::setFont (const Font& newFont) { stack->font = newFont; }
+Font OpenGLRenderer::getFont() { return stack->font; }
+
+END_JUCE_NAMESPACE
diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
new file mode 100644
index 0000000000..d7d796e620
--- /dev/null
+++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h
@@ -0,0 +1,83 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-11 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.
+
+ ==============================================================================
+*/
+
+#ifndef __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__
+#define __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__
+
+
+//==============================================================================
+/** A LowLevelGraphicsContext for rendering into an OpenGL framebuffer or window.
+*/
+class JUCE_API OpenGLRenderer : public LowLevelGraphicsContext
+{
+public:
+ explicit OpenGLRenderer (OpenGLComponent& target);
+ explicit OpenGLRenderer (OpenGLFrameBuffer& target);
+ ~OpenGLRenderer();
+
+ bool isVectorDevice() const;
+ void setOrigin (int x, int y);
+ void addTransform (const AffineTransform&);
+ float getScaleFactor();
+ bool clipToRectangle (const Rectangle&);
+ bool clipToRectangleList (const RectangleList&);
+ void excludeClipRectangle (const Rectangle&);
+ void clipToPath (const Path& path, const AffineTransform&);
+ void clipToImageAlpha (const Image& sourceImage, const AffineTransform&);
+ bool clipRegionIntersects (const Rectangle&);
+ Rectangle getClipBounds() const;
+ bool isClipEmpty() const;
+
+ void saveState();
+ void restoreState();
+
+ void beginTransparencyLayer (float opacity);
+ void endTransparencyLayer();
+
+ void setFill (const FillType& fillType);
+ void setOpacity (float newOpacity);
+ void setInterpolationQuality (Graphics::ResamplingQuality);
+
+ void fillRect (const Rectangle& r, bool replaceExistingContents);
+ void fillPath (const Path& path, const AffineTransform& transform);
+ void drawImage (const Image& sourceImage, const AffineTransform& transform);
+ void drawLine (const Line & line);
+ void drawVerticalLine (int x, float top, float bottom);
+ void drawHorizontalLine (int y, float left, float right);
+
+ void setFont (const Font&);
+ Font getFont();
+
+ void drawGlyph (int glyphNumber, const AffineTransform&);
+
+ #ifndef DOXYGEN
+ class SavedState;
+ #endif
+
+private:
+ RenderingHelpers::SavedStateStack stack;
+};
+
+#endif // __JUCE_OPENGLGRAPHICSCONTEXT_JUCEHEADER__
diff --git a/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp b/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp
index b2f8ad6afd..923595ca47 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp
+++ b/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp
@@ -35,13 +35,11 @@ void* OpenGLHelpers::getExtensionFunction (const char* functionName)
{
#if JUCE_WINDOWS
return (void*) wglGetProcAddress (functionName);
-
- #elif JUCE_MAC
- static void* handle = dlopen (nullptr, RTLD_LAZY);
- return dlsym (handle, functionName);
-
#elif JUCE_LINUX
return (void*) glXGetProcAddress ((const GLubyte*) functionName);
+ #else
+ static void* handle = dlopen (nullptr, RTLD_LAZY);
+ return dlsym (handle, functionName);
#endif
}
diff --git a/modules/juce_opengl/opengl/juce_OpenGLImage.cpp b/modules/juce_opengl/opengl/juce_OpenGLImage.cpp
index 4c7cdd14c3..e90ac5e6c5 100644
--- a/modules/juce_opengl/opengl/juce_OpenGLImage.cpp
+++ b/modules/juce_opengl/opengl/juce_OpenGLImage.cpp
@@ -38,7 +38,7 @@ OpenGLFrameBufferImage::~OpenGLFrameBufferImage() {}
LowLevelGraphicsContext* OpenGLFrameBufferImage::createLowLevelContext()
{
- return new LowLevelGraphicsSoftwareRenderer (Image (this));
+ return new OpenGLRenderer (frameBuffer);
}
Image::SharedImage* OpenGLFrameBufferImage::clone()
@@ -75,7 +75,24 @@ namespace OpenGLImageHelpers
static void read (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
{
frameBuffer.readPixels ((PixelARGB*) bitmapData.data,
- Rectangle (x, y, bitmapData.width, bitmapData.height));
+ Rectangle (x, frameBuffer.getHeight() - (y + bitmapData.height), bitmapData.width, bitmapData.height));
+
+ verticalRowFlip ((PixelARGB*) bitmapData.data, bitmapData.width, bitmapData.height);
+ }
+
+ static void verticalRowFlip (PixelARGB* const data, const int w, const int h)
+ {
+ HeapBlock tempRow (w);
+ const int rowSize = sizeof (PixelARGB) * w;
+
+ for (int y = 0; y < h / 2; ++y)
+ {
+ PixelARGB* const row1 = data + y * w;
+ PixelARGB* const row2 = data + (h - 1 - y) * w;
+ memcpy (tempRow, row1, rowSize);
+ memcpy (row1, row2, rowSize);
+ memcpy (row2, tempRow, rowSize);
+ }
}
};
@@ -87,7 +104,14 @@ namespace OpenGLImageHelpers
void write (const PixelARGB* const data) const noexcept
{
- frameBuffer.writePixels (data, area);
+ HeapBlock invertedCopy (area.getWidth() * area.getHeight());
+ const int rowSize = sizeof (PixelARGB) * area.getWidth();
+
+ for (int y = 0; y < area.getHeight(); ++y)
+ memcpy (invertedCopy + area.getWidth() * y,
+ data + area.getWidth() * (area.getHeight() - 1 - y), rowSize);
+
+ frameBuffer.writePixels (invertedCopy, area);
}
OpenGLFrameBuffer& frameBuffer;