1
0
Fork 0
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:
jules 2014-11-04 17:36:59 +00:00
parent 01bab0c146
commit 43fa10b12f
14 changed files with 2035 additions and 22 deletions

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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());

View file

@ -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))

View 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);
}

View 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;
}

View file

@ -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,
&params, &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 = &param;
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 (&param);
}
}
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

View file

@ -558,6 +558,10 @@ bool ResizableWindow::restoreWindowStateFromString (const String& s)
}
updateLastPosIfNotFullScreen();
if (fs)
setBoundsConstrained (newPos);
setFullScreen (fs);
if (! fs)

View file

@ -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();
}

View file

@ -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.
*/