| @@ -1,72 +0,0 @@ | |||
| AnimationComponent template: | |||
| base class for constantly repainting window. | |||
| member variables for getElapsedFrames() etc. | |||
| OPENGLComponent template: | |||
| methods for load / draw object. | |||
| 3D Camera object and mousehandling. | |||
| AudioTemplate | |||
| simplest waveform drawing of input. | |||
| 07719784(0)995 | |||
| DEMO CHANGES: | |||
| Sidebar: | |||
| dark grey background white text; | |||
| Welcome: | |||
| Bouncy logo | |||
| Colours | |||
| Animation: | |||
| background (to texture/dark grey) | |||
| content | |||
| Code Editor: | |||
| dark grey background, white text | |||
| Dialog Boxes: | |||
| replace aluminium with texture background | |||
| MDI: | |||
| replace aluminium with texture background | |||
| Multi-touch: | |||
| darker grey background | |||
| Transforms: | |||
| replace aluminium with texture background | |||
| Windows: | |||
| texture background | |||
| 2D Rendering: | |||
| Fonts: | |||
| Image formats: | |||
| Settings: | |||
| FilePlayback: | |||
| Latency detector: | |||
| Recording: | |||
| Synthesisers: | |||
| MIDI i/o: | |||
| Cryptography: | |||
| HTTP: | |||
| Multithreading: | |||
| XML & JSON: | |||
| replace aluminium with texture background | |||
| @@ -0,0 +1,27 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist> | |||
| <dict> | |||
| <key>CFBundleExecutable</key> | |||
| <string>${EXECUTABLE_NAME}</string> | |||
| <key>CFBundleIconFile</key> | |||
| <string></string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.yourcompany.OpenGLAppExample</string> | |||
| <key>CFBundleName</key> | |||
| <string>OpenGLAppExample</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>APPL</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <key>CFBundleShortVersionString</key> | |||
| <string>1.0.0</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.0.0</string> | |||
| <key>NSHumanReadableCopyright</key> | |||
| <string></string> | |||
| <key>NSHighResolutionCapable</key> | |||
| <true/> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,19 @@ | |||
| Microsoft Visual Studio Solution File, Format Version 11.00 | |||
| # Visual Studio 2010 | |||
| Project("{3AF5984B-1995-D9AA-6A48-A11A7E29B8ED}") = "OpenGLAppExample", "OpenGLAppExample.vcxproj", "{7C7408CA-ACB1-2C65-426D-235C519770A9}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|Win32 = Debug|Win32 | |||
| Release|Win32 = Release|Win32 | |||
| EndGlobalSection | |||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
| {7C7408CA-ACB1-2C65-426D-235C519770A9}.Debug|Win32.ActiveCfg = Debug|Win32 | |||
| {7C7408CA-ACB1-2C65-426D-235C519770A9}.Debug|Win32.Build.0 = Debug|Win32 | |||
| {7C7408CA-ACB1-2C65-426D-235C519770A9}.Release|Win32.ActiveCfg = Release|Win32 | |||
| {7C7408CA-ACB1-2C65-426D-235C519770A9}.Release|Win32.Build.0 = Release|Win32 | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||
| EndGlobalSection | |||
| EndGlobal | |||
| @@ -0,0 +1,29 @@ | |||
| #ifdef JUCE_USER_DEFINED_RC_FILE | |||
| #include JUCE_USER_DEFINED_RC_FILE | |||
| #else | |||
| #undef WIN32_LEAN_AND_MEAN | |||
| #define WIN32_LEAN_AND_MEAN | |||
| #include <windows.h> | |||
| VS_VERSION_INFO VERSIONINFO | |||
| FILEVERSION 1,0,0,0 | |||
| BEGIN | |||
| BLOCK "StringFileInfo" | |||
| BEGIN | |||
| BLOCK "040904E4" | |||
| BEGIN | |||
| VALUE "FileDescription", "OpenGLAppExample\0" | |||
| VALUE "FileVersion", "1.0.0\0" | |||
| VALUE "ProductName", "OpenGLAppExample\0" | |||
| VALUE "ProductVersion", "1.0.0\0" | |||
| END | |||
| END | |||
| BLOCK "VarFileInfo" | |||
| BEGIN | |||
| VALUE "Translation", 0x409, 65001 | |||
| END | |||
| END | |||
| #endif | |||
| @@ -0,0 +1,29 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist> | |||
| <dict> | |||
| <key>LSRequiresIPhoneOS</key> | |||
| <true/> | |||
| <key>CFBundleExecutable</key> | |||
| <string>${EXECUTABLE_NAME}</string> | |||
| <key>CFBundleIconFile</key> | |||
| <string></string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.yourcompany.OpenGLAppExample</string> | |||
| <key>CFBundleName</key> | |||
| <string>OpenGLAppExample</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>APPL</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <key>CFBundleShortVersionString</key> | |||
| <string>1.0.0</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.0.0</string> | |||
| <key>NSHumanReadableCopyright</key> | |||
| <string></string> | |||
| <key>NSHighResolutionCapable</key> | |||
| <true/> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,58 @@ | |||
| { | |||
| "images": [ | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "29x29", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "40x40", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "60x60", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "60x60", | |||
| "scale": "3x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "29x29", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "29x29", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "40x40", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "40x40", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "76x76", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "76x76", | |||
| "scale": "2x" | |||
| } | |||
| ], | |||
| "info": { | |||
| "version": 1, | |||
| "author": "xcode" | |||
| } | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| { | |||
| "images": [ | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "iphone", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "iphone", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "orientation": "landscape", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "orientation": "landscape", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x" | |||
| } | |||
| ], | |||
| "info": { | |||
| "version": 1, | |||
| "author": "xcode" | |||
| } | |||
| } | |||
| @@ -0,0 +1,196 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| There's a section below where you can add your own custom code safely, and the | |||
| Introjucer will preserve the contents of that block, but the best way to change | |||
| any of these definitions is by using the Introjucer's project settings. | |||
| Any commented-out settings will assume their default values. | |||
| */ | |||
| #ifndef __JUCE_APPCONFIG_C3KRLE__ | |||
| #define __JUCE_APPCONFIG_C3KRLE__ | |||
| //============================================================================== | |||
| // [BEGIN_USER_CODE_SECTION] | |||
| // (You can add your own code in this section, and the Introjucer will not overwrite it) | |||
| // [END_USER_CODE_SECTION] | |||
| //============================================================================== | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_processors 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_core 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_cryptography 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_data_structures 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_events 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_graphics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_gui_basics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_gui_extra 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_opengl 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_video 1 | |||
| //============================================================================== | |||
| // juce_audio_devices flags: | |||
| #ifndef JUCE_ASIO | |||
| //#define JUCE_ASIO | |||
| #endif | |||
| #ifndef JUCE_WASAPI | |||
| //#define JUCE_WASAPI | |||
| #endif | |||
| #ifndef JUCE_DIRECTSOUND | |||
| //#define JUCE_DIRECTSOUND | |||
| #endif | |||
| #ifndef JUCE_ALSA | |||
| //#define JUCE_ALSA | |||
| #endif | |||
| #ifndef JUCE_JACK | |||
| //#define JUCE_JACK | |||
| #endif | |||
| #ifndef JUCE_USE_ANDROID_OPENSLES | |||
| //#define JUCE_USE_ANDROID_OPENSLES | |||
| #endif | |||
| #ifndef JUCE_USE_CDREADER | |||
| //#define JUCE_USE_CDREADER | |||
| #endif | |||
| #ifndef JUCE_USE_CDBURNER | |||
| //#define JUCE_USE_CDBURNER | |||
| #endif | |||
| //============================================================================== | |||
| // juce_audio_formats flags: | |||
| #ifndef JUCE_USE_FLAC | |||
| //#define JUCE_USE_FLAC | |||
| #endif | |||
| #ifndef JUCE_USE_OGGVORBIS | |||
| //#define JUCE_USE_OGGVORBIS | |||
| #endif | |||
| #ifndef JUCE_USE_MP3AUDIOFORMAT | |||
| //#define JUCE_USE_MP3AUDIOFORMAT | |||
| #endif | |||
| #ifndef JUCE_USE_LAME_AUDIO_FORMAT | |||
| //#define JUCE_USE_LAME_AUDIO_FORMAT | |||
| #endif | |||
| #ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT | |||
| //#define JUCE_USE_WINDOWS_MEDIA_FORMAT | |||
| #endif | |||
| //============================================================================== | |||
| // juce_audio_processors flags: | |||
| #ifndef JUCE_PLUGINHOST_VST | |||
| //#define JUCE_PLUGINHOST_VST | |||
| #endif | |||
| #ifndef JUCE_PLUGINHOST_VST3 | |||
| //#define JUCE_PLUGINHOST_VST3 | |||
| #endif | |||
| #ifndef JUCE_PLUGINHOST_AU | |||
| //#define JUCE_PLUGINHOST_AU | |||
| #endif | |||
| //============================================================================== | |||
| // juce_core flags: | |||
| #ifndef JUCE_FORCE_DEBUG | |||
| //#define JUCE_FORCE_DEBUG | |||
| #endif | |||
| #ifndef JUCE_LOG_ASSERTIONS | |||
| //#define JUCE_LOG_ASSERTIONS | |||
| #endif | |||
| #ifndef JUCE_CHECK_MEMORY_LEAKS | |||
| //#define JUCE_CHECK_MEMORY_LEAKS | |||
| #endif | |||
| #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||
| //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||
| #endif | |||
| #ifndef JUCE_INCLUDE_ZLIB_CODE | |||
| //#define JUCE_INCLUDE_ZLIB_CODE | |||
| #endif | |||
| //============================================================================== | |||
| // juce_graphics flags: | |||
| #ifndef JUCE_USE_COREIMAGE_LOADER | |||
| //#define JUCE_USE_COREIMAGE_LOADER | |||
| #endif | |||
| #ifndef JUCE_USE_DIRECTWRITE | |||
| //#define JUCE_USE_DIRECTWRITE | |||
| #endif | |||
| //============================================================================== | |||
| // juce_gui_basics flags: | |||
| #ifndef JUCE_ENABLE_REPAINT_DEBUGGING | |||
| //#define JUCE_ENABLE_REPAINT_DEBUGGING | |||
| #endif | |||
| #ifndef JUCE_USE_XSHM | |||
| //#define JUCE_USE_XSHM | |||
| #endif | |||
| #ifndef JUCE_USE_XRENDER | |||
| //#define JUCE_USE_XRENDER | |||
| #endif | |||
| #ifndef JUCE_USE_XCURSOR | |||
| //#define JUCE_USE_XCURSOR | |||
| #endif | |||
| //============================================================================== | |||
| // juce_gui_extra flags: | |||
| #ifndef JUCE_WEB_BROWSER | |||
| //#define JUCE_WEB_BROWSER | |||
| #endif | |||
| #ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR | |||
| //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR | |||
| #endif | |||
| //============================================================================== | |||
| // juce_video flags: | |||
| #ifndef JUCE_DIRECTSHOW | |||
| //#define JUCE_DIRECTSHOW | |||
| #endif | |||
| #ifndef JUCE_MEDIAFOUNDATION | |||
| //#define JUCE_MEDIAFOUNDATION | |||
| #endif | |||
| #ifndef JUCE_QUICKTIME | |||
| //#define JUCE_QUICKTIME | |||
| #endif | |||
| #ifndef JUCE_USE_CAMERA | |||
| //#define JUCE_USE_CAMERA | |||
| #endif | |||
| #endif // __JUCE_APPCONFIG_C3KRLE__ | |||
| @@ -0,0 +1,26 @@ | |||
| /* ========================================================================================= | |||
| This is an auto-generated file: Any edits you make may be overwritten! | |||
| */ | |||
| #ifndef BINARYDATA_H_65160528_INCLUDED | |||
| #define BINARYDATA_H_65160528_INCLUDED | |||
| namespace BinaryData | |||
| { | |||
| extern const char* teapot_obj; | |||
| const int teapot_objSize = 95000; | |||
| // Points to the start of a list of resource names. | |||
| extern const char* namedResourceList[]; | |||
| // Number of elements in the namedResourceList array. | |||
| const int namedResourceListSize = 1; | |||
| // If you provide the name of one of the binary resource variables above, this function will | |||
| // return the corresponding data and its size (or a null pointer if the name isn't found). | |||
| const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw(); | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,47 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| This is the header file that your files should include in order to get all the | |||
| JUCE library headers. You should avoid including the JUCE headers directly in | |||
| your own source files, because that wouldn't pick up the correct configuration | |||
| options for your app. | |||
| */ | |||
| #ifndef __APPHEADERFILE_C3KRLE__ | |||
| #define __APPHEADERFILE_C3KRLE__ | |||
| #include "AppConfig.h" | |||
| #include "modules/juce_audio_basics/juce_audio_basics.h" | |||
| #include "modules/juce_audio_devices/juce_audio_devices.h" | |||
| #include "modules/juce_audio_formats/juce_audio_formats.h" | |||
| #include "modules/juce_audio_processors/juce_audio_processors.h" | |||
| #include "modules/juce_core/juce_core.h" | |||
| #include "modules/juce_cryptography/juce_cryptography.h" | |||
| #include "modules/juce_data_structures/juce_data_structures.h" | |||
| #include "modules/juce_events/juce_events.h" | |||
| #include "modules/juce_graphics/juce_graphics.h" | |||
| #include "modules/juce_gui_basics/juce_gui_basics.h" | |||
| #include "modules/juce_gui_extra/juce_gui_extra.h" | |||
| #include "modules/juce_opengl/juce_opengl.h" | |||
| #include "modules/juce_video/juce_video.h" | |||
| #include "BinaryData.h" | |||
| #if ! DONT_SET_USING_JUCE_NAMESPACE | |||
| // If your code uses a lot of JUCE classes, then this will obviously save you | |||
| // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. | |||
| using namespace juce; | |||
| #endif | |||
| #if ! JUCE_DONT_DECLARE_PROJECTINFO | |||
| namespace ProjectInfo | |||
| { | |||
| const char* const projectName = "OpenGLAppExample"; | |||
| const char* const versionString = "1.0.0"; | |||
| const int versionNumber = 0x10000; | |||
| } | |||
| #endif | |||
| #endif // __APPHEADERFILE_C3KRLE__ | |||
| @@ -0,0 +1,12 @@ | |||
| Important Note!! | |||
| ================ | |||
| The purpose of this folder is to contain files that are auto-generated by the Introjucer, | |||
| and ALL files in this folder will be mercilessly DELETED and completely re-written whenever | |||
| the Introjucer saves your project. | |||
| Therefore, it's a bad idea to make any manual changes to the files in here, or to | |||
| put any of your own files in here if you don't want to lose them. (Of course you may choose | |||
| to add the folder's contents to your version-control system so that you can re-merge your own | |||
| modifications after the Introjucer has saved its changes). | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_audio_basics/juce_audio_basics.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_audio_devices/juce_audio_devices.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_audio_formats/juce_audio_formats.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_audio_processors/juce_audio_processors.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_core/juce_core.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_cryptography/juce_cryptography.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_data_structures/juce_data_structures.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_events/juce_events.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_graphics/juce_graphics.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_gui_basics/juce_gui_basics.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_gui_extra/juce_gui_extra.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_opengl/juce_opengl.h" | |||
| @@ -0,0 +1,5 @@ | |||
| // This is an auto-generated file to redirect any included | |||
| // module headers to the correct external folder. | |||
| #include "../../../../../modules/juce_video/juce_video.h" | |||
| @@ -0,0 +1,111 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <JUCERPROJECT id="c3KrlE" name="OpenGLAppExample" projectType="guiapp" version="1.0.0" | |||
| bundleIdentifier="com.yourcompany.OpenGLAppExample" includeBinaryInAppConfig="1" | |||
| jucerVersion="3.1.0"> | |||
| <MAINGROUP id="amjEXL" name="OpenGLAppExample"> | |||
| <GROUP id="{F5EA45A1-E25D-1821-14F8-EBCFBA9B2B81}" name="Shaders"> | |||
| <FILE id="D3dDWc" name="FragmentShader.glsl" compile="1" resource="0" | |||
| file="Source/FragmentShader.glsl"/> | |||
| <FILE id="l2YQJq" name="VertexShader.glsl" compile="1" resource="0" | |||
| file="Source/VertexShader.glsl"/> | |||
| </GROUP> | |||
| <GROUP id="{28FE2D12-A88D-07E2-72CF-CD04014CF225}" name="Source"> | |||
| <GROUP id="{666960E2-D311-806A-1FE7-A27057939840}" name="Resources"> | |||
| <FILE id="TK8Cyp" name="teapot.obj" compile="0" resource="1" file="Source/Resources/teapot.obj"/> | |||
| </GROUP> | |||
| <FILE id="uJnfj6" name="MainComponent.cpp" compile="1" resource="0" | |||
| file="Source/MainComponent.cpp"/> | |||
| <FILE id="vbnESJ" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/> | |||
| <FILE id="g9rTnA" name="WavefrontObjParser.h" compile="0" resource="0" | |||
| file="Source/Resources/WavefrontObjParser.h"/> | |||
| </GROUP> | |||
| </MAINGROUP> | |||
| <EXPORTFORMATS> | |||
| <XCODE_MAC targetFolder="Builds/MacOSX"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" osxSDK="default" osxCompatibility="default" osxArchitecture="default" | |||
| isDebug="1" optimisation="1" targetName="OpenGLAppExample"/> | |||
| <CONFIGURATION name="Release" osxSDK="default" osxCompatibility="default" osxArchitecture="default" | |||
| isDebug="0" optimisation="2" targetName="OpenGLAppExample"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_extra" path="../../modules"/> | |||
| <MODULEPATH id="juce_cryptography" path="../../modules"/> | |||
| <MODULEPATH id="juce_video" path="../../modules"/> | |||
| <MODULEPATH id="juce_opengl" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_processors" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_MAC> | |||
| <XCODE_IPHONE targetFolder="Builds/iOS"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" iosCompatibility="default" isDebug="1" optimisation="1" | |||
| targetName="OpenGLAppExample"/> | |||
| <CONFIGURATION name="Release" iosCompatibility="default" isDebug="0" optimisation="2" | |||
| targetName="OpenGLAppExample"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_extra" path="../../modules"/> | |||
| <MODULEPATH id="juce_cryptography" path="../../modules"/> | |||
| <MODULEPATH id="juce_video" path="../../modules"/> | |||
| <MODULEPATH id="juce_opengl" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_processors" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_IPHONE> | |||
| <VS2010 targetFolder="Builds/VisualStudio2010"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" | |||
| isDebug="1" optimisation="1" targetName="OpenGLAppExample"/> | |||
| <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" | |||
| isDebug="0" optimisation="2" targetName="OpenGLAppExample"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_extra" path="../../modules"/> | |||
| <MODULEPATH id="juce_cryptography" path="../../modules"/> | |||
| <MODULEPATH id="juce_video" path="../../modules"/> | |||
| <MODULEPATH id="juce_opengl" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_processors" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </VS2010> | |||
| </EXPORTFORMATS> | |||
| <MODULES> | |||
| <MODULES id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_audio_devices" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_audio_processors" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_core" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_cryptography" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_data_structures" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_events" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_graphics" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_gui_basics" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_gui_extra" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_opengl" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_video" showAllCode="1" useLocalCopy="0"/> | |||
| </MODULES> | |||
| <JUCEOPTIONS/> | |||
| </JUCERPROJECT> | |||
| @@ -0,0 +1,10 @@ | |||
| /* | |||
| ============================================================================== | |||
| FragmentShader.cpp | |||
| Created: 11 Nov 2014 12:17:53pm | |||
| Author: Felix Faire | |||
| ============================================================================== | |||
| */ | |||
| @@ -0,0 +1,102 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file was auto-generated by the Introjucer! | |||
| It contains the basic startup code for a Juce application. | |||
| ============================================================================== | |||
| */ | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| Component* createMainContentComponent(); | |||
| //============================================================================== | |||
| class OpenGLAppExampleApplication : public JUCEApplication | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| OpenGLAppExampleApplication() {} | |||
| const String getApplicationName() override { return ProjectInfo::projectName; } | |||
| const String getApplicationVersion() override { return ProjectInfo::versionString; } | |||
| bool moreThanOneInstanceAllowed() override { return true; } | |||
| //============================================================================== | |||
| void initialise (const String& commandLine) override | |||
| { | |||
| // This method is where you should put your application's initialisation code.. | |||
| mainWindow = new MainWindow (getApplicationName()); | |||
| } | |||
| void shutdown() override | |||
| { | |||
| // Add your application's shutdown code here.. | |||
| mainWindow = nullptr; // (deletes our window) | |||
| } | |||
| //============================================================================== | |||
| void systemRequestedQuit() override | |||
| { | |||
| // This is called when the app is being asked to quit: you can ignore this | |||
| // request and let the app carry on running, or call quit() to allow the app to close. | |||
| quit(); | |||
| } | |||
| void anotherInstanceStarted (const String& commandLine) override | |||
| { | |||
| // When another instance of the app is launched while this one is running, | |||
| // this method is invoked, and the commandLine parameter tells you what | |||
| // the other instance's command-line arguments were. | |||
| } | |||
| //============================================================================== | |||
| /* | |||
| This class implements the desktop window that contains an instance of | |||
| our MainContentComponent class. | |||
| */ | |||
| class MainWindow : public DocumentWindow | |||
| { | |||
| public: | |||
| MainWindow (String name) : DocumentWindow (name, | |||
| Colours::lightgrey, | |||
| DocumentWindow::allButtons) | |||
| { | |||
| setUsingNativeTitleBar (true); | |||
| setContentOwned (createMainContentComponent(), true); | |||
| setResizable (true, true); | |||
| centreWithSize (getWidth(), getHeight()); | |||
| setVisible (true); | |||
| } | |||
| void closeButtonPressed() override | |||
| { | |||
| // This is called when the user tries to close this window. Here, we'll just | |||
| // ask the app to quit when this happens, but you can change this to do | |||
| // whatever you need. | |||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||
| } | |||
| /* Note: Be careful if you override any DocumentWindow methods - the base | |||
| class uses a lot of them, so by overriding you might break its functionality. | |||
| It's best to do all your work in your content component instead, but if | |||
| you really have to override any DocumentWindow methods, make sure your | |||
| subclass also calls the superclass's method. | |||
| */ | |||
| private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) | |||
| }; | |||
| private: | |||
| ScopedPointer<MainWindow> mainWindow; | |||
| }; | |||
| //============================================================================== | |||
| // This macro generates the main() routine that launches the app. | |||
| START_JUCE_APPLICATION (OpenGLAppExampleApplication) | |||
| @@ -0,0 +1,403 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file was auto-generated! | |||
| ============================================================================== | |||
| */ | |||
| #ifndef MAINCOMPONENT_H_INCLUDED | |||
| #define MAINCOMPONENT_H_INCLUDED | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| #include "WavefrontObjParser.h" | |||
| //============================================================================== | |||
| /* | |||
| This component lives inside our window, and this is where you should put all | |||
| your controls and content. | |||
| */ | |||
| class MainContentComponent : public OpenGLAppComponent | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| MainContentComponent() | |||
| { | |||
| setSize (800, 600); | |||
| } | |||
| ~MainContentComponent() | |||
| { | |||
| shutdownOpenGL(); | |||
| } | |||
| void initialise() override | |||
| { | |||
| setShaders(); | |||
| } | |||
| void shutdown() override | |||
| { | |||
| shader = nullptr; | |||
| shape = nullptr; | |||
| attributes = nullptr; | |||
| uniforms = nullptr; | |||
| } | |||
| Matrix3D<float> getProjectionMatrix() const | |||
| { | |||
| float w = 1.0f / (0.5 + 0.1f); | |||
| float h = w * getLocalBounds().toFloat().getAspectRatio (false); | |||
| return Matrix3D<float>::fromFrustum (-w, w, -h, h, 4.0f, 30.0f); | |||
| } | |||
| Matrix3D<float> getViewMatrix() const | |||
| { | |||
| Matrix3D<float> viewMatrix (Vector3D<float> (0.0f, 0.0f, -10.0f)); | |||
| //viewMatrix *= draggableOrientation.getRotationMatrix(); | |||
| // Matrix3D<float> rotationMatrix = viewMatrix.rotated (Vector3D<float> (rotation, rotation, -0.3f)); | |||
| Matrix3D<float> rotationMatrix = viewMatrix.rotated (Vector3D<float> (-0.3f, 5.0f*sin(getFrameCounter()*0.01f), 0.0f)); | |||
| return viewMatrix * rotationMatrix; | |||
| } | |||
| void render() override | |||
| { | |||
| jassert (OpenGLHelpers::isContextActive()); | |||
| const float desktopScale = (float) openGLContext.getRenderingScale(); | |||
| OpenGLHelpers::clear (Colour::greyLevel(0.1)); | |||
| glEnable (GL_DEPTH_TEST); | |||
| glDepthFunc (GL_LESS); | |||
| glEnable (GL_BLEND); | |||
| glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
| openGLContext.extensions.glActiveTexture (GL_TEXTURE0); | |||
| glEnable (GL_TEXTURE_2D); | |||
| glViewport (0, 0, roundToInt (desktopScale * getWidth()), roundToInt (desktopScale * getHeight())); | |||
| shader->use(); | |||
| if (uniforms->projectionMatrix != nullptr) | |||
| uniforms->projectionMatrix->setMatrix4 (getProjectionMatrix().mat, 1, false); | |||
| if (uniforms->viewMatrix != nullptr) | |||
| uniforms->viewMatrix->setMatrix4 (getViewMatrix().mat, 1, false); | |||
| shape->draw (openGLContext, *attributes); | |||
| // Reset the element buffers so child Components draw correctly | |||
| openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0); | |||
| openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); | |||
| } | |||
| void paint (Graphics& g) override | |||
| { | |||
| // You can add your component specific drawing code here! | |||
| // This will draw over the top of the openGL background. | |||
| // g.setColour(Colours::white); | |||
| // g.drawEllipse (100, 100, 50, 50, 2); | |||
| } | |||
| void resized() override | |||
| { | |||
| // This is called when the MainContentComponent is resized. | |||
| // If you add any child components, this is where you should | |||
| // update their positions. | |||
| } | |||
| void setShaders() | |||
| { | |||
| vertexShader = { | |||
| "attribute vec4 position;\n" | |||
| "attribute vec4 sourceColour;\n" | |||
| "attribute vec2 texureCoordIn;\n" | |||
| "\n" | |||
| "uniform mat4 projectionMatrix;\n" | |||
| "uniform mat4 viewMatrix;\n" | |||
| "\n" | |||
| "varying vec4 destinationColour;\n" | |||
| "varying vec2 textureCoordOut;\n" | |||
| "\n" | |||
| "void main()\n" | |||
| "{\n" | |||
| " destinationColour = sourceColour;\n" | |||
| " textureCoordOut = texureCoordIn;\n" | |||
| " gl_Position = projectionMatrix * viewMatrix * position;\n" | |||
| "}\n"}; | |||
| fragmentShader = { | |||
| #if JUCE_OPENGL_ES | |||
| "varying lowp vec4 destinationColour;\n" | |||
| "varying lowp vec2 textureCoordOut;\n" | |||
| #else | |||
| "varying vec4 destinationColour;\n" | |||
| "varying vec2 textureCoordOut;\n" | |||
| #endif | |||
| "\n" | |||
| "void main()\n" | |||
| "{\n" | |||
| " vec4 colour = vec4(0.95, 0.57, 0.03, 0.8);\n" | |||
| " gl_FragColor = colour;\n" | |||
| "}\n" }; | |||
| ScopedPointer<OpenGLShaderProgram> newShader (new OpenGLShaderProgram (openGLContext)); | |||
| String statusText; | |||
| if (newShader->addVertexShader (OpenGLHelpers::translateVertexShaderToV3 (vertexShader)) | |||
| && newShader->addFragmentShader (OpenGLHelpers::translateFragmentShaderToV3 (fragmentShader)) | |||
| && newShader->link()) | |||
| { | |||
| shape = nullptr; | |||
| attributes = nullptr; | |||
| uniforms = nullptr; | |||
| shader = newShader; | |||
| shader->use(); | |||
| shape = new Shape (openGLContext); | |||
| attributes = new Attributes (openGLContext, *shader); | |||
| uniforms = new Uniforms (openGLContext, *shader); | |||
| statusText = "GLSL: v" + String (OpenGLShaderProgram::getLanguageVersion(), 2); | |||
| } | |||
| else | |||
| { | |||
| statusText = newShader->getLastError(); | |||
| } | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| // private member variables | |||
| struct Vertex | |||
| { | |||
| float position[3]; | |||
| float normal[3]; | |||
| float colour[4]; | |||
| float texCoord[2]; | |||
| }; | |||
| //============================================================================== | |||
| // This class just manages the attributes that the demo shaders use. | |||
| struct Attributes | |||
| { | |||
| Attributes (OpenGLContext& openGLContext, OpenGLShaderProgram& shader) | |||
| { | |||
| position = createAttribute (openGLContext, shader, "position"); | |||
| normal = createAttribute (openGLContext, shader, "normal"); | |||
| sourceColour = createAttribute (openGLContext, shader, "sourceColour"); | |||
| texureCoordIn = createAttribute (openGLContext, shader, "texureCoordIn"); | |||
| } | |||
| void enable (OpenGLContext& openGLContext) | |||
| { | |||
| if (position != nullptr) | |||
| { | |||
| openGLContext.extensions.glVertexAttribPointer (position->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), 0); | |||
| openGLContext.extensions.glEnableVertexAttribArray (position->attributeID); | |||
| } | |||
| if (normal != nullptr) | |||
| { | |||
| openGLContext.extensions.glVertexAttribPointer (normal->attributeID, 3, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 3)); | |||
| openGLContext.extensions.glEnableVertexAttribArray (normal->attributeID); | |||
| } | |||
| if (sourceColour != nullptr) | |||
| { | |||
| openGLContext.extensions.glVertexAttribPointer (sourceColour->attributeID, 4, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 6)); | |||
| openGLContext.extensions.glEnableVertexAttribArray (sourceColour->attributeID); | |||
| } | |||
| if (texureCoordIn != nullptr) | |||
| { | |||
| openGLContext.extensions.glVertexAttribPointer (texureCoordIn->attributeID, 2, GL_FLOAT, GL_FALSE, sizeof (Vertex), (GLvoid*) (sizeof (float) * 10)); | |||
| openGLContext.extensions.glEnableVertexAttribArray (texureCoordIn->attributeID); | |||
| } | |||
| } | |||
| void disable (OpenGLContext& openGLContext) | |||
| { | |||
| if (position != nullptr) openGLContext.extensions.glDisableVertexAttribArray (position->attributeID); | |||
| if (normal != nullptr) openGLContext.extensions.glDisableVertexAttribArray (normal->attributeID); | |||
| if (sourceColour != nullptr) openGLContext.extensions.glDisableVertexAttribArray (sourceColour->attributeID); | |||
| if (texureCoordIn != nullptr) openGLContext.extensions.glDisableVertexAttribArray (texureCoordIn->attributeID); | |||
| } | |||
| ScopedPointer<OpenGLShaderProgram::Attribute> position, normal, sourceColour, texureCoordIn; | |||
| private: | |||
| static OpenGLShaderProgram::Attribute* createAttribute (OpenGLContext& openGLContext, | |||
| OpenGLShaderProgram& shader, | |||
| const char* attributeName) | |||
| { | |||
| if (openGLContext.extensions.glGetAttribLocation (shader.getProgramID(), attributeName) < 0) | |||
| return nullptr; | |||
| return new OpenGLShaderProgram::Attribute (shader, attributeName); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| // This class just manages the uniform values that the demo shaders use. | |||
| struct Uniforms | |||
| { | |||
| Uniforms (OpenGLContext& openGLContext, OpenGLShaderProgram& shader) | |||
| { | |||
| projectionMatrix = createUniform (openGLContext, shader, "projectionMatrix"); | |||
| viewMatrix = createUniform (openGLContext, shader, "viewMatrix"); | |||
| texture = createUniform (openGLContext, shader, "demoTexture"); | |||
| lightPosition = createUniform (openGLContext, shader, "lightPosition"); | |||
| bouncingNumber = createUniform (openGLContext, shader, "bouncingNumber"); | |||
| } | |||
| ScopedPointer<OpenGLShaderProgram::Uniform> projectionMatrix, viewMatrix, texture, lightPosition, bouncingNumber; | |||
| private: | |||
| static OpenGLShaderProgram::Uniform* createUniform (OpenGLContext& openGLContext, | |||
| OpenGLShaderProgram& shader, | |||
| const char* uniformName) | |||
| { | |||
| if (openGLContext.extensions.glGetUniformLocation (shader.getProgramID(), uniformName) < 0) | |||
| return nullptr; | |||
| return new OpenGLShaderProgram::Uniform (shader, uniformName); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| /** This loads a 3D model from an OBJ file and converts it into some vertex buffers | |||
| that we can draw. | |||
| */ | |||
| struct Shape | |||
| { | |||
| Shape (OpenGLContext& openGLContext) | |||
| { | |||
| if (shapeFile.load (BinaryData::teapot_obj).wasOk()) | |||
| for (int i = 0; i < shapeFile.shapes.size(); ++i) | |||
| vertexBuffers.add (new VertexBuffer (openGLContext, *shapeFile.shapes.getUnchecked(i))); | |||
| } | |||
| void draw (OpenGLContext& openGLContext, Attributes& attributes) | |||
| { | |||
| for (int i = 0; i < vertexBuffers.size(); ++i) | |||
| { | |||
| VertexBuffer& vertexBuffer = *vertexBuffers.getUnchecked (i); | |||
| vertexBuffer.bind(); | |||
| attributes.enable (openGLContext); | |||
| glDrawElements (GL_TRIANGLES, vertexBuffer.numIndices, GL_UNSIGNED_INT, 0); | |||
| attributes.disable (openGLContext); | |||
| } | |||
| } | |||
| private: | |||
| struct VertexBuffer | |||
| { | |||
| VertexBuffer (OpenGLContext& context, WavefrontObjFile::Shape& shape) : openGLContext (context) | |||
| { | |||
| numIndices = shape.mesh.indices.size(); | |||
| openGLContext.extensions.glGenBuffers (1, &vertexBuffer); | |||
| openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer); | |||
| Array<Vertex> vertices; | |||
| createVertexListFromMesh (shape.mesh, vertices, Colours::green); | |||
| openGLContext.extensions.glBufferData (GL_ARRAY_BUFFER, vertices.size() * sizeof (Vertex), | |||
| vertices.getRawDataPointer(), GL_STATIC_DRAW); | |||
| openGLContext.extensions.glGenBuffers (1, &indexBuffer); | |||
| openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer); | |||
| openGLContext.extensions.glBufferData (GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof (juce::uint32), | |||
| shape.mesh.indices.getRawDataPointer(), GL_STATIC_DRAW); | |||
| } | |||
| ~VertexBuffer() | |||
| { | |||
| openGLContext.extensions.glDeleteBuffers (1, &vertexBuffer); | |||
| openGLContext.extensions.glDeleteBuffers (1, &indexBuffer); | |||
| } | |||
| void bind() | |||
| { | |||
| openGLContext.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer); | |||
| openGLContext.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexBuffer); | |||
| } | |||
| GLuint vertexBuffer, indexBuffer; | |||
| int numIndices; | |||
| OpenGLContext& openGLContext; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VertexBuffer) | |||
| }; | |||
| WavefrontObjFile shapeFile; | |||
| OwnedArray<VertexBuffer> vertexBuffers; | |||
| static void createVertexListFromMesh (const WavefrontObjFile::Mesh& mesh, Array<Vertex>& list, Colour colour) | |||
| { | |||
| const float scale = 0.2f; | |||
| WavefrontObjFile::TextureCoord defaultTexCoord = { 0.5f, 0.5f }; | |||
| WavefrontObjFile::Vertex defaultNormal = { 0.5f, 0.5f, 0.5f }; | |||
| for (int i = 0; i < mesh.vertices.size(); ++i) | |||
| { | |||
| const WavefrontObjFile::Vertex& v = mesh.vertices.getReference (i); | |||
| const WavefrontObjFile::Vertex& n | |||
| = i < mesh.normals.size() ? mesh.normals.getReference (i) : defaultNormal; | |||
| const WavefrontObjFile::TextureCoord& tc | |||
| = i < mesh.textureCoords.size() ? mesh.textureCoords.getReference (i) : defaultTexCoord; | |||
| Vertex vert = | |||
| { | |||
| { scale * v.x, scale * v.y, scale * v.z, }, | |||
| { scale * n.x, scale * n.y, scale * n.z, }, | |||
| { colour.getFloatRed(), colour.getFloatGreen(), colour.getFloatBlue(), colour.getFloatAlpha() }, | |||
| { tc.x, tc.y } | |||
| }; | |||
| list.add (vert); | |||
| } | |||
| } | |||
| }; | |||
| const char* vertexShader; | |||
| const char* fragmentShader; | |||
| ScopedPointer<OpenGLShaderProgram> shader; | |||
| ScopedPointer<Shape> shape; | |||
| ScopedPointer<Attributes> attributes; | |||
| ScopedPointer<Uniforms> uniforms; | |||
| String newVertexShader, newFragmentShader; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent) | |||
| }; | |||
| // (This function is called by the app startup code to create our main component) | |||
| Component* createMainContentComponent() { return new MainContentComponent(); } | |||
| #endif // MAINCOMPONENT_H_INCLUDED | |||
| @@ -0,0 +1,359 @@ | |||
| /* | |||
| ============================================================================== | |||
| 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 <map> | |||
| //============================================================================== | |||
| /** | |||
| This is a quick-and-dirty parser for the 3D OBJ file format. | |||
| Just call load() and if there aren't any errors, the 'shapes' array should | |||
| be filled with all the shape objects that were loaded from the file. | |||
| */ | |||
| class WavefrontObjFile | |||
| { | |||
| public: | |||
| WavefrontObjFile() {} | |||
| Result load (const String& objFileContent) | |||
| { | |||
| shapes.clear(); | |||
| return parseObjFile (StringArray::fromLines (objFileContent)); | |||
| } | |||
| Result load (const File& file) | |||
| { | |||
| sourceFile = file; | |||
| return load (file.loadFileAsString()); | |||
| } | |||
| //============================================================================== | |||
| typedef juce::uint32 Index; | |||
| struct Vertex { float x, y, z; }; | |||
| struct TextureCoord { float x, y; }; | |||
| struct Mesh | |||
| { | |||
| Array<Vertex> vertices, normals; | |||
| Array<TextureCoord> textureCoords; | |||
| Array<Index> indices; | |||
| }; | |||
| struct Material | |||
| { | |||
| Material() noexcept : shininess (1.0f), refractiveIndex (0.0f) | |||
| { | |||
| zerostruct (ambient); | |||
| zerostruct (diffuse); | |||
| zerostruct (specular); | |||
| zerostruct (transmittance); | |||
| zerostruct (emission); | |||
| } | |||
| String name; | |||
| Vertex ambient, diffuse, specular, transmittance, emission; | |||
| float shininess, refractiveIndex; | |||
| String ambientTextureName, diffuseTextureName, | |||
| specularTextureName, normalTextureName; | |||
| StringPairArray parameters; | |||
| }; | |||
| struct Shape | |||
| { | |||
| String name; | |||
| Mesh mesh; | |||
| Material material; | |||
| }; | |||
| OwnedArray<Shape> shapes; | |||
| private: | |||
| //============================================================================== | |||
| File sourceFile; | |||
| struct TripleIndex | |||
| { | |||
| TripleIndex() noexcept : vertexIndex (-1), textureIndex (-1), normalIndex (-1) {} | |||
| bool operator< (const TripleIndex& other) const noexcept { return vertexIndex < other.vertexIndex; } | |||
| int vertexIndex, textureIndex, normalIndex; | |||
| }; | |||
| struct IndexMap | |||
| { | |||
| std::map<TripleIndex, Index> map; | |||
| Index getIndexFor (TripleIndex i, Mesh& newMesh, const Mesh& srcMesh) | |||
| { | |||
| const std::map<TripleIndex, Index>::iterator it (map.find (i)); | |||
| if (it != map.end()) | |||
| return it->second; | |||
| const Index index = (Index) newMesh.vertices.size(); | |||
| if (isPositiveAndBelow (i.vertexIndex, srcMesh.vertices.size())) | |||
| newMesh.vertices.add (srcMesh.vertices.getReference (i.vertexIndex)); | |||
| if (isPositiveAndBelow (i.normalIndex, srcMesh.normals.size())) | |||
| newMesh.normals.add (srcMesh.normals.getReference (i.normalIndex)); | |||
| if (isPositiveAndBelow (i.textureIndex, srcMesh.textureCoords.size())) | |||
| newMesh.textureCoords.add (srcMesh.textureCoords.getReference (i.textureIndex)); | |||
| map[i] = index; | |||
| return index; | |||
| } | |||
| }; | |||
| static float parseFloat (String::CharPointerType& t) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| return (float) CharacterFunctions::readDoubleValue (t); | |||
| } | |||
| static Vertex parseVertex (String::CharPointerType t) | |||
| { | |||
| Vertex v; | |||
| v.x = parseFloat (t); | |||
| v.y = parseFloat (t); | |||
| v.z = parseFloat (t); | |||
| return v; | |||
| } | |||
| static TextureCoord parseTextureCoord (String::CharPointerType t) | |||
| { | |||
| TextureCoord tc; | |||
| tc.x = parseFloat (t); | |||
| tc.y = parseFloat (t); | |||
| return tc; | |||
| } | |||
| static bool matchToken (String::CharPointerType& t, const char* token) | |||
| { | |||
| const int len = (int) strlen (token); | |||
| if (CharacterFunctions::compareUpTo (CharPointer_ASCII (token), t, len) == 0) | |||
| { | |||
| String::CharPointerType end = t + len; | |||
| if (end.isEmpty() || end.isWhitespace()) | |||
| { | |||
| t = end.findEndOfWhitespace(); | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| struct Face | |||
| { | |||
| Face (String::CharPointerType t) | |||
| { | |||
| while (! t.isEmpty()) | |||
| triples.add (parseTriple (t)); | |||
| } | |||
| Array<TripleIndex> triples; | |||
| void addIndices (Mesh& newMesh, const Mesh& srcMesh, IndexMap& indexMap) | |||
| { | |||
| TripleIndex i0 (triples[0]), i1, i2 (triples[1]); | |||
| for (int i = 2; i < triples.size(); ++i) | |||
| { | |||
| i1 = i2; | |||
| i2 = triples.getReference (i); | |||
| newMesh.indices.add (indexMap.getIndexFor (i0, newMesh, srcMesh)); | |||
| newMesh.indices.add (indexMap.getIndexFor (i1, newMesh, srcMesh)); | |||
| newMesh.indices.add (indexMap.getIndexFor (i2, newMesh, srcMesh)); | |||
| } | |||
| } | |||
| static TripleIndex parseTriple (String::CharPointerType& t) | |||
| { | |||
| TripleIndex i; | |||
| t = t.findEndOfWhitespace(); | |||
| i.vertexIndex = t.getIntValue32() - 1; | |||
| t = findEndOfFaceToken (t); | |||
| if (t.isEmpty() || t.getAndAdvance() != '/') | |||
| return i; | |||
| if (*t == '/') | |||
| { | |||
| ++t; | |||
| } | |||
| else | |||
| { | |||
| i.textureIndex = t.getIntValue32() - 1; | |||
| t = findEndOfFaceToken (t); | |||
| if (t.isEmpty() || t.getAndAdvance() != '/') | |||
| return i; | |||
| } | |||
| i.normalIndex = t.getIntValue32() - 1; | |||
| t = findEndOfFaceToken (t); | |||
| return i; | |||
| } | |||
| static String::CharPointerType findEndOfFaceToken (String::CharPointerType t) noexcept | |||
| { | |||
| return CharacterFunctions::findEndOfToken (t, CharPointer_ASCII ("/ \t"), String::empty.getCharPointer()); | |||
| } | |||
| }; | |||
| static Shape* parseFaceGroup (const Mesh& srcMesh, | |||
| const Array<Face>& faceGroup, | |||
| const Material& material, | |||
| const String& name) | |||
| { | |||
| if (faceGroup.size() == 0) | |||
| return nullptr; | |||
| ScopedPointer<Shape> shape (new Shape()); | |||
| shape->name = name; | |||
| shape->material = material; | |||
| IndexMap indexMap; | |||
| for (int i = 0; i < faceGroup.size(); ++i) | |||
| faceGroup.getReference(i).addIndices (shape->mesh, srcMesh, indexMap); | |||
| return shape.release(); | |||
| } | |||
| Result parseObjFile (const StringArray& lines) | |||
| { | |||
| Mesh mesh; | |||
| Array<Face> faceGroup; | |||
| Array<Material> knownMaterials; | |||
| Material lastMaterial; | |||
| String lastName; | |||
| for (int lineNum = 0; lineNum < lines.size(); ++lineNum) | |||
| { | |||
| String::CharPointerType l = lines[lineNum].getCharPointer().findEndOfWhitespace(); | |||
| if (matchToken (l, "v")) { mesh.vertices.add (parseVertex (l)); continue; } | |||
| if (matchToken (l, "vn")) { mesh.normals.add (parseVertex (l)); continue; } | |||
| if (matchToken (l, "vt")) { mesh.textureCoords.add (parseTextureCoord (l)); continue; } | |||
| if (matchToken (l, "f")) { faceGroup.add (Face (l)); continue; } | |||
| if (matchToken (l, "usemtl")) | |||
| { | |||
| const String name (String (l).trim()); | |||
| for (int i = knownMaterials.size(); --i >= 0;) | |||
| { | |||
| if (knownMaterials.getReference(i).name == name) | |||
| { | |||
| lastMaterial = knownMaterials.getReference(i); | |||
| break; | |||
| } | |||
| } | |||
| continue; | |||
| } | |||
| if (matchToken (l, "mtllib")) | |||
| { | |||
| Result r = parseMaterial (knownMaterials, String (l).trim()); | |||
| continue; | |||
| } | |||
| if (matchToken (l, "g") || matchToken (l, "o")) | |||
| { | |||
| if (Shape* shape = parseFaceGroup (mesh, faceGroup, lastMaterial, lastName)) | |||
| shapes.add (shape); | |||
| faceGroup.clear(); | |||
| lastName = StringArray::fromTokens (l, " \t", "")[0]; | |||
| continue; | |||
| } | |||
| } | |||
| if (Shape* shape = parseFaceGroup (mesh, faceGroup, lastMaterial, lastName)) | |||
| shapes.add (shape); | |||
| return Result::ok(); | |||
| } | |||
| Result parseMaterial (Array<Material>& materials, const String& filename) | |||
| { | |||
| jassert (sourceFile.exists()); | |||
| File f (sourceFile.getSiblingFile (filename)); | |||
| if (! f.exists()) | |||
| return Result::fail ("Cannot open file: " + filename); | |||
| StringArray lines; | |||
| lines.addLines (f.loadFileAsString()); | |||
| materials.clear(); | |||
| Material material; | |||
| for (int i = 0; i < lines.size(); ++i) | |||
| { | |||
| String::CharPointerType l (lines[i].getCharPointer().findEndOfWhitespace()); | |||
| if (matchToken (l, "newmtl")) { materials.add (material); material.name = String (l).trim(); continue; } | |||
| if (matchToken (l, "Ka")) { material.ambient = parseVertex (l); continue; } | |||
| if (matchToken (l, "Kd")) { material.diffuse = parseVertex (l); continue; } | |||
| if (matchToken (l, "Ks")) { material.specular = parseVertex (l); continue; } | |||
| if (matchToken (l, "Kt")) { material.transmittance = parseVertex (l); continue; } | |||
| if (matchToken (l, "Ke")) { material.emission = parseVertex (l); continue; } | |||
| if (matchToken (l, "Ni")) { material.refractiveIndex = parseFloat (l); continue; } | |||
| if (matchToken (l, "Ns")) { material.shininess = parseFloat (l); continue; } | |||
| if (matchToken (l, "map_Ka")) { material.ambientTextureName = String (l).trim(); continue; } | |||
| if (matchToken (l, "map_Kd")) { material.diffuseTextureName = String (l).trim(); continue; } | |||
| if (matchToken (l, "map_Ks")) { material.specularTextureName = String (l).trim(); continue; } | |||
| if (matchToken (l, "map_Ns")) { material.normalTextureName = String (l).trim(); continue; } | |||
| StringArray tokens; | |||
| tokens.addTokens (l, " \t", ""); | |||
| if (tokens.size() >= 2) | |||
| material.parameters.set (tokens[0].trim(), tokens[1].trim()); | |||
| } | |||
| materials.add (material); | |||
| return Result::ok(); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavefrontObjFile) | |||
| }; | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| ============================================================================== | |||
| VertexShader.cpp | |||
| Created: 11 Nov 2014 12:17:40pm | |||
| Author: Felix Faire | |||
| ============================================================================== | |||
| */ | |||
| @@ -716,10 +716,10 @@ static const unsigned char temp_binary_data_8[] = | |||
| "\r\n" | |||
| "void CONTENTCOMPCLASS::paint (Graphics& g)\r\n" | |||
| "{\r\n" | |||
| " g.fillAll (Colour (0xffeeddff));\r\n" | |||
| " g.fillAll (Colour (0xff001F36));\r\n" | |||
| "\r\n" | |||
| " g.setFont (Font (16.0f));\r\n" | |||
| " g.setColour (Colours::black);\r\n" | |||
| " g.setColour (Colours::white);\r\n" | |||
| " g.drawText (\"Hello World!\", getLocalBounds(), Justification::centred, true);\r\n" | |||
| "}\r\n" | |||
| "\r\n" | |||
| @@ -21,10 +21,10 @@ CONTENTCOMPCLASS::~CONTENTCOMPCLASS() | |||
| void CONTENTCOMPCLASS::paint (Graphics& g) | |||
| { | |||
| g.fillAll (Colour (0xffeeddff)); | |||
| g.fillAll (Colour (0xff001F36)); | |||
| g.setFont (Font (16.0f)); | |||
| g.setColour (Colours::black); | |||
| g.setColour (Colours::white); | |||
| g.drawText ("Hello World!", getLocalBounds(), Justification::centred, true); | |||
| } | |||
| @@ -1,77 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file was auto-generated! | |||
| ============================================================================== | |||
| */ | |||
| #ifndef MAINCOMPONENT_H_INCLUDED | |||
| #define MAINCOMPONENT_H_INCLUDED | |||
| INCLUDE_JUCE | |||
| //============================================================================== | |||
| /* | |||
| This component lives inside our window, and this is where you should put all | |||
| your controls and content. | |||
| */ | |||
| class MainContentComponent : public OpenGLAppComponent | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| MainContentComponent() | |||
| { | |||
| setSize (800, 600); | |||
| } | |||
| ~MainContentComponent() | |||
| { | |||
| shutdownOpenGL(); | |||
| } | |||
| void initialise() override | |||
| { | |||
| } | |||
| void shutdown() override | |||
| { | |||
| } | |||
| void render() override | |||
| { | |||
| } | |||
| void paint (Graphics& g) override | |||
| { | |||
| // (Our component is opaque, so we must completely fill the background with a solid colour) | |||
| g.fillAll (Colours::black); | |||
| // You can add your drawing code here! | |||
| } | |||
| void resized() override | |||
| { | |||
| // This is called when the MainContentComponent is resized. | |||
| // If you add any child components, this is where you should | |||
| // update their positions. | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| // private member variables | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent) | |||
| }; | |||
| // (This function is called by the app startup code to create our main component) | |||
| Component* createMainContentComponent() { return new MainContentComponent(); } | |||
| #endif // MAINCOMPONENT_H_INCLUDED | |||
| @@ -40,15 +40,14 @@ public: | |||
| void render() override | |||
| { | |||
| OpenGLHelpers::clear (Colours::black); | |||
| } | |||
| void paint (Graphics& g) override | |||
| { | |||
| // (Our component is opaque, so we must completely fill the background with a solid colour) | |||
| g.fillAll (Colours::black); | |||
| // You can add your drawing code here! | |||
| // You can add your component specific drawing code here! | |||
| // This will draw over the top of the openGL background. | |||
| } | |||
| void resized() override | |||
| @@ -1,698 +0,0 @@ | |||
| /* | |||
| * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org | |||
| * | |||
| * This software is provided 'as-is', without any express or implied | |||
| * warranty. In no event will the authors be held liable for any damages | |||
| * arising from the use of this software. | |||
| * Permission is granted to anyone to use this software for any purpose, | |||
| * including commercial applications, and to alter it and redistribute it | |||
| * freely, subject to the following restrictions: | |||
| * 1. The origin of this software must not be misrepresented; you must not | |||
| * claim that you wrote the original software. If you use this software | |||
| * in a product, an acknowledgment in the product documentation would be | |||
| * appreciated but is not required. | |||
| * 2. Altered source versions must be plainly marked as such, and must not be | |||
| * misrepresented as being the original software. | |||
| * 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "b2Collision.h" | |||
| #include "Shapes/b2CircleShape.h" | |||
| #include "Shapes/b2EdgeShape.h" | |||
| #include "Shapes/b2PolygonShape.h" | |||
| // Compute contact points for edge versus circle. | |||
| // This accounts for edge connectivity. | |||
| void b2CollideEdgeAndCircle(b2Manifold* manifold, | |||
| const b2EdgeShape* edgeA, const b2Transform& xfA, | |||
| const b2CircleShape* circleB, const b2Transform& xfB) | |||
| { | |||
| manifold->pointCount = 0; | |||
| // Compute circle in frame of edge | |||
| b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p)); | |||
| b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2; | |||
| b2Vec2 e = B - A; | |||
| // Barycentric coordinates | |||
| float32 u = b2Dot(e, B - Q); | |||
| float32 v = b2Dot(e, Q - A); | |||
| float32 radius = edgeA->m_radius + circleB->m_radius; | |||
| b2ContactFeature cf; | |||
| cf.indexB = 0; | |||
| cf.typeB = b2ContactFeature::e_vertex; | |||
| // Region A | |||
| if (v <= 0.0f) | |||
| { | |||
| b2Vec2 P = A; | |||
| b2Vec2 d = Q - P; | |||
| float32 dd = b2Dot(d, d); | |||
| if (dd > radius * radius) | |||
| { | |||
| return; | |||
| } | |||
| // Is there an edge connected to A? | |||
| if (edgeA->m_hasVertex0) | |||
| { | |||
| b2Vec2 A1 = edgeA->m_vertex0; | |||
| b2Vec2 B1 = A; | |||
| b2Vec2 e1 = B1 - A1; | |||
| float32 u1 = b2Dot(e1, B1 - Q); | |||
| // Is the circle in Region AB of the previous edge? | |||
| if (u1 > 0.0f) | |||
| { | |||
| return; | |||
| } | |||
| } | |||
| cf.indexA = 0; | |||
| cf.typeA = b2ContactFeature::e_vertex; | |||
| manifold->pointCount = 1; | |||
| manifold->type = b2Manifold::e_circles; | |||
| manifold->localNormal.SetZero(); | |||
| manifold->localPoint = P; | |||
| manifold->points[0].id.key = 0; | |||
| manifold->points[0].id.cf = cf; | |||
| manifold->points[0].localPoint = circleB->m_p; | |||
| return; | |||
| } | |||
| // Region B | |||
| if (u <= 0.0f) | |||
| { | |||
| b2Vec2 P = B; | |||
| b2Vec2 d = Q - P; | |||
| float32 dd = b2Dot(d, d); | |||
| if (dd > radius * radius) | |||
| { | |||
| return; | |||
| } | |||
| // Is there an edge connected to B? | |||
| if (edgeA->m_hasVertex3) | |||
| { | |||
| b2Vec2 B2 = edgeA->m_vertex3; | |||
| b2Vec2 A2 = B; | |||
| b2Vec2 e2 = B2 - A2; | |||
| float32 v2 = b2Dot(e2, Q - A2); | |||
| // Is the circle in Region AB of the next edge? | |||
| if (v2 > 0.0f) | |||
| { | |||
| return; | |||
| } | |||
| } | |||
| cf.indexA = 1; | |||
| cf.typeA = b2ContactFeature::e_vertex; | |||
| manifold->pointCount = 1; | |||
| manifold->type = b2Manifold::e_circles; | |||
| manifold->localNormal.SetZero(); | |||
| manifold->localPoint = P; | |||
| manifold->points[0].id.key = 0; | |||
| manifold->points[0].id.cf = cf; | |||
| manifold->points[0].localPoint = circleB->m_p; | |||
| return; | |||
| } | |||
| // Region AB | |||
| float32 den = b2Dot(e, e); | |||
| b2Assert(den > 0.0f); | |||
| b2Vec2 P = (1.0f / den) * (u * A + v * B); | |||
| b2Vec2 d = Q - P; | |||
| float32 dd = b2Dot(d, d); | |||
| if (dd > radius * radius) | |||
| { | |||
| return; | |||
| } | |||
| b2Vec2 n(-e.y, e.x); | |||
| if (b2Dot(n, Q - A) < 0.0f) | |||
| { | |||
| n.Set(-n.x, -n.y); | |||
| } | |||
| n.Normalize(); | |||
| cf.indexA = 0; | |||
| cf.typeA = b2ContactFeature::e_face; | |||
| manifold->pointCount = 1; | |||
| manifold->type = b2Manifold::e_faceA; | |||
| manifold->localNormal = n; | |||
| manifold->localPoint = A; | |||
| manifold->points[0].id.key = 0; | |||
| manifold->points[0].id.cf = cf; | |||
| manifold->points[0].localPoint = circleB->m_p; | |||
| } | |||
| // This structure is used to keep track of the best separating axis. | |||
| struct b2EPAxis | |||
| { | |||
| enum Type | |||
| { | |||
| e_unknown, | |||
| e_edgeA, | |||
| e_edgeB | |||
| }; | |||
| Type type; | |||
| int32 index; | |||
| float32 separation; | |||
| }; | |||
| // This holds polygon B expressed in frame A. | |||
| struct b2TempPolygon | |||
| { | |||
| b2Vec2 vertices[b2_maxPolygonVertices]; | |||
| b2Vec2 normals[b2_maxPolygonVertices]; | |||
| int32 count; | |||
| }; | |||
| // Reference face used for clipping | |||
| struct b2ReferenceFace | |||
| { | |||
| int32 i1, i2; | |||
| b2Vec2 v1, v2; | |||
| b2Vec2 normal; | |||
| b2Vec2 sideNormal1; | |||
| float32 sideOffset1; | |||
| b2Vec2 sideNormal2; | |||
| float32 sideOffset2; | |||
| }; | |||
| // This class collides and edge and a polygon, taking into account edge adjacency. | |||
| struct b2EPCollider | |||
| { | |||
| void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, | |||
| const b2PolygonShape* polygonB, const b2Transform& xfB); | |||
| b2EPAxis ComputeEdgeSeparation(); | |||
| b2EPAxis ComputePolygonSeparation(); | |||
| enum VertexType | |||
| { | |||
| e_isolated, | |||
| e_concave, | |||
| e_convex | |||
| }; | |||
| b2TempPolygon m_polygonB; | |||
| b2Transform m_xf; | |||
| b2Vec2 m_centroidB; | |||
| b2Vec2 m_v0, m_v1, m_v2, m_v3; | |||
| b2Vec2 m_normal0, m_normal1, m_normal2; | |||
| b2Vec2 m_normal; | |||
| VertexType m_type1, m_type2; | |||
| b2Vec2 m_lowerLimit, m_upperLimit; | |||
| float32 m_radius; | |||
| bool m_front; | |||
| }; | |||
| // Algorithm: | |||
| // 1. Classify v1 and v2 | |||
| // 2. Classify polygon centroid as front or back | |||
| // 3. Flip normal if necessary | |||
| // 4. Initialize normal range to [-pi, pi] about face normal | |||
| // 5. Adjust normal range according to adjacent edges | |||
| // 6. Visit each separating axes, only accept axes within the range | |||
| // 7. Return if _any_ axis indicates separation | |||
| // 8. Clip | |||
| void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, | |||
| const b2PolygonShape* polygonB, const b2Transform& xfB) | |||
| { | |||
| m_xf = b2MulT(xfA, xfB); | |||
| m_centroidB = b2Mul(m_xf, polygonB->m_centroid); | |||
| m_v0 = edgeA->m_vertex0; | |||
| m_v1 = edgeA->m_vertex1; | |||
| m_v2 = edgeA->m_vertex2; | |||
| m_v3 = edgeA->m_vertex3; | |||
| bool hasVertex0 = edgeA->m_hasVertex0; | |||
| bool hasVertex3 = edgeA->m_hasVertex3; | |||
| b2Vec2 edge1 = m_v2 - m_v1; | |||
| edge1.Normalize(); | |||
| m_normal1.Set(edge1.y, -edge1.x); | |||
| float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1); | |||
| float32 offset0 = 0.0f, offset2 = 0.0f; | |||
| bool convex1 = false, convex2 = false; | |||
| // Is there a preceding edge? | |||
| if (hasVertex0) | |||
| { | |||
| b2Vec2 edge0 = m_v1 - m_v0; | |||
| edge0.Normalize(); | |||
| m_normal0.Set(edge0.y, -edge0.x); | |||
| convex1 = b2Cross(edge0, edge1) >= 0.0f; | |||
| offset0 = b2Dot(m_normal0, m_centroidB - m_v0); | |||
| } | |||
| // Is there a following edge? | |||
| if (hasVertex3) | |||
| { | |||
| b2Vec2 edge2 = m_v3 - m_v2; | |||
| edge2.Normalize(); | |||
| m_normal2.Set(edge2.y, -edge2.x); | |||
| convex2 = b2Cross(edge1, edge2) > 0.0f; | |||
| offset2 = b2Dot(m_normal2, m_centroidB - m_v2); | |||
| } | |||
| // Determine front or back collision. Determine collision normal limits. | |||
| if (hasVertex0 && hasVertex3) | |||
| { | |||
| if (convex1 && convex2) | |||
| { | |||
| m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal0; | |||
| m_upperLimit = m_normal2; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| } | |||
| else if (convex1) | |||
| { | |||
| m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f); | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal0; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal2; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| } | |||
| else if (convex2) | |||
| { | |||
| m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f); | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = m_normal2; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = -m_normal0; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal2; | |||
| m_upperLimit = -m_normal0; | |||
| } | |||
| } | |||
| } | |||
| else if (hasVertex0) | |||
| { | |||
| if (convex1) | |||
| { | |||
| m_front = offset0 >= 0.0f || offset1 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal0; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| m_front = offset0 >= 0.0f && offset1 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = -m_normal0; | |||
| } | |||
| } | |||
| } | |||
| else if (hasVertex3) | |||
| { | |||
| if (convex2) | |||
| { | |||
| m_front = offset1 >= 0.0f || offset2 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = m_normal2; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| m_front = offset1 >= 0.0f && offset2 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = -m_normal2; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| m_front = offset1 >= 0.0f; | |||
| if (m_front) | |||
| { | |||
| m_normal = m_normal1; | |||
| m_lowerLimit = -m_normal1; | |||
| m_upperLimit = -m_normal1; | |||
| } | |||
| else | |||
| { | |||
| m_normal = -m_normal1; | |||
| m_lowerLimit = m_normal1; | |||
| m_upperLimit = m_normal1; | |||
| } | |||
| } | |||
| // Get polygonB in frameA | |||
| m_polygonB.count = polygonB->m_vertexCount; | |||
| for (int32 i = 0; i < polygonB->m_vertexCount; ++i) | |||
| { | |||
| m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]); | |||
| m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]); | |||
| } | |||
| m_radius = 2.0f * b2_polygonRadius; | |||
| manifold->pointCount = 0; | |||
| b2EPAxis edgeAxis = ComputeEdgeSeparation(); | |||
| // If no valid normal can be found than this edge should not collide. | |||
| if (edgeAxis.type == b2EPAxis::e_unknown) | |||
| { | |||
| return; | |||
| } | |||
| if (edgeAxis.separation > m_radius) | |||
| { | |||
| return; | |||
| } | |||
| b2EPAxis polygonAxis = ComputePolygonSeparation(); | |||
| if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius) | |||
| { | |||
| return; | |||
| } | |||
| // Use hysteresis for jitter reduction. | |||
| const float32 k_relativeTol = 0.98f; | |||
| const float32 k_absoluteTol = 0.001f; | |||
| b2EPAxis primaryAxis; | |||
| if (polygonAxis.type == b2EPAxis::e_unknown) | |||
| { | |||
| primaryAxis = edgeAxis; | |||
| } | |||
| else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol) | |||
| { | |||
| primaryAxis = polygonAxis; | |||
| } | |||
| else | |||
| { | |||
| primaryAxis = edgeAxis; | |||
| } | |||
| b2ClipVertex ie[2]; | |||
| b2ReferenceFace rf; | |||
| if (primaryAxis.type == b2EPAxis::e_edgeA) | |||
| { | |||
| manifold->type = b2Manifold::e_faceA; | |||
| // Search for the polygon normal that is most anti-parallel to the edge normal. | |||
| int32 bestIndex = 0; | |||
| float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]); | |||
| for (int32 i = 1; i < m_polygonB.count; ++i) | |||
| { | |||
| float32 value = b2Dot(m_normal, m_polygonB.normals[i]); | |||
| if (value < bestValue) | |||
| { | |||
| bestValue = value; | |||
| bestIndex = i; | |||
| } | |||
| } | |||
| int32 i1 = bestIndex; | |||
| int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0; | |||
| ie[0].v = m_polygonB.vertices[i1]; | |||
| ie[0].id.cf.indexA = 0; | |||
| ie[0].id.cf.indexB = (uint8) i1; | |||
| ie[0].id.cf.typeA = b2ContactFeature::e_face; | |||
| ie[0].id.cf.typeB = b2ContactFeature::e_vertex; | |||
| ie[1].v = m_polygonB.vertices[i2]; | |||
| ie[1].id.cf.indexA = 0; | |||
| ie[1].id.cf.indexB = (uint8) i2; | |||
| ie[1].id.cf.typeA = b2ContactFeature::e_face; | |||
| ie[1].id.cf.typeB = b2ContactFeature::e_vertex; | |||
| if (m_front) | |||
| { | |||
| rf.i1 = 0; | |||
| rf.i2 = 1; | |||
| rf.v1 = m_v1; | |||
| rf.v2 = m_v2; | |||
| rf.normal = m_normal1; | |||
| } | |||
| else | |||
| { | |||
| rf.i1 = 1; | |||
| rf.i2 = 0; | |||
| rf.v1 = m_v2; | |||
| rf.v2 = m_v1; | |||
| rf.normal = -m_normal1; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| manifold->type = b2Manifold::e_faceB; | |||
| ie[0].v = m_v1; | |||
| ie[0].id.cf.indexA = 0; | |||
| ie[0].id.cf.indexB = (uint8) primaryAxis.index; | |||
| ie[0].id.cf.typeA = b2ContactFeature::e_vertex; | |||
| ie[0].id.cf.typeB = b2ContactFeature::e_face; | |||
| ie[1].v = m_v2; | |||
| ie[1].id.cf.indexA = 0; | |||
| ie[1].id.cf.indexB = (uint8) primaryAxis.index; | |||
| ie[1].id.cf.typeA = b2ContactFeature::e_vertex; | |||
| ie[1].id.cf.typeB = b2ContactFeature::e_face; | |||
| rf.i1 = primaryAxis.index; | |||
| rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0; | |||
| rf.v1 = m_polygonB.vertices[rf.i1]; | |||
| rf.v2 = m_polygonB.vertices[rf.i2]; | |||
| rf.normal = m_polygonB.normals[rf.i1]; | |||
| } | |||
| rf.sideNormal1.Set(rf.normal.y, -rf.normal.x); | |||
| rf.sideNormal2 = -rf.sideNormal1; | |||
| rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1); | |||
| rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2); | |||
| // Clip incident edge against extruded edge1 side edges. | |||
| b2ClipVertex clipPoints1[2]; | |||
| b2ClipVertex clipPoints2[2]; | |||
| int32 np; | |||
| // Clip to box side 1 | |||
| np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1); | |||
| if (np < b2_maxManifoldPoints) | |||
| { | |||
| return; | |||
| } | |||
| // Clip to negative box side 1 | |||
| np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2); | |||
| if (np < b2_maxManifoldPoints) | |||
| { | |||
| return; | |||
| } | |||
| // Now clipPoints2 contains the clipped points. | |||
| if (primaryAxis.type == b2EPAxis::e_edgeA) | |||
| { | |||
| manifold->localNormal = rf.normal; | |||
| manifold->localPoint = rf.v1; | |||
| } | |||
| else | |||
| { | |||
| manifold->localNormal = polygonB->m_normals[rf.i1]; | |||
| manifold->localPoint = polygonB->m_vertices[rf.i1]; | |||
| } | |||
| int32 pointCount = 0; | |||
| for (int32 i = 0; i < b2_maxManifoldPoints; ++i) | |||
| { | |||
| float32 separation; | |||
| separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1); | |||
| if (separation <= m_radius) | |||
| { | |||
| b2ManifoldPoint* cp = manifold->points + pointCount; | |||
| if (primaryAxis.type == b2EPAxis::e_edgeA) | |||
| { | |||
| cp->localPoint = b2MulT(m_xf, clipPoints2[i].v); | |||
| cp->id = clipPoints2[i].id; | |||
| } | |||
| else | |||
| { | |||
| cp->localPoint = clipPoints2[i].v; | |||
| cp->id.cf.typeA = clipPoints2[i].id.cf.typeB; | |||
| cp->id.cf.typeB = clipPoints2[i].id.cf.typeA; | |||
| cp->id.cf.indexA = clipPoints2[i].id.cf.indexB; | |||
| cp->id.cf.indexB = clipPoints2[i].id.cf.indexA; | |||
| } | |||
| ++pointCount; | |||
| } | |||
| } | |||
| manifold->pointCount = pointCount; | |||
| } | |||
| b2EPAxis b2EPCollider::ComputeEdgeSeparation() | |||
| { | |||
| b2EPAxis axis; | |||
| axis.type = b2EPAxis::e_edgeA; | |||
| axis.index = m_front ? 0 : 1; | |||
| axis.separation = FLT_MAX; | |||
| for (int32 i = 0; i < m_polygonB.count; ++i) | |||
| { | |||
| float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1); | |||
| if (s < axis.separation) | |||
| { | |||
| axis.separation = s; | |||
| } | |||
| } | |||
| return axis; | |||
| } | |||
| b2EPAxis b2EPCollider::ComputePolygonSeparation() | |||
| { | |||
| b2EPAxis axis; | |||
| axis.type = b2EPAxis::e_unknown; | |||
| axis.index = -1; | |||
| axis.separation = -FLT_MAX; | |||
| b2Vec2 perp(-m_normal.y, m_normal.x); | |||
| for (int32 i = 0; i < m_polygonB.count; ++i) | |||
| { | |||
| b2Vec2 n = -m_polygonB.normals[i]; | |||
| float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1); | |||
| float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2); | |||
| float32 s = b2Min(s1, s2); | |||
| if (s > m_radius) | |||
| { | |||
| // No collision | |||
| axis.type = b2EPAxis::e_edgeB; | |||
| axis.index = i; | |||
| axis.separation = s; | |||
| return axis; | |||
| } | |||
| // Adjacency | |||
| if (b2Dot(n, perp) >= 0.0f) | |||
| { | |||
| if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop) | |||
| { | |||
| continue; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop) | |||
| { | |||
| continue; | |||
| } | |||
| } | |||
| if (s > axis.separation) | |||
| { | |||
| axis.type = b2EPAxis::e_edgeB; | |||
| axis.index = i; | |||
| axis.separation = s; | |||
| } | |||
| } | |||
| return axis; | |||
| } | |||
| void b2CollideEdgeAndPolygon( b2Manifold* manifold, | |||
| const b2EdgeShape* edgeA, const b2Transform& xfA, | |||
| const b2PolygonShape* polygonB, const b2Transform& xfB) | |||
| { | |||
| b2EPCollider collider; | |||
| collider.Collide(manifold, edgeA, xfA, polygonB, xfB); | |||
| } | |||
| @@ -1,249 +0,0 @@ | |||
| /* | |||
| * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org | |||
| * | |||
| * This software is provided 'as-is', without any express or implied | |||
| * warranty. In no event will the authors be held liable for any damages | |||
| * arising from the use of this software. | |||
| * Permission is granted to anyone to use this software for any purpose, | |||
| * including commercial applications, and to alter it and redistribute it | |||
| * freely, subject to the following restrictions: | |||
| * 1. The origin of this software must not be misrepresented; you must not | |||
| * claim that you wrote the original software. If you use this software | |||
| * in a product, an acknowledgment in the product documentation would be | |||
| * appreciated but is not required. | |||
| * 2. Altered source versions must be plainly marked as such, and must not be | |||
| * misrepresented as being the original software. | |||
| * 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "b2Collision.h" | |||
| #include "b2Distance.h" | |||
| void b2WorldManifold::Initialize(const b2Manifold* manifold, | |||
| const b2Transform& xfA, float32 radiusA, | |||
| const b2Transform& xfB, float32 radiusB) | |||
| { | |||
| if (manifold->pointCount == 0) | |||
| { | |||
| return; | |||
| } | |||
| switch (manifold->type) | |||
| { | |||
| case b2Manifold::e_circles: | |||
| { | |||
| normal.Set(1.0f, 0.0f); | |||
| b2Vec2 pointA = b2Mul(xfA, manifold->localPoint); | |||
| b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint); | |||
| if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon) | |||
| { | |||
| normal = pointB - pointA; | |||
| normal.Normalize(); | |||
| } | |||
| b2Vec2 cA = pointA + radiusA * normal; | |||
| b2Vec2 cB = pointB - radiusB * normal; | |||
| points[0] = 0.5f * (cA + cB); | |||
| } | |||
| break; | |||
| case b2Manifold::e_faceA: | |||
| { | |||
| normal = b2Mul(xfA.q, manifold->localNormal); | |||
| b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint); | |||
| for (int32 i = 0; i < manifold->pointCount; ++i) | |||
| { | |||
| b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint); | |||
| b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal; | |||
| b2Vec2 cB = clipPoint - radiusB * normal; | |||
| points[i] = 0.5f * (cA + cB); | |||
| } | |||
| } | |||
| break; | |||
| case b2Manifold::e_faceB: | |||
| { | |||
| normal = b2Mul(xfB.q, manifold->localNormal); | |||
| b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint); | |||
| for (int32 i = 0; i < manifold->pointCount; ++i) | |||
| { | |||
| b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint); | |||
| b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal; | |||
| b2Vec2 cA = clipPoint - radiusA * normal; | |||
| points[i] = 0.5f * (cA + cB); | |||
| } | |||
| // Ensure normal points from A to B. | |||
| normal = -normal; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], | |||
| const b2Manifold* manifold1, const b2Manifold* manifold2) | |||
| { | |||
| for (int32 i = 0; i < b2_maxManifoldPoints; ++i) | |||
| { | |||
| state1[i] = b2_nullState; | |||
| state2[i] = b2_nullState; | |||
| } | |||
| // Detect persists and removes. | |||
| for (int32 i = 0; i < manifold1->pointCount; ++i) | |||
| { | |||
| b2ContactID id = manifold1->points[i].id; | |||
| state1[i] = b2_removeState; | |||
| for (int32 j = 0; j < manifold2->pointCount; ++j) | |||
| { | |||
| if (manifold2->points[j].id.key == id.key) | |||
| { | |||
| state1[i] = b2_persistState; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| // Detect persists and adds. | |||
| for (int32 i = 0; i < manifold2->pointCount; ++i) | |||
| { | |||
| b2ContactID id = manifold2->points[i].id; | |||
| state2[i] = b2_addState; | |||
| for (int32 j = 0; j < manifold1->pointCount; ++j) | |||
| { | |||
| if (manifold1->points[j].id.key == id.key) | |||
| { | |||
| state2[i] = b2_persistState; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // From Real-time Collision Detection, p179. | |||
| bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const | |||
| { | |||
| float32 tmin = -b2_maxFloat; | |||
| float32 tmax = b2_maxFloat; | |||
| b2Vec2 p = input.p1; | |||
| b2Vec2 d = input.p2 - input.p1; | |||
| b2Vec2 absD = b2Abs(d); | |||
| b2Vec2 normal; | |||
| for (int32 i = 0; i < 2; ++i) | |||
| { | |||
| if (absD(i) < b2_epsilon) | |||
| { | |||
| // Parallel. | |||
| if (p(i) < lowerBound(i) || upperBound(i) < p(i)) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| float32 inv_d = 1.0f / d(i); | |||
| float32 t1 = (lowerBound(i) - p(i)) * inv_d; | |||
| float32 t2 = (upperBound(i) - p(i)) * inv_d; | |||
| // Sign of the normal vector. | |||
| float32 s = -1.0f; | |||
| if (t1 > t2) | |||
| { | |||
| b2Swap(t1, t2); | |||
| s = 1.0f; | |||
| } | |||
| // Push the min up | |||
| if (t1 > tmin) | |||
| { | |||
| normal.SetZero(); | |||
| normal(i) = s; | |||
| tmin = t1; | |||
| } | |||
| // Pull the max down | |||
| tmax = b2Min(tmax, t2); | |||
| if (tmin > tmax) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| // Does the ray start inside the box? | |||
| // Does the ray intersect beyond the max fraction? | |||
| if (tmin < 0.0f || input.maxFraction < tmin) | |||
| { | |||
| return false; | |||
| } | |||
| // Intersection. | |||
| output->fraction = tmin; | |||
| output->normal = normal; | |||
| return true; | |||
| } | |||
| // Sutherland-Hodgman clipping. | |||
| int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], | |||
| const b2Vec2& normal, float32 offset, int32 vertexIndexA) | |||
| { | |||
| // Start with no output points | |||
| int32 numOut = 0; | |||
| // Calculate the distance of end points to the line | |||
| float32 distance0 = b2Dot(normal, vIn[0].v) - offset; | |||
| float32 distance1 = b2Dot(normal, vIn[1].v) - offset; | |||
| // If the points are behind the plane | |||
| if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; | |||
| if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; | |||
| // If the points are on different sides of the plane | |||
| if (distance0 * distance1 < 0.0f) | |||
| { | |||
| // Find intersection point of edge and plane | |||
| float32 interp = distance0 / (distance0 - distance1); | |||
| vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); | |||
| // VertexA is hitting edgeB. | |||
| vOut[numOut].id.cf.indexA = (uint8) vertexIndexA; | |||
| vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB; | |||
| vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex; | |||
| vOut[numOut].id.cf.typeB = b2ContactFeature::e_face; | |||
| ++numOut; | |||
| } | |||
| return numOut; | |||
| } | |||
| bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, | |||
| const b2Shape* shapeB, int32 indexB, | |||
| const b2Transform& xfA, const b2Transform& xfB) | |||
| { | |||
| b2DistanceInput input; | |||
| input.proxyA.Set(shapeA, indexA); | |||
| input.proxyB.Set(shapeB, indexB); | |||
| input.transformA = xfA; | |||
| input.transformB = xfB; | |||
| input.useRadii = true; | |||
| b2SimplexCache cache; | |||
| cache.count = 0; | |||
| b2DistanceOutput output; | |||
| b2Distance(&output, &cache, &input); | |||
| return output.distance < 10.0f * b2_epsilon; | |||
| } | |||
| @@ -1,947 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission is granted to use this software under the terms of either: | |||
| a) the GPL v2 (or any later version) | |||
| b) the Affero GPL v3 | |||
| Details of these licenses can be found 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.juce.com for more information. | |||
| ============================================================================== | |||
| */ | |||
| //============================================================================== | |||
| /* | |||
| This file contains all the gubbins to create an ActiveX browser plugin that | |||
| wraps your BrowserPluginComponent object. | |||
| */ | |||
| //============================================================================== | |||
| #if _MSC_VER | |||
| //============================================================================== | |||
| #include <olectl.h> | |||
| #include <objsafe.h> | |||
| #include <exdisp.h> | |||
| #pragma warning (disable:4584) | |||
| #include "../juce_browser_plugin.h" | |||
| using namespace juce; | |||
| #include "juce_BrowserPluginComponent.h" | |||
| #ifndef JuceBrowserPlugin_ActiveXCLSID | |||
| #error "For an activeX plugin, you need to define JuceBrowserPlugin_ActiveXCLSID in your BrowserPluginCharacteristics.h file!" | |||
| #endif | |||
| //============================================================================== | |||
| #if JUCE_DEBUG | |||
| static int numDOWID = 0, numJuceSO = 0; | |||
| #endif | |||
| #define log(a) DBG(a) | |||
| // Cunning trick used to add functions to export list without messing about with .def files. | |||
| #define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) | |||
| //============================================================================== | |||
| static void juceVarToVariant (const var& v, VARIANT& dest); | |||
| static var variantTojuceVar (const VARIANT& v); | |||
| //============================================================================== | |||
| // Takes care of the logic in invoking var methods from IDispatch callbacks. | |||
| class IDispatchHelper | |||
| { | |||
| public: | |||
| IDispatchHelper() {} | |||
| String getStringFromDISPID (const DISPID hash) const | |||
| { | |||
| return identifierNames [identifierIDs.indexOf (hash)]; | |||
| } | |||
| DISPID getDISPIDForName (const String& name) | |||
| { | |||
| const int i = identifierNames.indexOf (String (name)); | |||
| if (i >= 0) | |||
| return identifierIDs[i]; | |||
| const DISPID newID = (DISPID) name.hashCode64(); | |||
| identifierNames.add (name); | |||
| identifierIDs.add (newID); | |||
| return newID; | |||
| } | |||
| HRESULT doGetIDsOfNames (LPOLESTR* rgszNames, UINT cNames, DISPID* rgDispId) | |||
| { | |||
| for (unsigned int i = 0; i < cNames; ++i) | |||
| rgDispId[i] = getDISPIDForName (rgszNames[i]); | |||
| return S_OK; | |||
| } | |||
| HRESULT doInvoke (const var& v, | |||
| DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, | |||
| VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) | |||
| { | |||
| const Identifier memberId (getStringFromDISPID (dispIdMember)); | |||
| DynamicObject* const object = v.getDynamicObject(); | |||
| if (memberId.toString().isEmpty() || object == nullptr) | |||
| return DISP_E_MEMBERNOTFOUND; | |||
| if ((wFlags & DISPATCH_METHOD) != 0) | |||
| { | |||
| if (object->hasMethod (memberId)) | |||
| { | |||
| const int numArgs = pDispParams == nullptr ? 0 : pDispParams->cArgs; | |||
| var result; | |||
| if (numArgs == 0) | |||
| { | |||
| result = v.call (memberId); | |||
| } | |||
| else | |||
| { | |||
| Array<var> args; | |||
| for (int j = numArgs; --j >= 0;) | |||
| args.add (variantTojuceVar (pDispParams->rgvarg[j])); | |||
| result = v.invoke (memberId, numArgs == 0 ? nullptr : args.getRawDataPointer(), numArgs); | |||
| } | |||
| if (pVarResult != nullptr) | |||
| juceVarToVariant (result, *pVarResult); | |||
| return S_OK; | |||
| } | |||
| } | |||
| else if ((wFlags & DISPATCH_PROPERTYGET) != 0) | |||
| { | |||
| if (object->hasProperty (memberId) && pVarResult != nullptr) | |||
| { | |||
| juceVarToVariant (object->getProperty (memberId), *pVarResult); | |||
| return S_OK; | |||
| } | |||
| } | |||
| else if ((wFlags & DISPATCH_PROPERTYPUT) != 0) | |||
| { | |||
| if (pDispParams != nullptr && pDispParams->cArgs > 0) | |||
| { | |||
| object->setProperty (memberId, variantTojuceVar (pDispParams->rgvarg[0])); | |||
| return S_OK; | |||
| } | |||
| } | |||
| return DISP_E_MEMBERNOTFOUND; | |||
| } | |||
| private: | |||
| Array<DISPID> identifierIDs; | |||
| StringArray identifierNames; | |||
| JUCE_DECLARE_NON_COPYABLE (IDispatchHelper) | |||
| }; | |||
| //============================================================================== | |||
| // Makes a var look like an IDispatch | |||
| class IDispatchWrappingDynamicObject : public IDispatch | |||
| { | |||
| public: | |||
| IDispatchWrappingDynamicObject (const var& object_) | |||
| : object (object_), | |||
| refCount (1) | |||
| { | |||
| DBG ("num Juce wrapper objs: " + String (++numJuceSO)); | |||
| } | |||
| virtual ~IDispatchWrappingDynamicObject() | |||
| { | |||
| DBG ("num Juce wrapper objs: " + String (--numJuceSO)); | |||
| } | |||
| HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) | |||
| { | |||
| if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } | |||
| if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; } | |||
| *result = 0; | |||
| return E_NOINTERFACE; | |||
| } | |||
| ULONG __stdcall AddRef() { return ++refCount; } | |||
| ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } | |||
| HRESULT __stdcall GetTypeInfoCount (UINT*) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, | |||
| LCID lcid, DISPID* rgDispId) | |||
| { | |||
| return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId); | |||
| } | |||
| HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, | |||
| DISPPARAMS* pDispParams, VARIANT* pVarResult, | |||
| EXCEPINFO* pExcepInfo, UINT* puArgErr) | |||
| { | |||
| return iDispatchHelper.doInvoke (object, dispIdMember, riid, lcid, wFlags, pDispParams, | |||
| pVarResult, pExcepInfo, puArgErr); | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| var object; | |||
| int refCount; | |||
| IDispatchHelper iDispatchHelper; | |||
| JUCE_DECLARE_NON_COPYABLE (IDispatchWrappingDynamicObject) | |||
| }; | |||
| //============================================================================== | |||
| // Makes an IDispatch look like a var | |||
| class DynamicObjectWrappingIDispatch : public DynamicObject | |||
| { | |||
| public: | |||
| DynamicObjectWrappingIDispatch (IDispatch* const source_) | |||
| : source (source_) | |||
| { | |||
| source->AddRef(); | |||
| log ("num IDispatch wrapper objs: " + String (++numDOWID)); | |||
| } | |||
| ~DynamicObjectWrappingIDispatch() | |||
| { | |||
| source->Release(); | |||
| log ("num IDispatch wrapper objs: " + String (--numDOWID)); | |||
| } | |||
| var getProperty (const Identifier& propertyName) const override | |||
| { | |||
| const String nameCopy (propertyName.toString()); | |||
| LPCOLESTR name = nameCopy.toUTF16(); | |||
| DISPID id = 0; | |||
| if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK) | |||
| { | |||
| EXCEPINFO excepInfo; | |||
| DISPPARAMS params; | |||
| zerostruct (params); | |||
| UINT argError; | |||
| VARIANT result; | |||
| zerostruct (result); | |||
| if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYGET, | |||
| ¶ms, &result, &excepInfo, &argError) == S_OK) | |||
| { | |||
| var v (variantTojuceVar (result)); | |||
| VariantClear (&result); | |||
| return v; | |||
| } | |||
| } | |||
| return var(); | |||
| } | |||
| bool hasProperty (const Identifier& propertyName) const override | |||
| { | |||
| const String nameCopy (propertyName.toString()); | |||
| LPCOLESTR name = nameCopy.toUTF16(); | |||
| DISPID id = 0; | |||
| return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK; | |||
| } | |||
| void setProperty (const Identifier& propertyName, const var& newValue) override | |||
| { | |||
| const String nameCopy (propertyName.toString()); | |||
| LPCOLESTR name = nameCopy.toUTF16(); | |||
| DISPID id = 0; | |||
| if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK) | |||
| { | |||
| VARIANT param; | |||
| zerostruct (param); | |||
| juceVarToVariant (newValue, param); | |||
| DISPPARAMS dispParams; | |||
| zerostruct (dispParams); | |||
| dispParams.cArgs = 1; | |||
| dispParams.rgvarg = ¶m; | |||
| EXCEPINFO excepInfo; | |||
| zerostruct (excepInfo); | |||
| VARIANT result; | |||
| zerostruct (result); | |||
| UINT argError = 0; | |||
| if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYPUT, | |||
| &dispParams, &result, &excepInfo, &argError) == S_OK) | |||
| { | |||
| VariantClear (&result); | |||
| } | |||
| VariantClear (¶m); | |||
| } | |||
| } | |||
| void removeProperty (const Identifier& propertyName) override | |||
| { | |||
| setProperty (propertyName, var()); | |||
| } | |||
| bool hasMethod (const Identifier& methodName) const override | |||
| { | |||
| const String nameCopy (methodName.toString()); | |||
| LPCOLESTR name = nameCopy.toUTF16(); | |||
| DISPID id = 0; | |||
| return source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK; | |||
| } | |||
| var invokeMethod (Identifier methodName, const var::NativeFunctionArgs& args) override | |||
| { | |||
| var returnValue; | |||
| const String nameCopy (methodName.toString()); | |||
| LPCOLESTR name = nameCopy.toUTF16(); | |||
| DISPID id = 0; | |||
| if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*) &name, 1, 0, &id) == S_OK) | |||
| { | |||
| HeapBlock <VARIANT> params; | |||
| params.calloc (args.numArguments + 1); | |||
| for (int i = 0; i < args.numArguments; ++i) | |||
| juceVarToVariant (args.arguments[(args.numArguments - 1) - i], params[i]); | |||
| DISPPARAMS dispParams; | |||
| zerostruct (dispParams); | |||
| dispParams.cArgs = args.numArguments; | |||
| dispParams.rgvarg = params; | |||
| EXCEPINFO excepInfo; | |||
| zerostruct (excepInfo); | |||
| VARIANT result; | |||
| zerostruct (result); | |||
| UINT argError = 0; | |||
| if (source->Invoke (id, IID_NULL, 0, DISPATCH_METHOD, | |||
| &dispParams, &result, &excepInfo, &argError) == S_OK) | |||
| { | |||
| returnValue = variantTojuceVar (result); | |||
| VariantClear (&result); | |||
| } | |||
| } | |||
| return returnValue; | |||
| } | |||
| private: | |||
| IDispatch* const source; | |||
| JUCE_DECLARE_NON_COPYABLE (DynamicObjectWrappingIDispatch) | |||
| }; | |||
| //============================================================================== | |||
| void juceVarToVariant (const var& v, VARIANT& dest) | |||
| { | |||
| if (v.isVoid()) | |||
| { | |||
| dest.vt = VT_EMPTY; | |||
| } | |||
| else if (v.isInt()) | |||
| { | |||
| dest.vt = VT_INT; | |||
| dest.intVal = (int) v; | |||
| } | |||
| else if (v.isBool()) | |||
| { | |||
| dest.vt = VT_BOOL; | |||
| dest.boolVal = (int) v; | |||
| } | |||
| else if (v.isDouble()) | |||
| { | |||
| dest.vt = VT_R8; | |||
| dest.dblVal = (double) v; | |||
| } | |||
| else if (v.isString()) | |||
| { | |||
| dest.vt = VT_BSTR; | |||
| dest.bstrVal = SysAllocString (v.toString().toUTF16()); | |||
| } | |||
| else if (v.getDynamicObject() != nullptr) | |||
| { | |||
| dest.vt = VT_DISPATCH; | |||
| dest.pdispVal = new IDispatchWrappingDynamicObject (v); | |||
| } | |||
| else if (v.isMethod()) | |||
| { | |||
| dest.vt = VT_EMPTY; | |||
| } | |||
| } | |||
| var variantTojuceVar (const VARIANT& v) | |||
| { | |||
| if ((v.vt & VT_ARRAY) != 0) | |||
| { | |||
| //xxx | |||
| } | |||
| else | |||
| { | |||
| switch (v.vt & ~VT_BYREF) | |||
| { | |||
| case VT_VOID: | |||
| case VT_EMPTY: return var(); | |||
| case VT_I1: return var ((int) v.cVal); | |||
| case VT_I2: return var ((int) v.iVal); | |||
| case VT_I4: return var ((int) v.lVal); | |||
| case VT_I8: return var (String (v.llVal)); | |||
| case VT_UI1: return var ((int) v.bVal); | |||
| case VT_UI2: return var ((int) v.uiVal); | |||
| case VT_UI4: return var ((int) v.ulVal); | |||
| case VT_UI8: return var (String (v.ullVal)); | |||
| case VT_INT: return var ((int) v.intVal); | |||
| case VT_UINT: return var ((int) v.uintVal); | |||
| case VT_R4: return var ((double) v.fltVal); | |||
| case VT_R8: return var ((double) v.dblVal); | |||
| case VT_BSTR: return var (String (v.bstrVal)); | |||
| case VT_BOOL: return var (v.boolVal ? true : false); | |||
| case VT_DISPATCH: return var (new DynamicObjectWrappingIDispatch (v.pdispVal)); | |||
| default: break; | |||
| } | |||
| } | |||
| return var(); | |||
| } | |||
| //============================================================================== | |||
| // This acts as the embedded HWND | |||
| class AXBrowserPluginHolderComponent : public Component | |||
| { | |||
| public: | |||
| AXBrowserPluginHolderComponent() | |||
| : parentHWND (0), | |||
| browser (nullptr) | |||
| { | |||
| setOpaque (true); | |||
| setWantsKeyboardFocus (false); | |||
| addAndMakeVisible (child = createBrowserPlugin()); | |||
| jassert (child != nullptr); // You have to create one of these! | |||
| } | |||
| ~AXBrowserPluginHolderComponent() | |||
| { | |||
| setWindow (nullptr); | |||
| child = nullptr; | |||
| } | |||
| //============================================================================== | |||
| void paint (Graphics& g) override | |||
| { | |||
| if (child == nullptr || ! child->isOpaque()) | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void resized() override | |||
| { | |||
| if (child != nullptr) | |||
| child->setBounds (getLocalBounds()); | |||
| } | |||
| var getObject() { return child->getJavascriptObject(); } | |||
| void setWindow (IOleInPlaceSite* site) | |||
| { | |||
| if (browser != nullptr) | |||
| { | |||
| browser->Release(); | |||
| browser = nullptr; | |||
| } | |||
| HWND newHWND = 0; | |||
| if (site != nullptr) | |||
| { | |||
| site->GetWindow (&newHWND); | |||
| IServiceProvider* sp = nullptr; | |||
| site->QueryInterface (IID_IServiceProvider, (void**) &sp); | |||
| if (sp != nullptr) | |||
| { | |||
| sp->QueryService (IID_IWebBrowserApp, IID_IWebBrowser2, (void**) &browser); | |||
| sp->Release(); | |||
| } | |||
| } | |||
| if (parentHWND != newHWND) | |||
| { | |||
| removeFromDesktop(); | |||
| setVisible (false); | |||
| parentHWND = newHWND; | |||
| if (parentHWND != 0) | |||
| { | |||
| addToDesktop (0); | |||
| HWND ourHWND = (HWND) getWindowHandle(); | |||
| SetParent (ourHWND, parentHWND); | |||
| DWORD val = GetWindowLong (ourHWND, GWL_STYLE); | |||
| val = (val & ~WS_POPUP) | WS_CHILD; | |||
| SetWindowLong (ourHWND, GWL_STYLE, val); | |||
| setVisible (true); | |||
| } | |||
| } | |||
| if (site != nullptr) | |||
| site->OnInPlaceActivate(); | |||
| } | |||
| String getBrowserURL() const | |||
| { | |||
| if (browser == nullptr) | |||
| return String::empty; | |||
| BSTR url = nullptr; | |||
| browser->get_LocationURL (&url); | |||
| return URL::removeEscapeChars (url); | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| ScopedPointer<BrowserPluginComponent> child; | |||
| HWND parentHWND; | |||
| IWebBrowser2* browser; | |||
| JUCE_DECLARE_NON_COPYABLE (AXBrowserPluginHolderComponent) | |||
| }; | |||
| //============================================================================== | |||
| extern String browserVersionDesc; | |||
| static String getExePath() | |||
| { | |||
| TCHAR moduleFile [2048] = { 0 }; | |||
| GetModuleFileName (0, moduleFile, 2048); | |||
| return moduleFile; | |||
| } | |||
| static String getExeVersion (const String& exeFileName, const String& fieldName) | |||
| { | |||
| DWORD pointlessWin32Variable; | |||
| DWORD size = GetFileVersionInfoSize (exeFileName.toUTF16(), &pointlessWin32Variable); | |||
| if (size > 0) | |||
| { | |||
| HeapBlock <char> exeInfo; | |||
| exeInfo.calloc (size); | |||
| if (GetFileVersionInfo (exeFileName.toUTF16(), 0, size, exeInfo)) | |||
| { | |||
| TCHAR* result = nullptr; | |||
| unsigned int resultLen = 0; | |||
| // try the 1200 codepage (Unicode) | |||
| String queryStr ("\\StringFileInfo\\040904B0\\" + fieldName); | |||
| if (! VerQueryValue (exeInfo, (LPTSTR) queryStr.toUTF16().getAddress(), (void**) &result, &resultLen)) | |||
| { | |||
| // try the 1252 codepage (Windows Multilingual) | |||
| queryStr = "\\StringFileInfo\\040904E4\\" + fieldName; | |||
| VerQueryValue (exeInfo, (LPTSTR) queryStr.toUTF16().getAddress(), (void**) &result, &resultLen); | |||
| } | |||
| return String (result, resultLen); | |||
| } | |||
| } | |||
| return String::empty; | |||
| } | |||
| static int numActivePlugins = 0; | |||
| class JuceActiveXObject : public IUnknown, | |||
| public IDispatch, | |||
| public IObjectWithSite, | |||
| public IObjectSafety, | |||
| public IOleInPlaceObject | |||
| { | |||
| public: | |||
| JuceActiveXObject() | |||
| : site (nullptr), refCount (0) | |||
| { | |||
| log ("JuceActiveXObject"); | |||
| } | |||
| ~JuceActiveXObject() | |||
| { | |||
| log ("~JuceActiveXObject"); | |||
| holderComp = nullptr; | |||
| } | |||
| HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) | |||
| { | |||
| if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } | |||
| if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; } | |||
| if (id == IID_IObjectWithSite) { AddRef(); *result = (IObjectWithSite*) this; return S_OK; } | |||
| if (id == IID_IObjectSafety) { AddRef(); *result = (IObjectSafety*) this; return S_OK; } | |||
| if (id == IID_IOleInPlaceObject) { AddRef(); *result = (IOleInPlaceObject*) this; return S_OK; } | |||
| if (id == IID_IOleWindow) { AddRef(); *result = (IOleWindow*) (IOleInPlaceObject*) this; return S_OK; } | |||
| *result = 0; | |||
| return E_NOINTERFACE; | |||
| } | |||
| ULONG __stdcall AddRef() { return ++refCount; } | |||
| ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } | |||
| HRESULT __stdcall GetTypeInfoCount (UINT* pctinfo) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetTypeInfo (UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, | |||
| LCID lcid, DISPID* rgDispId) | |||
| { | |||
| return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId); | |||
| } | |||
| HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, | |||
| DISPPARAMS* pDispParams, VARIANT* pVarResult, | |||
| EXCEPINFO* pExcepInfo, UINT* puArgErr) | |||
| { | |||
| if (holderComp == nullptr) | |||
| return DISP_E_MEMBERNOTFOUND; | |||
| return iDispatchHelper.doInvoke (holderComp->getObject(), | |||
| dispIdMember, riid, lcid, wFlags, pDispParams, | |||
| pVarResult, pExcepInfo, puArgErr); | |||
| } | |||
| HRESULT __stdcall SetSite (IUnknown* newSite) | |||
| { | |||
| if (newSite != site) | |||
| { | |||
| if (site != nullptr) | |||
| site->Release(); | |||
| site = newSite; | |||
| if (site != nullptr) | |||
| { | |||
| site->AddRef(); | |||
| IOleInPlaceSite* inPlaceSite = nullptr; | |||
| site->QueryInterface (IID_IOleInPlaceSite, (void**) &inPlaceSite); | |||
| if (inPlaceSite != nullptr) | |||
| { | |||
| createHolderComp(); | |||
| holderComp->setWindow (inPlaceSite); | |||
| inPlaceSite->Release(); | |||
| } | |||
| else | |||
| { | |||
| deleteHolderComp(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| deleteHolderComp(); | |||
| } | |||
| } | |||
| return S_OK; | |||
| } | |||
| void createHolderComp() | |||
| { | |||
| if (holderComp == nullptr) | |||
| { | |||
| if (numActivePlugins++ == 0) | |||
| { | |||
| log ("initialiseJuce_GUI()"); | |||
| initialiseJuce_GUI(); | |||
| browserVersionDesc = "Internet Explorer " + getExeVersion (getExePath(), "FileVersion"); | |||
| } | |||
| holderComp = new AXBrowserPluginHolderComponent(); | |||
| } | |||
| } | |||
| void deleteHolderComp() | |||
| { | |||
| if (holderComp != nullptr) | |||
| { | |||
| holderComp = nullptr; | |||
| if (--numActivePlugins == 0) | |||
| { | |||
| log ("shutdownJuce_GUI()"); | |||
| shutdownJuce_GUI(); | |||
| } | |||
| } | |||
| } | |||
| HRESULT __stdcall GetSite (REFIID riid, void **ppvSite) | |||
| { | |||
| *ppvSite = site; | |||
| return S_OK; | |||
| } | |||
| //============================================================================== | |||
| HRESULT __stdcall SetObjectRects (LPCRECT r, LPCRECT c) | |||
| { | |||
| if (holderComp != nullptr) | |||
| holderComp->setBounds (r->left, r->top, r->right - r->left, r->bottom - r->top); | |||
| return S_OK; | |||
| } | |||
| HRESULT __stdcall GetWindow (HWND* phwnd) | |||
| { | |||
| if (holderComp == nullptr) | |||
| return E_NOTIMPL; | |||
| *phwnd = (HWND) holderComp->getWindowHandle(); | |||
| return S_OK; | |||
| } | |||
| //============================================================================== | |||
| HRESULT __stdcall ContextSensitiveHelp (BOOL fEnterMode) { return E_NOTIMPL; } | |||
| HRESULT __stdcall InPlaceDeactivate() { return E_NOTIMPL; } | |||
| HRESULT __stdcall UIDeactivate() { return E_NOTIMPL; } | |||
| HRESULT __stdcall ReactivateAndUndo() { return E_NOTIMPL; } | |||
| //============================================================================== | |||
| HRESULT __stdcall GetInterfaceSafetyOptions (REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) | |||
| { | |||
| *pdwSupportedOptions = *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA; | |||
| return S_OK; | |||
| } | |||
| HRESULT __stdcall SetInterfaceSafetyOptions (REFIID, DWORD, DWORD) { return S_OK; } | |||
| private: | |||
| IUnknown* site; | |||
| int refCount; | |||
| ScopedPointer<AXBrowserPluginHolderComponent> holderComp; | |||
| IDispatchHelper iDispatchHelper; | |||
| JUCE_DECLARE_NON_COPYABLE (JuceActiveXObject) | |||
| }; | |||
| //============================================================================== | |||
| class JuceActiveXObjectFactory : public IUnknown, | |||
| public IClassFactory | |||
| { | |||
| public: | |||
| JuceActiveXObjectFactory() : refCount (0) {} | |||
| HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) | |||
| { | |||
| if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } | |||
| if (id == IID_IClassFactory) { AddRef(); *result = (IClassFactory*) this; return S_OK; } | |||
| *result = nullptr; | |||
| return E_NOINTERFACE; | |||
| } | |||
| ULONG __stdcall AddRef() { return ++refCount; } | |||
| ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } | |||
| HRESULT __stdcall CreateInstance (IUnknown* pUnkOuter, REFIID riid, void** ppvObject) | |||
| { | |||
| *ppvObject = nullptr; | |||
| if (pUnkOuter != nullptr && riid != IID_IUnknown) | |||
| return CLASS_E_NOAGGREGATION; | |||
| JuceActiveXObject* ax = new JuceActiveXObject(); | |||
| return ax->QueryInterface (riid, ppvObject); | |||
| } | |||
| HRESULT __stdcall LockServer (BOOL /*fLock*/) { return S_OK; } | |||
| private: | |||
| int refCount; | |||
| JUCE_DECLARE_NON_COPYABLE (JuceActiveXObjectFactory) | |||
| }; | |||
| //============================================================================== | |||
| String getActiveXBrowserURL (const BrowserPluginComponent* comp) | |||
| { | |||
| if (AXBrowserPluginHolderComponent* ax = dynamic_cast<AXBrowserPluginHolderComponent*> (comp->getParentComponent())) | |||
| return ax->getBrowserURL(); | |||
| return String(); | |||
| } | |||
| //============================================================================== | |||
| extern "C" BOOL WINAPI DllMain (HANDLE instance, DWORD reason, LPVOID) | |||
| { | |||
| #pragma EXPORTED_FUNCTION | |||
| switch (reason) | |||
| { | |||
| case DLL_PROCESS_ATTACH: | |||
| log ("DLL_PROCESS_ATTACH"); | |||
| Process::setCurrentModuleInstanceHandle (instance); | |||
| break; | |||
| case DLL_PROCESS_DETACH: | |||
| log ("DLL_PROCESS_DETACH"); | |||
| browserVersionDesc.clear(); | |||
| // IE has a tendency to leak our objects, so although none of this should be | |||
| // necessary, it's best to make sure.. | |||
| jassert (numActivePlugins == 0); | |||
| shutdownJuce_GUI(); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| return TRUE; | |||
| } | |||
| static String CLSIDToJuceString (REFCLSID clsid) | |||
| { | |||
| LPWSTR s = nullptr; | |||
| StringFromIID (clsid, &s); | |||
| if (s == nullptr) | |||
| return String::empty; | |||
| const String result (s); | |||
| LPMALLOC malloc; | |||
| CoGetMalloc (1, &malloc); | |||
| if (malloc != nullptr) | |||
| { | |||
| malloc->Free (s); | |||
| malloc->Release(); | |||
| } | |||
| return result.removeCharacters ("{}").trim(); | |||
| } | |||
| STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv) | |||
| { | |||
| #pragma EXPORTED_FUNCTION | |||
| *ppv = nullptr; | |||
| if (CLSIDToJuceString (rclsid).equalsIgnoreCase (String (JuceBrowserPlugin_ActiveXCLSID))) | |||
| { | |||
| JuceActiveXObjectFactory* afx = new JuceActiveXObjectFactory(); | |||
| if (afx->QueryInterface (riid, ppv) == S_OK) | |||
| return S_OK; | |||
| delete afx; | |||
| } | |||
| return CLASS_E_CLASSNOTAVAILABLE; | |||
| } | |||
| STDAPI DllCanUnloadNow() | |||
| { | |||
| #pragma EXPORTED_FUNCTION | |||
| return S_OK; | |||
| } | |||
| //============================================================================== | |||
| static String makeLegalRegistryName (const String& s) | |||
| { | |||
| return s.retainCharacters ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_."); | |||
| } | |||
| static HRESULT doRegistration (const bool unregister) | |||
| { | |||
| const String company (makeLegalRegistryName (JuceBrowserPlugin_Company)); | |||
| const String plugin (makeLegalRegistryName (JuceBrowserPlugin_Name)); | |||
| const String clsID ("{" + String (JuceBrowserPlugin_ActiveXCLSID).toUpperCase() + "}"); | |||
| const String root ("HKEY_CLASSES_ROOT\\"); | |||
| const String companyDotPlugin (company + "." + plugin); | |||
| const String companyDotPluginCur (companyDotPlugin + ".1"); | |||
| const String clsIDRoot (root + "CLSID\\" + clsID + "\\"); | |||
| const String dllPath (File::getSpecialLocation (File::currentApplicationFile).getFullPathName()); | |||
| StringPairArray settings; | |||
| settings.set (root + companyDotPluginCur + "\\", JuceBrowserPlugin_Name); | |||
| settings.set (root + companyDotPluginCur + "\\CLSID\\", clsID); | |||
| settings.set (root + companyDotPlugin + "\\", JuceBrowserPlugin_Name); | |||
| settings.set (root + companyDotPlugin + "\\CLSID\\", clsID); | |||
| settings.set (root + companyDotPlugin + "\\CurVer\\", companyDotPluginCur); | |||
| settings.set (clsIDRoot, JuceBrowserPlugin_Name); | |||
| settings.set (clsIDRoot + "Implemented Categories\\{7DD95801-9882-11CF-9FA9-00AA006C42C4}\\", String::empty); | |||
| settings.set (clsIDRoot + "Implemented Categories\\{7DD95802-9882-11CF-9FA9-00AA006C42C4}\\", String::empty); | |||
| settings.set (clsIDRoot + "ProgID\\", companyDotPluginCur); | |||
| settings.set (clsIDRoot + "VersionIndependentProgID\\", companyDotPlugin); | |||
| settings.set (clsIDRoot + "Programmable\\", String::empty); | |||
| settings.set (clsIDRoot + "InProcServer32\\", dllPath); | |||
| settings.set (clsIDRoot + "InProcServer32\\ThreadingModel", "Apartment"); | |||
| settings.set (clsIDRoot + "Control\\", String::empty); | |||
| settings.set (clsIDRoot + "Insertable\\", String::empty); | |||
| settings.set (clsIDRoot + "ToolboxBitmap32\\", dllPath + ", 101"); | |||
| settings.set (clsIDRoot + "TypeLib\\", ""); | |||
| settings.set (clsIDRoot + "Version\\", JuceBrowserPlugin_Version); | |||
| if (unregister) | |||
| { | |||
| for (int i = 0; i < settings.getAllKeys().size(); ++i) | |||
| WindowsRegistry::deleteValue (settings.getAllKeys()[i]); | |||
| WindowsRegistry::deleteKey (root + companyDotPluginCur); | |||
| WindowsRegistry::deleteKey (root + companyDotPlugin); | |||
| WindowsRegistry::deleteKey (clsIDRoot); | |||
| if (WindowsRegistry::valueExists (clsIDRoot + "InProcServer32")) | |||
| return SELFREG_E_CLASS; | |||
| } | |||
| else | |||
| { | |||
| WindowsRegistry::deleteKey (clsIDRoot); | |||
| for (int i = 0; i < settings.getAllKeys().size(); ++i) | |||
| WindowsRegistry::setValue (settings.getAllKeys()[i], | |||
| settings [settings.getAllKeys()[i]]); | |||
| // check whether the registration actually worked - if not, we probably don't have | |||
| // enough privileges to write to the registry.. | |||
| if (WindowsRegistry::getValue (clsIDRoot + "InProcServer32\\") != dllPath) | |||
| return SELFREG_E_CLASS; | |||
| } | |||
| return S_OK; | |||
| } | |||
| STDAPI DllRegisterServer() | |||
| { | |||
| #pragma EXPORTED_FUNCTION | |||
| return doRegistration (false); | |||
| } | |||
| STDAPI DllUnregisterServer() | |||
| { | |||
| #pragma EXPORTED_FUNCTION | |||
| return doRegistration (true); | |||
| } | |||
| #endif | |||
| @@ -62,10 +62,11 @@ public: | |||
| */ | |||
| virtual void render() = 0; | |||
| OpenGLContext openGLContext; | |||
| private: | |||
| //============================================================================== | |||
| OpenGLContext openGLContext; | |||
| int frameCounter; | |||
| void newOpenGLContextCreated() override; | |||