mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
More template cleanups
This commit is contained in:
parent
01bab0c146
commit
43fa10b12f
14 changed files with 2035 additions and 22 deletions
|
|
@ -24,7 +24,7 @@ public:
|
|||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String& commandLine) override
|
||||
void initialise (const String& /*commandLine*/) override
|
||||
{
|
||||
// This method is where you should put your application's initialisation code..
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ public:
|
|||
quit();
|
||||
}
|
||||
|
||||
void anotherInstanceStarted (const String& commandLine) override
|
||||
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
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ public:
|
|||
phaseDelta (0.0f),
|
||||
frequency (5000.0f),
|
||||
amplitude (0.2f),
|
||||
sampleRate (0.0)
|
||||
sampleRate (0.0),
|
||||
expectedSamplesPerBlock (0)
|
||||
{
|
||||
setSize (500, 400);
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ public:
|
|||
void prepareToPlay (int samplesPerBlockExpected, double newSampleRate) override
|
||||
{
|
||||
sampleRate = newSampleRate;
|
||||
expectedSamplesPerBlock = samplesPerBlockExpected;
|
||||
}
|
||||
|
||||
/* This method generates the actual audio samples.
|
||||
|
|
@ -140,6 +142,7 @@ private:
|
|||
float amplitude;
|
||||
|
||||
double sampleRate;
|
||||
int expectedSamplesPerBlock;
|
||||
Point<float> lastMousePosition;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ static const unsigned char temp_binary_data_0[] =
|
|||
" void update() override\r\n"
|
||||
" {\r\n"
|
||||
" // This function is called at the frequency specified by the setFramesPerSecond() call\r\n"
|
||||
" // in the constructor. You can use it\r\n"
|
||||
" // in the constructor. You can use it to update counters, animate values, etc.\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void paint (Graphics& g) override\r\n"
|
||||
|
|
@ -111,8 +111,8 @@ static const unsigned char temp_binary_data_1[] =
|
|||
" {\r\n"
|
||||
" setSize (500, 400);\r\n"
|
||||
"\r\n"
|
||||
" // specify the number of input and output channels needed\r\n"
|
||||
" setAudioChannels (1, 1);\r\n"
|
||||
" // specify the number of input and output channels that we want to open\r\n"
|
||||
" setAudioChannels (2, 2);\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" ~MainContentComponent()\r\n"
|
||||
|
|
@ -1344,15 +1344,26 @@ static const unsigned char temp_binary_data_20[] =
|
|||
" MainContentComponent()\r\n"
|
||||
" {\r\n"
|
||||
" setSize (500, 400);\r\n"
|
||||
"\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" ~MainContentComponent()\r\n"
|
||||
" {\r\n"
|
||||
" shutdownAudio();\r\n"
|
||||
" shutdownOpenGL();\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void paint (Graphics& g)\r\n"
|
||||
" void initialise() override\r\n"
|
||||
" {\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void shutdown() override\r\n"
|
||||
" {\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void render() override\r\n"
|
||||
" {\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void paint (Graphics& g) override\r\n"
|
||||
" {\r\n"
|
||||
" // (Our component is opaque, so we must completely fill the background with a solid colour)\r\n"
|
||||
" g.fillAll (Colours::black);\r\n"
|
||||
|
|
@ -1361,7 +1372,7 @@ static const unsigned char temp_binary_data_20[] =
|
|||
" // You can add your drawing code here!\r\n"
|
||||
" }\r\n"
|
||||
"\r\n"
|
||||
" void resized()\r\n"
|
||||
" void resized() override\r\n"
|
||||
" {\r\n"
|
||||
" // This is called when the MainContentComponent is resized.\r\n"
|
||||
" // If you add any child components, this is where you should\r\n"
|
||||
|
|
@ -3627,8 +3638,8 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw
|
|||
|
||||
switch (hash)
|
||||
{
|
||||
case 0x6cf2645e: numBytes = 1908; return jucer_AnimatedComponentTemplate_cpp;
|
||||
case 0xafccbd3f: numBytes = 2977; return jucer_AudioComponentTemplate_cpp;
|
||||
case 0x6cf2645e: numBytes = 1949; return jucer_AnimatedComponentTemplate_cpp;
|
||||
case 0xafccbd3f: numBytes = 2991; return jucer_AudioComponentTemplate_cpp;
|
||||
case 0x27c5a93a: numBytes = 1180; return jucer_AudioPluginEditorTemplate_cpp;
|
||||
case 0x4d0721bf: numBytes = 1012; return jucer_AudioPluginEditorTemplate_h;
|
||||
case 0x51b49ac5: numBytes = 5039; return jucer_AudioPluginFilterTemplate_cpp;
|
||||
|
|
@ -3647,7 +3658,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw
|
|||
case 0x02a2a077: numBytes = 262; return jucer_NewCppFileTemplate_cpp;
|
||||
case 0x0842c43c: numBytes = 308; return jucer_NewCppFileTemplate_h;
|
||||
case 0x36e634a1: numBytes = 1626; return jucer_NewInlineComponentTemplate_h;
|
||||
case 0x7fbac252: numBytes = 1679; return jucer_OpenGLComponentTemplate_cpp;
|
||||
case 0x7fbac252: numBytes = 1834; return jucer_OpenGLComponentTemplate_cpp;
|
||||
case 0x44be9398: numBytes = 2922; return AudioPluginXCodeScript_txt;
|
||||
case 0x4a0cfd09: numBytes = 151; return background_tile_png;
|
||||
case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml;
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
namespace BinaryData
|
||||
{
|
||||
extern const char* jucer_AnimatedComponentTemplate_cpp;
|
||||
const int jucer_AnimatedComponentTemplate_cppSize = 1908;
|
||||
const int jucer_AnimatedComponentTemplate_cppSize = 1949;
|
||||
|
||||
extern const char* jucer_AudioComponentTemplate_cpp;
|
||||
const int jucer_AudioComponentTemplate_cppSize = 2977;
|
||||
const int jucer_AudioComponentTemplate_cppSize = 2991;
|
||||
|
||||
extern const char* jucer_AudioPluginEditorTemplate_cpp;
|
||||
const int jucer_AudioPluginEditorTemplate_cppSize = 1180;
|
||||
|
|
@ -70,7 +70,7 @@ namespace BinaryData
|
|||
const int jucer_NewInlineComponentTemplate_hSize = 1626;
|
||||
|
||||
extern const char* jucer_OpenGLComponentTemplate_cpp;
|
||||
const int jucer_OpenGLComponentTemplate_cppSize = 1679;
|
||||
const int jucer_OpenGLComponentTemplate_cppSize = 1834;
|
||||
|
||||
extern const char* AudioPluginXCodeScript_txt;
|
||||
const int AudioPluginXCodeScript_txtSize = 2922;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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 (500, 400);
|
||||
}
|
||||
|
||||
~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
|
||||
|
|
@ -27,10 +27,22 @@ public:
|
|||
|
||||
~MainContentComponent()
|
||||
{
|
||||
shutdownAudio();
|
||||
shutdownOpenGL();
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
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);
|
||||
|
|
@ -39,7 +51,7 @@ public:
|
|||
// You can add your drawing code here!
|
||||
}
|
||||
|
||||
void resized()
|
||||
void resized() override
|
||||
{
|
||||
// This is called when the MainContentComponent is resized.
|
||||
// If you add any child components, this is where you should
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ struct AnimatedAppWizard : public NewProjectWizard
|
|||
|
||||
// create main window
|
||||
String windowCpp = project.getFileTemplate ("jucer_AnimatedComponentTemplate_cpp")
|
||||
.replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false);
|
||||
.replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false);
|
||||
|
||||
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompCpp, windowCpp))
|
||||
failedFiles.add (contentCompCpp.getFullPathName());
|
||||
|
|
|
|||
|
|
@ -49,8 +49,7 @@ struct OpenGLAppWizard : public NewProjectWizard
|
|||
String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));
|
||||
|
||||
// create main window
|
||||
|
||||
String windowCpp = project.getFileTemplate ("jucer_OpenglComponentTemplate_cpp")
|
||||
String windowCpp = project.getFileTemplate ("jucer_OpenGLComponentTemplate_cpp")
|
||||
.replace ("INCLUDE_JUCE", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false);
|
||||
|
||||
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompCpp, windowCpp))
|
||||
|
|
|
|||
698
modules/juce_box2d/box2d/Collision/b2collideedge.cpp
Normal file
698
modules/juce_box2d/box2d/Collision/b2collideedge.cpp
Normal file
|
|
@ -0,0 +1,698 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
249
modules/juce_box2d/box2d/Collision/b2collision.cpp
Normal file
249
modules/juce_box2d/box2d/Collision/b2collision.cpp
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,947 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
|
|
@ -558,6 +558,10 @@ bool ResizableWindow::restoreWindowStateFromString (const String& s)
|
|||
}
|
||||
|
||||
updateLastPosIfNotFullScreen();
|
||||
|
||||
if (fs)
|
||||
setBoundsConstrained (newPos);
|
||||
|
||||
setFullScreen (fs);
|
||||
|
||||
if (! fs)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,17 @@ OpenGLAppComponent::OpenGLAppComponent() : frameCounter (0)
|
|||
}
|
||||
|
||||
OpenGLAppComponent::~OpenGLAppComponent()
|
||||
{
|
||||
// Before your subclass's destructor has completed, you must call
|
||||
// shutdownOpenGL() to release the GL context. (Otherwise there's
|
||||
// a danger that it may invoke a GL callback on your class while
|
||||
// it's in the process of being deleted.
|
||||
jassert (! openGLContext.isAttached());
|
||||
|
||||
shutdownOpenGL();
|
||||
}
|
||||
|
||||
void OpenGLAppComponent::shutdownOpenGL()
|
||||
{
|
||||
openGLContext.detach();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ public:
|
|||
*/
|
||||
int getFrameCounter() const noexcept { return frameCounter; }
|
||||
|
||||
void shutdownOpenGL();
|
||||
|
||||
/** Implement this method to set up any GL objects that you need for rendering.
|
||||
The GL context will be active when this method is called.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue